001 package ttsolver.heuristics;
002
003 import ifs.perturbations.*;
004 import ifs.util.*;
005 import ifs.model.*;
006 import ifs.solution.*;
007 import ttsolver.model.*;
008 import ttsolver.constraint.*;
009 import java.util.*;
010 import edu.purdue.smas.timetable.serverfwk.ParameterDefinition;
011
012 /**
013 * Perturbation penalty computation.
014 * <br><br>
015 * In practise, the strategy for computing perturbations needs to be extended. For example, a change in time is usually
016 * much worse than a movement to a different classroom. The number of enrolled/involved students should also be taken
017 * into account. Another factor is whether the solution has already been published or not.
018 * <br>
019 * The priorities for evaluating perturbations are as follows. Before publishing timetable:<ul>
020 * <li>minimize number of classes with time changes,
021 * <li>minimize number of student conflicts,
022 * <li>optimize satisfaction of problem soft constraints.
023 * </ul><br>
024 * After publishing the timetable (class time changes are not allowed):<ul>
025 * <li>minimize number of additional (new) student conflicts,
026 * <li>minimize number of students with time changes,
027 * <li>minimize number of classes with time changes,
028 * <li>optimize satisfaction of problem soft constraints.
029 * </ul>
030 * In both cases, the number of classes with room change is not significant at all. Before the timetable is published,
031 * minimizing the number of classes with time changes is the most important criteria for the MPP as long as it does not
032 * create too many additional student conflicts in the process. Therefore, as a compromise, the cost (in equivalent
033 * conflicts) of changing the time assigned to a class equals a number like 5% of the students enrolled in that class.
034 * Otherwise none of our other criteria would have any importance.
035 * <br><br>
036 * Similar properties apply between other criteria as well. To fulfil all these needs we have crated a function (called
037 * perturbations penalty) which can be computed over a partial solution. This is a weighted sum of various perturbations
038 * criteria like the number of classes with time changes or the number of additional student conflicts. This
039 * perturbation penalty is added as an extra optimization criterion to the solution comparator and to value selection
040 * criterion, so we can also setup the weights between this perturbation penalty and other (initial) soft constraints.
041 * <br><br>
042 * Parameters:
043 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
044 * <tr><td>Perturbations.DifferentPlacement</td><td>{@link Double}</td><td>Different value than initial is assigned</td></tr>
045 * <tr><td>Perturbations.AffectedStudentWeight</td><td>{@link Double}</td><td>Number of students which are enrolled in a class which is placed to a different location than initial (a student can be included twice or more)</td></tr>
046 * <tr><td>Perturbations.AffectedInstructorWeight</td><td>{@link Double}</td><td>Number of instructors which are assigned to classes which are placed to different locations than initial (an instructor can be included twice or more)</td></tr>
047 * <tr><td>Perturbations.DifferentRoomWeight</td><td>{@link Double}</td><td>Number of classes which are placed to a different room than initial</td></tr>
048 * <tr><td>Perturbations.DifferentBuildingWeight</td><td>{@link Double}</td><td>Number of classes which are placed to a different building than initial</td></tr>
049 * <tr><td>Perturbations.DifferentTimeWeight</td><td>{@link Double}</td><td>Number of classes which are placed in a different time than initial</td></tr>
050 * <tr><td>Perturbations.DifferentDayWeight</td><td>{@link Double}</td><td>Number of classes which are placed in a different days than initial</td></tr>
051 * <tr><td>Perturbations.DifferentHourWeight</td><td>{@link Double}</td><td>Number of classes which are placed in a different hours than initial</td></tr>
052 * <tr><td>Perturbations.DeltaStudentConflictsWeight</td><td>{@link Double}</td><td>Difference of student conflicts of classes assigned to current placements instead of initial placements. It is a difference between number of students conflicts which are in the initial solution and the current one. Student conflicts created by classes without initial placement are not taken into account</td></tr>
053 * <tr><td>Perturbations.NewStudentConflictsWeight</td><td>{@link Double}</td><td>New created student conflicts -- particular students are taken into account. Student conflicts created by classes without initial placement are not taken into account</td></tr>
054 * <tr><td>Perturbations.TooFarForInstructorsWeight</td><td>{@link Double}</td><td>New placement of a class is too far from the intial placement (instructor-wise). It is computed only when the class has an instructor assigned, moreover:<ul><li>0 < distance(currentPlacement,initialPlacement) <= 5 .. weight is taken once<li>5 < distance(currentPlacement,initialPlacement) <= 20 .. weight is taken twice<li>20 < distance(currentPlacement,initialPlacement) .. weight is taken ten times</ul></td></tr>
055 * <tr><td>Perturbations.TooFarForStudentsWeight</td><td>{@link Double}</td><td>New placement of a class is too far from the intial placement (instructor-student). It is weighted by the number of students enrolled in the class when distance(currentPlacement,initialPlacement) > 67</td></tr>
056 * <tr><td>Perturbations.DeltaInstructorDistancePreferenceWeight</td><td>{@link Double}</td><td>Difference between number of instructor distance preferences of the initial (but maybe inconsistent) solution and the current solution. Instructor distance preferences of classes without initial placement are not taken into account</td></tr>
057 * <tr><td>Perturbations.DeltaRoomPreferenceWeight</td><td>{@link Double}</td><td>Difference between room preferences of the initial and the current solution. Room preferences of classes without initial placement are not taken into account</td></tr>
058 * <tr><td>Perturbations.DeltaTimePreferenceWeight</td><td>{@link Double}</td><td>Difference between time preferences of the initial and the current solution. Time preferences of classes without initial placement are not taken into account</td></tr>
059 * <tr><td>Perturbations.AffectedStudentByTimeWeight</td><td>{@link Double}</td><td>Number of students which are enrolled in a class which is placed to a different time than initial </td></tr>
060 * <tr><td>Perturbations.AffectedInstructorByTimeWeight</td><td>{@link Double}</td><td>Number of instructors which are assigned to classes which are placed to different time than initial</td></tr>
061 * <tr><td>Perturbations.AffectedStudentByRoomWeight</td><td>{@link Double}</td><td>Number of students which are enrolled in a class which is placed to a different room than initial </td></tr>
062 * <tr><td>Perturbations.AffectedInstructorByRoomWeight</td><td>{@link Double}</td><td>Number of instructors which are assigned to classes which are placed to different room than initial </td></tr>
063 * <tr><td>Perturbations.AffectedStudentByBldgWeight</td><td>{@link Double}</td><td>Number of students which are enrolled in a class which is placed to a different building than initial</td></tr>
064 * <tr><td>Perturbations.AffectedInstructorByBldgWeight</td><td>{@link Double}</td><td>Number of instructors which are assigned to classes which are placed to different building than initial </td></tr>
065 * </table>
066 *
067 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
068 * @version 1.0
069 */
070
071 public class UniversalPerturbationsCounter extends DefaultPerturbationsCounter {
072 private double iDifferentPlacement = 1.0;
073 private double iAffectedStudentWeight = 0.0;
074 private double iAffectedInstructorWeight = 0.0;
075 private double iAffectedStudentByTimeWeight = 0.0;
076 private double iAffectedInstructorByTimeWeight = 0.0;
077 private double iAffectedStudentByRoomWeight = 0.0;
078 private double iAffectedInstructorByRoomWeight = 0.0;
079 private double iAffectedStudentByBldgWeight = 0.0;
080 private double iAffectedInstructorByBldgWeight = 0.0;
081 private double iDifferentRoomWeight = 0.0;
082 private double iDifferentBuildingWeight = 0.0;
083 private double iDifferentTimeWeight = 0.0;
084 private double iDifferentDayWeight = 0.0;
085 private double iDifferentHourWeight = 0.0;
086 private double iNewStudentConflictsWeight = 0.0;
087 private double iDeltaStudentConflictsWeight = 0.0;
088 private double iTooFarForInstructorsWeight = 0.0;
089 private double iTooFarForStudentsWeight = 0.0;
090 private double iDeltaInstructorDistancePreferenceWeight = 0.0;
091 private double iDeltaRoomPreferenceWeight = 0.0;
092 private double iDeltaTimePreferenceWeight = 0.0;
093 private boolean iMPP = false;
094
095 public UniversalPerturbationsCounter(DataProperties properties) {
096 super(properties);
097 iMPP = properties.getPropertyBoolean("General.MPP",false);
098 iDifferentPlacement = properties.getPropertyDouble("Perturbations.DifferentPlacement",iDifferentPlacement);
099 iAffectedStudentWeight = properties.getPropertyDouble("Perturbations.AffectedStudentWeight",iAffectedStudentWeight);
100 iAffectedInstructorWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorWeight",iAffectedInstructorWeight);
101 iAffectedStudentByTimeWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByTimeWeight",iAffectedStudentByTimeWeight);
102 iAffectedInstructorByTimeWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByTimeWeight",iAffectedInstructorByTimeWeight);
103 iAffectedStudentByRoomWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByRoomWeight",iAffectedStudentByRoomWeight);
104 iAffectedInstructorByRoomWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByRoomWeight",iAffectedInstructorByRoomWeight);
105 iAffectedStudentByBldgWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByBldgWeight",iAffectedStudentByBldgWeight);
106 iAffectedInstructorByBldgWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByBldgWeight",iAffectedInstructorByBldgWeight);
107 iDifferentRoomWeight = properties.getPropertyDouble("Perturbations.DifferentRoomWeight",iDifferentRoomWeight);
108 iDifferentBuildingWeight = properties.getPropertyDouble("Perturbations.DifferentBuildingWeight",iDifferentBuildingWeight);
109 iDifferentTimeWeight = properties.getPropertyDouble("Perturbations.DifferentTimeWeight",iDifferentTimeWeight);
110 iDifferentDayWeight = properties.getPropertyDouble("Perturbations.DifferentDayWeight",iDifferentDayWeight);
111 iDifferentHourWeight = properties.getPropertyDouble("Perturbations.DifferentHourWeight",iDifferentHourWeight);
112 iDeltaStudentConflictsWeight = properties.getPropertyDouble("Perturbations.DeltaStudentConflictsWeight",iDeltaStudentConflictsWeight);
113 iNewStudentConflictsWeight = properties.getPropertyDouble("Perturbations.NewStudentConflictsWeight",iNewStudentConflictsWeight);
114 iTooFarForInstructorsWeight = properties.getPropertyDouble("Perturbations.TooFarForInstructorsWeight",iTooFarForInstructorsWeight);
115 iTooFarForStudentsWeight = properties.getPropertyDouble("Perturbations.TooFarForStudentsWeight",iTooFarForStudentsWeight);
116 iDeltaInstructorDistancePreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaInstructorDistancePreferenceWeight",iDeltaInstructorDistancePreferenceWeight);
117 iDeltaRoomPreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaRoomPreferenceWeight",iDeltaRoomPreferenceWeight);
118 iDeltaTimePreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaTimePreferenceWeight",iDeltaTimePreferenceWeight);
119 }
120
121 public static Vector parameters() {
122 Vector ret = new FastVector();
123
124 ParameterDefinition.Dependency mppDep = new ParameterDefinition.Dependency("General.MPP","true");
125
126 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DifferentPlacement", "Different placement than initial", ParameterDefinition.TYPE_DOUBLE, "1.0").addDependency(mppDep));
127 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedStudentWeight", "Number of students", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
128 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedInstructorWeight", "An instructor is assigned", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
129 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedStudentByTimeWeight", "Number of students (time change)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
130 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedInstructorByTimeWeight", "An instructor is assigned (time change)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
131 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedStudentByRoomWeight", "Number of students (room change)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
132 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedInstructorByRoomWeight", "An instructor is assigned (room change)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
133 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedStudentByBldgWeight", "Number of students (building change)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
134 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.AffectedInstructorByBldgWeight", "An instructor is assigned (building change)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
135 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DifferentRoomWeight", "Different room used", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
136 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DifferentBuildingWeight", "Different building used", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
137 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DifferentTimeWeight", "Different time used", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
138 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DifferentDayWeight", "Different day(s) used", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
139 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DifferentHourWeight", "Different hour(s) used", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
140 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DeltaStudentConflictsWeight", "Delta of student conflicts", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
141 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.NewStudentConflictsWeight", "New students in conflict", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
142 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.TooFarForInstructorsWeight", "New placement too far from initial (fot instructors)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
143 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.TooFarForStudentsWeight", "New placement too far from initial (for students)", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
144 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DeltaInstructorDistancePreferenceWeight", "Delta of instructor distance preferences", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
145 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DeltaRoomPreferenceWeight", "Delta of room preferences", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
146 ret.addElement(new ParameterDefinition("Perturbations - Weights","Perturbations.DeltaTimePreferenceWeight", "Delta of time preferences", ParameterDefinition.TYPE_DOUBLE, "0.0").addDependency(mppDep));
147
148 return ret;
149 }
150
151 protected double getPenalty(Value assignedValue, Value initialValue) {
152 // assigned and initial value of the same lecture
153 // assigned might be null
154 Lecture lecture = (Lecture)initialValue.variable();
155 Placement assignedPlacement = (assignedValue==null?null:(Placement)assignedValue);
156 Placement initialPlacement = (Placement)initialValue;
157 double penalty = 0.0;
158 if (iDifferentPlacement!=0.0)
159 penalty += iDifferentPlacement;
160 if (iAffectedStudentWeight!=0.0)
161 penalty += iAffectedStudentWeight*lecture.countStudents();
162 if (iAffectedInstructorWeight!=0.0 && initialPlacement.getInstructorId()!=null)
163 penalty += iAffectedInstructorWeight;
164 if (assignedValue!=null) {
165 if ((iDifferentRoomWeight!=0.0 || iAffectedInstructorByRoomWeight!=0.0 || iAffectedStudentByRoomWeight!=0.0) && !initialPlacement.getRoomId().equals(assignedPlacement.getRoomId())) {
166 penalty += iDifferentRoomWeight;
167 if (initialPlacement.getInstructorId()!=null) penalty += iAffectedInstructorByRoomWeight;
168 penalty += iAffectedStudentByRoomWeight * lecture.countStudents();
169 } if ((iDifferentBuildingWeight!=0.0 || iAffectedInstructorByBldgWeight!=0.0 || iAffectedStudentByBldgWeight!=0.0) && !initialPlacement.getBuildingId().equals(assignedPlacement.getBuildingId())) {
170 penalty += iDifferentBuildingWeight;
171 if (initialPlacement.getInstructorId()!=null) penalty += iAffectedInstructorByBldgWeight;
172 penalty += iAffectedStudentByBldgWeight * lecture.countStudents();
173 } if ((iDifferentTimeWeight!=0.0 || iAffectedInstructorByTimeWeight!=0.0 || iAffectedStudentByTimeWeight!=0.0) && !initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) {
174 penalty += iDifferentTimeWeight;
175 if (initialPlacement.getInstructorId()!=null) penalty += iAffectedInstructorByTimeWeight;
176 penalty += iAffectedStudentByTimeWeight * lecture.countStudents();
177 } if (iDifferentDayWeight!=0.0 && initialPlacement.getTimeLocation().getDayCode()!=assignedPlacement.getTimeLocation().getDayCode())
178 penalty += iDifferentDayWeight;
179 if (iDifferentHourWeight!=0.0 && initialPlacement.getTimeLocation().getTimeCode()!=assignedPlacement.getTimeLocation().getTimeCode())
180 penalty += iDifferentHourWeight;
181 if ((iTooFarForInstructorsWeight!=0.0 || iTooFarForStudentsWeight!=0.0) && !initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) {
182 double distance = Placement.getDistance(initialPlacement, assignedPlacement);
183 if (initialPlacement.getInstructorId()!=null && iTooFarForInstructorsWeight!=0.0) {
184 if (distance>0.0 && distance<=5.0) {
185 penalty += iTooFarForInstructorsWeight;
186 } else if (distance>5.0 && distance<=20.0) {
187 penalty += 2*iTooFarForInstructorsWeight;
188 } else if (distance>20.0) {
189 penalty += 10*iTooFarForInstructorsWeight;
190 }
191 }
192 if (iTooFarForStudentsWeight!=0.0 && distance > 67.0)
193 penalty += iTooFarForStudentsWeight*lecture.countStudents();
194 }
195 if (iDeltaStudentConflictsWeight!=0.0) {
196 int newStudentConflicts = lecture.countStudentConflicts(assignedValue);
197 int oldStudentConflicts = lecture.countInitialStudentConflicts();
198 penalty += iDeltaStudentConflictsWeight * (newStudentConflicts-oldStudentConflicts);
199 }
200 if (iNewStudentConflictsWeight!=0.0) {
201 Vector newStudentConflicts = lecture.conflictStudents(assignedValue);
202 Set initialStudentConflicts = lecture.initialStudentConflicts();
203 for (Enumeration e=newStudentConflicts.elements();e.hasMoreElements();)
204 if (!initialStudentConflicts.contains(e.nextElement())) penalty += iNewStudentConflictsWeight;
205 }
206 if (iDeltaTimePreferenceWeight!=0.0) {
207 penalty += iDeltaTimePreferenceWeight * (assignedPlacement.getTimeLocation().getPreference() - initialPlacement.getTimeLocation().getPreference());
208 }
209 if (iDeltaRoomPreferenceWeight!=0.0) {
210 penalty += iDeltaRoomPreferenceWeight * (assignedPlacement.getRoomLocation().getPreference() - initialPlacement.getRoomLocation().getPreference());
211 }
212 if (iDeltaInstructorDistancePreferenceWeight!=0.0) {
213 InstructorConstraint ic = lecture.getInstructorConstraint();
214 if (ic!=null) for (Enumeration e=ic.variables().elements();e.hasMoreElements();) {
215 Lecture lect = (Lecture)e.nextElement();
216 if (lect.equals(lecture)) continue;
217 int initialPreference = (lect.getInitialAssignment()==null?0:InstructorConstraint.getDistancePreference(initialPlacement,(Placement)lect.getInitialAssignment()));
218 int assignedPreference = (lect.getAssignment()==null?0:InstructorConstraint.getDistancePreference(assignedPlacement,(Placement)lect.getAssignment()));
219 penalty += iDeltaInstructorDistancePreferenceWeight * (assignedPreference - initialPreference);
220 }
221 }
222 }
223 return penalty;
224 }
225
226 public void getInfo(Dictionary info, Solution solution) {
227 super.getInfo(info, solution);
228 if (!iMPP) return;
229 int perts = 0;
230 long affectedStudents=0;
231 int affectedInstructors=0;
232 long affectedStudentsByTime=0;
233 int affectedInstructorsByTime=0;
234 long affectedStudentsByRoom=0;
235 int affectedInstructorsByRoom=0;
236 long affectedStudentsByBldg=0;
237 int affectedInstructorsByBldg=0;
238 int differentRoom=0;
239 int differentBuilding=0;
240 int differentTime=0;
241 int differentDay=0;
242 int differentHour=0;
243 int tooFarForInstructors=0;
244 int tooFarForStudents=0;
245 int deltaStudentConflicts=0;
246 int newStudentConflicts=0;
247 int deltaTimePreferences=0;
248 int deltaRoomPreferences=0;
249 int deltaInstructorDistancePreferences=0;
250 for (Enumeration e=solution.getModel().perturbVariables().elements();e.hasMoreElements();) {
251 Variable variable = (Variable)e.nextElement();
252 if (variable.getAssignment()==null || variable.getInitialAssignment()==null || variable.getAssignment().equals(variable.getInitialAssignment())) continue;
253 perts++;
254 Lecture lecture = (Lecture)variable ;
255 Placement assignedPlacement = (Placement)variable.getAssignment();
256 Placement initialPlacement = (Placement)variable.getInitialAssignment();
257 affectedStudents += lecture.countStudents();
258 if (initialPlacement.getInstructorId()!=null) affectedInstructors++;
259 if (!initialPlacement.getRoomId().equals(assignedPlacement.getRoomId())) {
260 differentRoom++;
261 if (initialPlacement.getInstructorId()!=null) affectedInstructorsByRoom++;
262 affectedStudentsByRoom += lecture.countStudents();
263 }
264 if (!initialPlacement.getBuildingId().equals(assignedPlacement.getBuildingId())) {
265 differentBuilding++;
266 if (initialPlacement.getInstructorId()!=null) affectedInstructorsByBldg++;
267 affectedStudentsByBldg += lecture.countStudents();
268 }
269 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) {
270 differentTime++;
271 if (initialPlacement.getInstructorId()!=null) affectedInstructorsByTime++;
272 affectedStudentsByTime += lecture.countStudents();
273 }
274 if (initialPlacement.getTimeLocation().getDayCode()!=assignedPlacement.getTimeLocation().getDayCode()) differentDay++;
275 if (initialPlacement.getTimeLocation().getTimeCode()!=assignedPlacement.getTimeLocation().getTimeCode()) differentHour++;
276 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) {
277 double distance = Placement.getDistance(initialPlacement, assignedPlacement);
278 if (initialPlacement.getInstructorId()!=null) {
279 if (distance>0.0 && distance<=5.0) tooFarForInstructors+=1;
280 else if (distance>5.0 && distance<=20.0) tooFarForInstructors+=2;
281 else if (distance>20.0) tooFarForInstructors+=10;
282 }
283 if (distance > 67.0) tooFarForStudents+=lecture.countStudents();
284 }
285 deltaStudentConflicts += lecture.countStudentConflicts(assignedPlacement) - lecture.countInitialStudentConflicts();
286 Vector newStudentConflictsSet = lecture.conflictStudents(assignedPlacement);
287 Set initialStudentConflicts = lecture.initialStudentConflicts();
288 for (Enumeration e1=newStudentConflictsSet.elements();e1.hasMoreElements();)
289 if (!initialStudentConflicts.contains(e1.nextElement())) newStudentConflicts++;
290 deltaTimePreferences += assignedPlacement.getTimeLocation().getPreference() - initialPlacement.getTimeLocation().getPreference();
291 deltaRoomPreferences += assignedPlacement.getRoomLocation().getPreference() - initialPlacement.getRoomLocation().getPreference();
292 InstructorConstraint ic = lecture.getInstructorConstraint();
293 if (ic!=null) for (Enumeration e1=ic.variables().elements();e1.hasMoreElements();) {
294 Lecture lect = (Lecture)e1.nextElement();
295 if (lect.equals(lecture)) continue;
296 int initialPreference = (lect.getInitialAssignment()==null?0:InstructorConstraint.getDistancePreference(initialPlacement,(Placement)lect.getInitialAssignment()));
297 int assignedPreference = (lect.getAssignment()==null?0:InstructorConstraint.getDistancePreference(assignedPlacement,(Placement)lect.getAssignment()));
298 deltaInstructorDistancePreferences += assignedPreference - initialPreference;
299 }
300 }
301 info.put("Perturbations: Different placement", String.valueOf(perts)+" (weighted "+sDoubleFormat.format(iDifferentPlacement*perts)+")");
302 info.put("Perturbations: Number of affected students", String.valueOf(affectedStudents)+" (weighted "+sDoubleFormat.format(iAffectedStudentWeight*affectedStudents)+")");
303 info.put("Perturbations: Number of affected instructors", String.valueOf(affectedInstructors)+" (weighted "+sDoubleFormat.format(iAffectedInstructorWeight*affectedInstructors)+")");
304 info.put("Perturbations: Number of affected students (time change)", String.valueOf(affectedStudentsByTime)+" (weighted "+sDoubleFormat.format(iAffectedStudentByTimeWeight*affectedStudentsByTime)+")");
305 info.put("Perturbations: Number of affected instructors (time change)", String.valueOf(affectedInstructorsByTime)+" (weighted "+sDoubleFormat.format(iAffectedInstructorByTimeWeight*affectedInstructorsByTime)+")");
306 info.put("Perturbations: Number of affected students (room change)", String.valueOf(affectedStudentsByRoom)+" (weighted "+sDoubleFormat.format(iAffectedStudentByRoomWeight*affectedStudentsByRoom)+")");
307 info.put("Perturbations: Number of affected instructors (room change)", String.valueOf(affectedInstructorsByRoom)+" (weighted "+sDoubleFormat.format(iAffectedInstructorByRoomWeight*affectedInstructorsByRoom)+")");
308 info.put("Perturbations: Number of affected students (bldg change)", String.valueOf(affectedStudentsByBldg)+" (weighted "+sDoubleFormat.format(iAffectedStudentByBldgWeight*affectedStudentsByBldg)+")");
309 info.put("Perturbations: Number of affected instructors (bldg change)", String.valueOf(affectedInstructorsByBldg)+" (weighted "+sDoubleFormat.format(iAffectedInstructorByBldgWeight*affectedInstructorsByBldg)+")");
310 info.put("Perturbations: Different room", String.valueOf(differentRoom)+" (weighted "+sDoubleFormat.format(iDifferentRoomWeight*differentRoom)+")");
311 info.put("Perturbations: Different building", String.valueOf(differentBuilding)+" (weighted "+sDoubleFormat.format(iDifferentBuildingWeight*differentBuilding)+")");
312 info.put("Perturbations: Different time", String.valueOf(differentTime)+" (weighted "+sDoubleFormat.format(iDifferentTimeWeight*differentTime)+")");
313 info.put("Perturbations: Different day", String.valueOf(differentDay)+" (weighted "+sDoubleFormat.format(iDifferentDayWeight*differentDay)+")");
314 info.put("Perturbations: Different hour", String.valueOf(differentHour)+" (weighted "+sDoubleFormat.format(iDifferentHourWeight*differentHour)+")");
315 info.put("Perturbations: New placement too far from initial (for instructors)", String.valueOf(tooFarForInstructors)+" (weighted "+sDoubleFormat.format(iTooFarForInstructorsWeight*tooFarForInstructors)+")");
316 info.put("Perturbations: New placement too far from initial (for students)", String.valueOf(tooFarForStudents)+" (weighted "+sDoubleFormat.format(iTooFarForStudentsWeight*tooFarForStudents)+")");
317 info.put("Perturbations: Delta student conflicts", String.valueOf(deltaStudentConflicts)+" (weighted "+sDoubleFormat.format(iDeltaStudentConflictsWeight*deltaStudentConflicts)+")");
318 info.put("Perturbations: New student conflicts", String.valueOf(newStudentConflicts)+" (weighted "+sDoubleFormat.format(iNewStudentConflictsWeight*newStudentConflicts)+")");
319 info.put("Perturbations: Delta time preferences", String.valueOf(deltaTimePreferences)+" (weighted "+sDoubleFormat.format(iDeltaTimePreferenceWeight*deltaTimePreferences)+")");
320 info.put("Perturbations: Delta room preferences", String.valueOf(deltaRoomPreferences)+" (weighted "+sDoubleFormat.format(iDeltaRoomPreferenceWeight*deltaRoomPreferences)+")");
321 info.put("Perturbations: Delta instructor distance preferences", String.valueOf(deltaInstructorDistancePreferences)+" (weighted "+sDoubleFormat.format(iDeltaInstructorDistancePreferenceWeight*deltaInstructorDistancePreferences)+")");
322 }
323
324 public Hashtable getCompactInfo(Solution solution, boolean includeZero, boolean weighted) {
325 Hashtable info = new Hashtable();
326 if (!iMPP) return info;
327 int perts = 0;
328 long affectedStudents=0;
329 int affectedInstructors=0;
330 long affectedStudentsByTime=0;
331 int affectedInstructorsByTime=0;
332 long affectedStudentsByRoom=0;
333 int affectedInstructorsByRoom=0;
334 long affectedStudentsByBldg=0;
335 int affectedInstructorsByBldg=0;
336 int differentRoom=0;
337 int differentBuilding=0;
338 int differentTime=0;
339 int differentDay=0;
340 int differentHour=0;
341 int tooFarForInstructors=0;
342 int tooFarForStudents=0;
343 int deltaStudentConflicts=0;
344 int newStudentConflicts=0;
345 int deltaTimePreferences=0;
346 int deltaRoomPreferences=0;
347 int deltaInstructorDistancePreferences=0;
348 for (Enumeration e=solution.getModel().perturbVariables().elements();e.hasMoreElements();) {
349 Variable variable = (Variable)e.nextElement();
350 if (variable.getAssignment()==null || variable.getInitialAssignment()==null || variable.getAssignment().equals(variable.getInitialAssignment())) continue;
351 perts++;
352 Lecture lecture = (Lecture)variable ;
353 Placement assignedPlacement = (Placement)variable.getAssignment();
354 Placement initialPlacement = (Placement)variable.getInitialAssignment();
355 affectedStudents += lecture.countStudents();
356 if (initialPlacement.getInstructorId()!=null) affectedInstructors++;
357 if (!initialPlacement.getRoomId().equals(assignedPlacement.getRoomId())) {
358 differentRoom++;
359 if (initialPlacement.getInstructorId()!=null) affectedInstructorsByRoom++;
360 affectedStudentsByRoom += lecture.countStudents();
361 }
362 if (!initialPlacement.getBuildingId().equals(assignedPlacement.getBuildingId())) {
363 differentBuilding++;
364 if (initialPlacement.getInstructorId()!=null) affectedInstructorsByBldg++;
365 affectedStudentsByBldg += lecture.countStudents();
366 }
367 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) {
368 differentTime++;
369 if (initialPlacement.getInstructorId()!=null) affectedInstructorsByTime++;
370 affectedStudentsByTime += lecture.countStudents();
371 }
372 if (initialPlacement.getTimeLocation().getDayCode()!=assignedPlacement.getTimeLocation().getDayCode()) differentDay++;
373 if (initialPlacement.getTimeLocation().getTimeCode()!=assignedPlacement.getTimeLocation().getTimeCode()) differentHour++;
374 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) {
375 double distance = Placement.getDistance(initialPlacement, assignedPlacement);
376 if (initialPlacement.getInstructorId()!=null) {
377 if (distance>0.0 && distance<=5.0) tooFarForInstructors+=1;
378 else if (distance>5.0 && distance<=20.0) tooFarForInstructors+=2;
379 else if (distance>20.0) tooFarForInstructors+=10;
380 }
381 if (distance > 67.0) tooFarForStudents+=lecture.countStudents();
382 }
383 deltaStudentConflicts += lecture.countStudentConflicts(assignedPlacement) - lecture.countInitialStudentConflicts();
384 Vector newStudentConflictsSet = lecture.conflictStudents(assignedPlacement);
385 Set initialStudentConflicts = lecture.initialStudentConflicts();
386 for (Enumeration e1=newStudentConflictsSet.elements();e1.hasMoreElements();)
387 if (!initialStudentConflicts.contains(e1.nextElement())) newStudentConflicts++;
388 deltaTimePreferences += assignedPlacement.getTimeLocation().getPreference() - initialPlacement.getTimeLocation().getPreference();
389 deltaRoomPreferences += assignedPlacement.getRoomLocation().getPreference() - initialPlacement.getRoomLocation().getPreference();
390 InstructorConstraint ic = lecture.getInstructorConstraint();
391 if (ic!=null) for (Enumeration e1=ic.variables().elements();e1.hasMoreElements();) {
392 Lecture lect = (Lecture)e1.nextElement();
393 if (lect.equals(lecture)) continue;
394 int initialPreference = (lect.getInitialAssignment()==null?0:InstructorConstraint.getDistancePreference(initialPlacement,(Placement)lect.getInitialAssignment()));
395 int assignedPreference = (lect.getAssignment()==null?0:InstructorConstraint.getDistancePreference(assignedPlacement,(Placement)lect.getAssignment()));
396 deltaInstructorDistancePreferences += assignedPreference - initialPreference;
397 }
398 }
399 if (includeZero || iDifferentPlacement!=0.0)
400 info.put("Different placement", new Double(weighted?iDifferentPlacement*perts:perts));
401 if (includeZero || iAffectedStudentWeight!=0.0)
402 info.put("Affected students", new Double(weighted?iAffectedStudentWeight*affectedStudents:affectedStudents));
403 if (includeZero || iAffectedInstructorWeight!=0.0)
404 info.put("Affected instructors", new Double(weighted?iAffectedInstructorWeight*affectedInstructors:affectedInstructors));
405 if (includeZero || iAffectedStudentByTimeWeight!=0.0)
406 info.put("Affected students [time]", new Double(weighted?iAffectedStudentByTimeWeight*affectedStudentsByTime:affectedStudentsByTime));
407 if (includeZero || iAffectedInstructorByTimeWeight!=0.0)
408 info.put("Affected instructors [time]", new Double(weighted?iAffectedInstructorByTimeWeight*affectedInstructorsByTime:affectedInstructorsByTime));
409 if (includeZero || iAffectedStudentByRoomWeight!=0.0)
410 info.put("Affected students [room]", new Double(weighted?iAffectedStudentByRoomWeight*affectedStudentsByRoom:affectedStudentsByRoom));
411 if (includeZero || iAffectedInstructorByRoomWeight!=0.0)
412 info.put("Affected instructors [room]", new Double(weighted?iAffectedInstructorByRoomWeight*affectedInstructorsByRoom:affectedInstructorsByRoom));
413 if (includeZero || iAffectedStudentByBldgWeight!=0.0)
414 info.put("Affected students [bldg]", new Double(weighted?iAffectedStudentByBldgWeight*affectedStudentsByBldg:affectedStudentsByBldg));
415 if (includeZero || iAffectedInstructorByBldgWeight!=0.0)
416 info.put("Affected instructors [bldg]", new Double(weighted?iAffectedInstructorByBldgWeight*affectedInstructorsByBldg:affectedInstructorsByBldg));
417 if (includeZero || iDifferentRoomWeight!=0.0)
418 info.put("Different room", new Double(weighted?iDifferentRoomWeight*differentRoom:differentRoom));
419 if (includeZero || iDifferentBuildingWeight!=0.0)
420 info.put("Different building", new Double(weighted?iDifferentBuildingWeight*differentBuilding:differentBuilding));
421 if (includeZero || iDifferentTimeWeight!=0.0)
422 info.put("Different time", new Double(weighted?iDifferentTimeWeight*differentTime:differentTime));
423 if (includeZero || iDifferentDayWeight!=0.0)
424 info.put("Different day", new Double(weighted?iDifferentDayWeight*differentDay:differentDay));
425 if (includeZero || iDifferentHourWeight!=0.0)
426 info.put("Different hour", new Double(weighted?iDifferentHourWeight*differentHour:differentHour));
427 if (includeZero || iTooFarForInstructorsWeight!=0.0)
428 info.put("New placement too far for initial [instructors]", new Double(weighted?iTooFarForInstructorsWeight*tooFarForInstructors:tooFarForInstructors));
429 if (includeZero || iTooFarForStudentsWeight!=0.0)
430 info.put("New placement too far for initial [students]", new Double(weighted?iTooFarForStudentsWeight*tooFarForStudents:tooFarForStudents));
431 if (includeZero || iDeltaStudentConflictsWeight!=0.0)
432 info.put("Delta student conflicts", new Double(weighted?iDeltaStudentConflictsWeight*deltaStudentConflicts:deltaStudentConflicts));
433 if (includeZero || iNewStudentConflictsWeight!=0.0)
434 info.put("New student conflicts", new Double(weighted?iNewStudentConflictsWeight*newStudentConflicts:newStudentConflicts));
435 if (includeZero || iDeltaTimePreferenceWeight!=0.0)
436 info.put("Delta time preferences", new Double(weighted?iDeltaTimePreferenceWeight*deltaTimePreferences:deltaTimePreferences));
437 if (includeZero || iDeltaRoomPreferenceWeight!=0.0)
438 info.put("Delta room preferences", new Double(weighted?iDeltaRoomPreferenceWeight*deltaRoomPreferences:deltaRoomPreferences));
439 if (includeZero || iDeltaInstructorDistancePreferenceWeight!=0.0)
440 info.put("Delta instructor distance preferences", new Double(weighted?iDeltaInstructorDistancePreferenceWeight*deltaInstructorDistancePreferences:deltaInstructorDistancePreferences));
441 return info;
442 }
443 }