001package org.cpsolver.exam.criteria; 002 003import java.util.Collection; 004import java.util.HashSet; 005import java.util.Set; 006 007import org.cpsolver.exam.criteria.additional.DistributionViolation; 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; 013import org.cpsolver.ifs.solver.Solver; 014import org.cpsolver.ifs.util.DataProperties; 015 016 017/** 018 * Distribution penalty. I.e., sum weights of violated distribution 019 * constraints. 020 * <br><br> 021 * A weight of violated distribution soft constraints (see 022 * {@link ExamDistributionConstraint}) can be set by problem property 023 * Exams.RoomDistributionWeight, or in the input xml file, property 024 * roomDistributionWeight. 025 * 026 * <br> 027 * 028 * @version ExamTT 1.3 (Examination Timetabling)<br> 029 * Copyright (C) 2008 - 2014 Tomáš Müller<br> 030 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 031 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 032 * <br> 033 * This library is free software; you can redistribute it and/or modify 034 * it under the terms of the GNU Lesser General Public License as 035 * published by the Free Software Foundation; either version 3 of the 036 * License, or (at your option) any later version. <br> 037 * <br> 038 * This library is distributed in the hope that it will be useful, but 039 * WITHOUT ANY WARRANTY; without even the implied warranty of 040 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 041 * Lesser General Public License for more details. <br> 042 * <br> 043 * You should have received a copy of the GNU Lesser General Public 044 * License along with this library; if not see 045 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 046 */ 047public class DistributionPenalty extends ExamCriterion { 048 protected Integer iSoftDistributions = null; 049 050 public DistributionPenalty() { 051 setValueUpdateType(ValueUpdateType.NoUpdate); 052 } 053 054 055 @Override 056 public boolean init(Solver<Exam, ExamPlacement> solver) { 057 if (super.init(solver)) { 058 iSoftDistributions = solver.getProperties().getPropertyInteger("Exam.SoftDistributions", null); 059 if (iSoftDistributions != null) { 060 DistributionViolation dv = new DistributionViolation(); 061 getModel().addCriterion(dv); 062 return dv.init(solver); 063 } 064 } 065 return true; 066 } 067 068 @Override 069 public String getWeightName() { 070 return "Exams.DistributionWeight"; 071 } 072 073 @Override 074 public String getXmlWeightName() { 075 return "distributionWeight"; 076 } 077 078 @Override 079 public double getWeightDefault(DataProperties config) { 080 return 1.0; 081 } 082 083 @Override 084 public double getValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value, Set<ExamPlacement> conflicts) { 085 int penalty = 0; 086 for (ExamDistributionConstraint dc : value.variable().getDistributionConstraints()) { 087 if (dc.isHard() || (iSoftDistributions != null && iSoftDistributions == dc.getWeight())) 088 continue; 089 boolean sat = dc.isSatisfied(assignment, value); 090 if (sat != dc.isSatisfied(assignment)) 091 penalty += (sat ? -dc.getWeight() : dc.getWeight()); 092 } 093 return penalty; 094 } 095 096 @Override 097 public boolean isRoomCriterion() { return true; } 098 099 /** 100 * Room related distribution penalty, i.e., sum weights of violated 101 * distribution constraints 102 */ 103 @Override 104 public double getRoomValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value) { 105 int penalty = 0; 106 for (ExamDistributionConstraint dc : value.variable().getDistributionConstraints()) { 107 if (dc.isHard() || (iSoftDistributions != null && iSoftDistributions == dc.getWeight()) || !dc.isRoomRelated()) 108 continue; 109 boolean sat = dc.isSatisfied(assignment, value); 110 if (sat != dc.isSatisfied(assignment)) 111 penalty += (sat ? -dc.getWeight() : dc.getWeight()); 112 } 113 return penalty; 114 } 115 116 @Override 117 public double getValue(Assignment<Exam, ExamPlacement> assignment, Collection<Exam> variables) { 118 int penalty = 0; 119 Set<ExamDistributionConstraint> added = new HashSet<ExamDistributionConstraint>(); 120 for (Exam exam: variables) { 121 for (ExamDistributionConstraint dc : exam.getDistributionConstraints()) { 122 if (added.add(dc)) { 123 if (dc.isHard() || (iSoftDistributions != null && iSoftDistributions == dc.getWeight())) 124 continue; 125 if (!dc.isSatisfied(assignment)) 126 penalty += dc.getWeight(); 127 } 128 } 129 } 130 return penalty; 131 } 132 133 @Override 134 public boolean isPeriodCriterion() { return true; } 135 136 @Override 137 public void inc(Assignment<Exam, ExamPlacement> assignment, double value) { 138 if (iSoftDistributions != null && iSoftDistributions == value) { 139 getModel().getCriterion(DistributionViolation.class).inc(assignment, 1.0); 140 } else if (iSoftDistributions != null && iSoftDistributions == -value) { 141 getModel().getCriterion(DistributionViolation.class).inc(assignment, -1.0); 142 } else { 143 super.inc(assignment, value); 144 } 145 } 146 147 /** 148 * Period related distribution penalty, i.e., sum weights of violated 149 * distribution constraints 150 */ 151 @Override 152 public double getPeriodValue(Assignment<Exam, ExamPlacement> assignment, ExamPlacement value) { 153 int penalty = 0; 154 for (ExamDistributionConstraint dc : value.variable().getDistributionConstraints()) { 155 if (dc.isHard() || (iSoftDistributions != null && iSoftDistributions == dc.getWeight()) || !dc.isPeriodRelated()) 156 continue; 157 boolean sat = dc.isSatisfied(assignment, value); 158 if (sat != dc.isSatisfied(assignment)) 159 penalty += (sat ? -dc.getWeight() : dc.getWeight()); 160 } 161 return penalty; 162 } 163 164 @Override 165 protected double[] computeBounds(Assignment<Exam, ExamPlacement> assignment) { 166 double[] bounds = new double[] { 0.0, 0.0 }; 167 for (ExamDistributionConstraint dc : ((ExamModel)getModel()).getDistributionConstraints()) { 168 if (dc.isHard() || (iSoftDistributions != null && iSoftDistributions == dc.getWeight())) 169 continue; 170 bounds[1] += dc.getWeight(); 171 } 172 return bounds; 173 } 174 175 @Override 176 public String toString(Assignment<Exam, ExamPlacement> assignment) { 177 return (getValue(assignment) <= 0.0 ? "" : "DP:" + sDoubleFormat.format(getValue(assignment))); 178 } 179}