001 package net.sf.cpsolver.exam.criteria;
002
003 import java.util.Collection;
004 import java.util.Set;
005
006 import net.sf.cpsolver.exam.criteria.additional.RoomViolation;
007 import net.sf.cpsolver.exam.model.Exam;
008 import net.sf.cpsolver.exam.model.ExamModel;
009 import net.sf.cpsolver.exam.model.ExamPeriod;
010 import net.sf.cpsolver.exam.model.ExamPlacement;
011 import net.sf.cpsolver.exam.model.ExamRoom;
012 import net.sf.cpsolver.exam.model.ExamRoomPlacement;
013 import net.sf.cpsolver.ifs.solver.Solver;
014 import net.sf.cpsolver.ifs.util.DataProperties;
015
016 /**
017 * Room penalty (penalty for using given rooms). I.e., sum of
018 * {@link ExamRoomPlacement#getPenalty(ExamPeriod)} of assigned rooms.
019 * <br><br>
020 * A weight for room penalty can be set by problem property
021 * Exams.RoomPreferenceWeight, or in the input xml file, property
022 * roomWeight).
023 *
024 * <br>
025 *
026 * @version ExamTT 1.2 (Examination Timetabling)<br>
027 * Copyright (C) 2008 - 2012 Tomas Muller<br>
028 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
029 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
030 * <br>
031 * This library is free software; you can redistribute it and/or modify
032 * it under the terms of the GNU Lesser General Public License as
033 * published by the Free Software Foundation; either version 3 of the
034 * License, or (at your option) any later version. <br>
035 * <br>
036 * This library is distributed in the hope that it will be useful, but
037 * WITHOUT ANY WARRANTY; without even the implied warranty of
038 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
039 * Lesser General Public License for more details. <br>
040 * <br>
041 * You should have received a copy of the GNU Lesser General Public
042 * License along with this library; if not see
043 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
044 */
045 public class RoomPenalty extends ExamCriterion {
046 protected Integer iSoftRooms = null;
047
048 @Override
049 public boolean init(Solver<Exam, ExamPlacement> solver) {
050 if (super.init(solver)) {
051 iSoftRooms = solver.getProperties().getPropertyInteger("Exam.SoftRooms", null);
052 if (iSoftRooms != null) {
053 RoomViolation rv = new RoomViolation();
054 getModel().addCriterion(rv);
055 return rv.init(solver);
056 }
057 }
058 return true;
059 }
060
061 @Override
062 public String getWeightName() {
063 return "Exams.RoomWeight";
064 }
065
066 @Override
067 public String getXmlWeightName() {
068 return "roomWeight";
069 }
070
071 @Override
072 public double getWeightDefault(DataProperties config) {
073 return 0.1;
074 }
075
076 @Override
077 public double getValue(ExamPlacement value, Set<ExamPlacement> conflicts) {
078 double penalty = 0.0;
079 if (value.getRoomPlacements() != null)
080 for (ExamRoomPlacement r : value.getRoomPlacements()) {
081 penalty += (iSoftRooms != null && (iSoftRooms == r.getPenalty() || iSoftRooms == r.getPenalty(value.getPeriod())) ? 0.0 : r.getPenalty(value.getPeriod()));
082 }
083 return penalty;
084 }
085
086 private int getMinPenalty(ExamRoom r) {
087 int min = Integer.MAX_VALUE;
088 for (ExamPeriod p : ((ExamModel)getModel()).getPeriods()) {
089 if (r.isAvailable(p) && (iSoftRooms == null || r.getPenalty(p) != iSoftRooms)) {
090 min = Math.min(min, r.getPenalty(p));
091 }
092 }
093 return min;
094 }
095
096 private int getMaxPenalty(ExamRoom r) {
097 int max = Integer.MIN_VALUE;
098 for (ExamPeriod p : ((ExamModel)getModel()).getPeriods()) {
099 if (r.isAvailable(p) && (iSoftRooms == null || r.getPenalty(p) != iSoftRooms)) {
100 max = Math.max(max, r.getPenalty(p));
101 }
102 }
103 return max;
104 }
105
106 private boolean isAvailable(ExamRoom r) {
107 for (ExamPeriod p : ((ExamModel)getModel()).getPeriods()) {
108 if (r.isAvailable(p) && (iSoftRooms == null || r.getPenalty(p) != iSoftRooms))
109 return true;
110 }
111 return false;
112 }
113
114 @Override
115 public double[] getBounds(Collection<Exam> variables) {
116 double[] bounds = new double[] { 0.0, 0.0 };
117 for (Exam exam : variables) {
118 if (!exam.getRoomPlacements().isEmpty()) {
119 int minPenalty = Integer.MAX_VALUE, maxPenalty = Integer.MIN_VALUE;
120 for (ExamRoomPlacement roomPlacement : exam.getRoomPlacements()) {
121 if (iSoftRooms != null && iSoftRooms == roomPlacement.getPenalty()) continue;
122 if (!isAvailable(roomPlacement.getRoom())) continue;
123 minPenalty = Math.min(minPenalty, 2 * roomPlacement.getPenalty() + getMinPenalty(roomPlacement.getRoom()));
124 maxPenalty = Math.max(maxPenalty, 2 * roomPlacement.getPenalty() + getMaxPenalty(roomPlacement.getRoom()));
125 }
126 bounds[0] += minPenalty;
127 bounds[1] += maxPenalty;
128 }
129 }
130 return bounds;
131 }
132
133 @Override
134 public String toString() {
135 return "RP:" + sDoubleFormat.format(getValue());
136 }
137
138 @Override
139 public boolean isPeriodCriterion() { return false; }
140 }