001package org.cpsolver.exam.criteria.additional; 002 003import java.util.Collection; 004import java.util.HashSet; 005import java.util.Set; 006 007import org.cpsolver.exam.criteria.ExamCriterion; 008import org.cpsolver.exam.model.Exam; 009import org.cpsolver.exam.model.ExamDistributionConstraint; 010import org.cpsolver.exam.model.ExamModel; 011import org.cpsolver.exam.model.ExamPlacement; 012import org.cpsolver.ifs.assignment.Assignment; 013 014 015/** 016 * Experimental criterion counting violations of hard distribution constraints. 017 * <br><br> 018 * To enable breaking of hard distribution constraints, set parameter Exam.SoftDistributions to 019 * a weight that should be inferred by a hard distribution constraint being broken. 020 * 021 * <br> 022 * 023 * @version ExamTT 1.3 (Examination Timetabling)<br> 024 * Copyright (C) 2008 - 2014 Tomáš Müller<br> 025 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 026 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 027 * <br> 028 * This library is free software; you can redistribute it and/or modify 029 * it under the terms of the GNU Lesser General Public License as 030 * published by the Free Software Foundation; either version 3 of the 031 * License, or (at your option) any later version. <br> 032 * <br> 033 * This library is distributed in the hope that it will be useful, but 034 * WITHOUT ANY WARRANTY; without even the implied warranty of 035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 036 * Lesser General Public License for more details. <br> 037 * <br> 038 * You should have received a copy of the GNU Lesser General Public 039 * License along with this library; if not see 040 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 041 */ 042public class DistributionViolation extends ExamCriterion { 043 044 public DistributionViolation() { 045 super(); 046 setValueUpdateType(ValueUpdateType.NoUpdate); 047 } 048 049 @Override 050 public String getWeightName() { 051 return "Exam.SoftDistributions"; 052 } 053 054 @Override 055 public String getXmlWeightName() { 056 return "softDistributions"; 057 } 058 059 @Override 060 public double getValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value, Set<ExamPlacement> conflicts) { 061 int penalty = 0; 062 ExamPlacement original = assignment.getValue(value.variable()); 063 for (ExamDistributionConstraint dc : value.variable().getDistributionConstraints()) { 064 if (dc.isHard() || getWeight() != dc.getWeight()) 065 continue; 066 penalty += dc.countViolations(assignment, value); 067 if (original != null) penalty -= dc.countViolations(assignment, original); 068 } 069 return penalty; 070 } 071 072 @Override 073 protected double[] computeBounds(Assignment<Exam, ExamPlacement> assignment) { 074 double[] bounds = new double[] { 0.0, 0.0 }; 075 for (ExamDistributionConstraint dc : ((ExamModel)getModel()).getDistributionConstraints()) { 076 if (!dc.isHard() && getWeight() == dc.getWeight()) 077 bounds[1] += dc.variables().size() * (dc.variables().size() - 1) / 2; 078 } 079 return bounds; 080 } 081 082 @Override 083 public boolean isRoomCriterion() { return true; } 084 085 @Override 086 public double getRoomValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value) { 087 int penalty = 0; 088 ExamPlacement original = assignment.getValue(value.variable()); 089 for (ExamDistributionConstraint dc : value.variable().getDistributionConstraints()) { 090 if (dc.isHard() || getWeight() != dc.getWeight() || !dc.isRoomRelated()) 091 continue; 092 penalty += dc.countViolations(assignment, value); 093 if (original != null) penalty -= dc.countViolations(assignment, original); 094 } 095 return penalty; 096 } 097 098 @Override 099 public boolean isPeriodCriterion() { return true; } 100 101 @Override 102 public double getPeriodValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value) { 103 int penalty = 0; 104 ExamPlacement original = assignment.getValue(value.variable()); 105 for (ExamDistributionConstraint dc : value.variable().getDistributionConstraints()) { 106 if (dc.isHard() || getWeight() != dc.getWeight() || !dc.isPeriodRelated()) 107 continue; 108 penalty += dc.countViolations(assignment, value); 109 if (original != null) penalty -= dc.countViolations(assignment, original); 110 } 111 return penalty; 112 } 113 114 @Override 115 public double getValue(Assignment<Exam, ExamPlacement> assignment, Collection<Exam> variables) { 116 int penalty = 0; 117 Set<ExamDistributionConstraint> added = new HashSet<ExamDistributionConstraint>(); 118 for (Exam exam: variables) { 119 for (ExamDistributionConstraint dc : exam.getDistributionConstraints()) { 120 if (added.add(dc)) { 121 if (dc.isHard() || getWeight() != dc.getWeight()) 122 continue; 123 penalty += dc.countViolations(assignment); 124 } 125 } 126 } 127 return penalty; 128 } 129 130 @Override 131 public String toString(Assignment<Exam, ExamPlacement> assignment) { 132 return (getValue(assignment) <= 0.0 ? "" : "!D:" + sDoubleFormat.format(getValue(assignment))); 133 } 134}