001package org.cpsolver.coursett.heuristics; 002 003import java.util.HashMap; 004import java.util.Iterator; 005import java.util.List; 006import java.util.Map; 007import java.util.Set; 008 009import org.cpsolver.coursett.Constants; 010import org.cpsolver.coursett.constraint.InstructorConstraint; 011import org.cpsolver.coursett.model.Lecture; 012import org.cpsolver.coursett.model.Placement; 013import org.cpsolver.coursett.model.Student; 014import org.cpsolver.coursett.model.TimetableModel; 015import org.cpsolver.ifs.assignment.Assignment; 016import org.cpsolver.ifs.perturbations.DefaultPerturbationsCounter; 017import org.cpsolver.ifs.util.DataProperties; 018import org.cpsolver.ifs.util.DistanceMetric; 019 020 021/** 022 * Perturbation penalty computation. <br> 023 * <br> 024 * In practice, the strategy for computing perturbations needs to be extended. 025 * For example, a change in time is usually much worse than a movement to a 026 * different classroom. The number of enrolled/involved students should also be 027 * taken into account. Another factor is whether the solution has already been 028 * published or not. <br> 029 * The priorities for evaluating perturbations are as follows. Before publishing 030 * timetable: 031 * <ul> 032 * <li>minimize number of classes with time changes, 033 * <li>minimize number of student conflicts, 034 * <li>optimize satisfaction of problem soft constraints. 035 * </ul> 036 * <br> 037 * After publishing the timetable (class time changes are not allowed): 038 * <ul> 039 * <li>minimize number of additional (new) student conflicts, 040 * <li>minimize number of students with time changes, 041 * <li>minimize number of classes with time changes, 042 * <li>optimize satisfaction of problem soft constraints. 043 * </ul> 044 * In both cases, the number of classes with room change is not significant at 045 * all. Before the timetable is published, minimizing the number of classes with 046 * time changes is the most important criteria for the MPP as long as it does 047 * not create too many additional student conflicts in the process. Therefore, 048 * as a compromise, the cost (in equivalent conflicts) of changing the time 049 * assigned to a class equals a number like 5% of the students enrolled in that 050 * class. Otherwise none of our other criteria would have any importance. <br> 051 * <br> 052 * Similar properties apply between other criteria as well. To fulfill all these 053 * needs we have created a function (called perturbations penalty) which can be 054 * computed over a partial solution. This is a weighted sum of various 055 * perturbations criteria like the number of classes with time changes or the 056 * number of additional student conflicts. This perturbation penalty is added as 057 * an extra optimization criterion to the solution comparator and to value 058 * selection criterion, so we can also setup the weights between this 059 * perturbation penalty and other (initial) soft constraints. <br> 060 * <br> 061 * Parameters: 062 * <table border='1'><caption>Related Solver Parameters</caption> 063 * <tr> 064 * <th>Parameter</th> 065 * <th>Type</th> 066 * <th>Comment</th> 067 * </tr> 068 * <tr> 069 * <td>Perturbations.DifferentPlacement</td> 070 * <td>{@link Double}</td> 071 * <td>Different value than initial is assigned</td> 072 * </tr> 073 * <tr> 074 * <td>Perturbations.AffectedStudentWeight</td> 075 * <td>{@link Double}</td> 076 * <td>Number of students which are enrolled in a class which is placed to a 077 * different location than initial (a student can be included twice or more)</td> 078 * </tr> 079 * <tr> 080 * <td>Perturbations.AffectedInstructorWeight</td> 081 * <td>{@link Double}</td> 082 * <td>Number of instructors which are assigned to classes which are placed to 083 * different locations than initial (an instructor can be included twice or 084 * more)</td> 085 * </tr> 086 * <tr> 087 * <td>Perturbations.DifferentRoomWeight</td> 088 * <td>{@link Double}</td> 089 * <td>Number of classes which are placed to a different room than initial</td> 090 * </tr> 091 * <tr> 092 * <td>Perturbations.DifferentBuildingWeight</td> 093 * <td>{@link Double}</td> 094 * <td>Number of classes which are placed to a different building than initial</td> 095 * </tr> 096 * <tr> 097 * <td>Perturbations.DifferentTimeWeight</td> 098 * <td>{@link Double}</td> 099 * <td>Number of classes which are placed in a different time than initial</td> 100 * </tr> 101 * <tr> 102 * <td>Perturbations.DifferentDayWeight</td> 103 * <td>{@link Double}</td> 104 * <td>Number of classes which are placed in a different days than initial</td> 105 * </tr> 106 * <tr> 107 * <td>Perturbations.DifferentHourWeight</td> 108 * <td>{@link Double}</td> 109 * <td>Number of classes which are placed in a different hours than initial</td> 110 * </tr> 111 * <tr> 112 * <td>Perturbations.DeltaStudentConflictsWeight</td> 113 * <td>{@link Double}</td> 114 * <td>Difference of student conflicts of classes assigned to current placements 115 * instead of initial placements. It is a difference between number of students 116 * conflicts which are in the initial solution and the current one. Student 117 * conflicts created by classes without initial placement are not taken into 118 * account</td> 119 * </tr> 120 * <tr> 121 * <td>Perturbations.NewStudentConflictsWeight</td> 122 * <td>{@link Double}</td> 123 * <td>New created student conflicts -- particular students are taken into 124 * account. Student conflicts created by classes without initial placement are 125 * not taken into account</td> 126 * </tr> 127 * <tr> 128 * <td>Perturbations.TooFarForInstructorsWeight</td> 129 * <td>{@link Double}</td> 130 * <td>New placement of a class is too far from the intial placement 131 * (instructor-wise). It is computed only when the class has an instructor 132 * assigned, moreover: 133 * <ul> 134 * <li>0 < distance(currentPlacement,initialPlacement) <= 5 .. weight is taken 135 * once 136 * <li>5 < distance(currentPlacement,initialPlacement) <= 20 .. weight is taken 137 * twice 138 * <li>20 < distance(currentPlacement,initialPlacement) .. weight is taken ten 139 * times 140 * </ul> 141 * </td> 142 * </tr> 143 * <tr> 144 * <td>Perturbations.TooFarForStudentsWeight</td> 145 * <td>{@link Double}</td> 146 * <td>New placement of a class is too far from the intial placement 147 * (instructor-student). It is weighted by the number of students enrolled in 148 * the class when distance(currentPlacement,initialPlacement) > 67</td> 149 * </tr> 150 * <tr> 151 * <td>Perturbations.DeltaInstructorDistancePreferenceWeight</td> 152 * <td>{@link Double}</td> 153 * <td>Difference between number of instructor distance preferences of the 154 * initial (but maybe inconsistent) solution and the current solution. 155 * Instructor distance preferences of classes without initial placement are not 156 * taken into account</td> 157 * </tr> 158 * <tr> 159 * <td>Perturbations.DeltaRoomPreferenceWeight</td> 160 * <td>{@link Double}</td> 161 * <td>Difference between room preferences of the initial and the current 162 * solution. Room preferences of classes without initial placement are not taken 163 * into account</td> 164 * </tr> 165 * <tr> 166 * <td>Perturbations.DeltaTimePreferenceWeight</td> 167 * <td>{@link Double}</td> 168 * <td>Difference between time preferences of the initial and the current 169 * solution. Time preferences of classes without initial placement are not taken 170 * into account</td> 171 * </tr> 172 * <tr> 173 * <td>Perturbations.AffectedStudentByTimeWeight</td> 174 * <td>{@link Double}</td> 175 * <td>Number of students which are enrolled in a class which is placed to a 176 * different time than initial</td> 177 * </tr> 178 * <tr> 179 * <td>Perturbations.AffectedInstructorByTimeWeight</td> 180 * <td>{@link Double}</td> 181 * <td>Number of instructors which are assigned to classes which are placed to 182 * different time than initial</td> 183 * </tr> 184 * <tr> 185 * <td>Perturbations.AffectedStudentByRoomWeight</td> 186 * <td>{@link Double}</td> 187 * <td>Number of students which are enrolled in a class which is placed to a 188 * different room than initial</td> 189 * </tr> 190 * <tr> 191 * <td>Perturbations.AffectedInstructorByRoomWeight</td> 192 * <td>{@link Double}</td> 193 * <td>Number of instructors which are assigned to classes which are placed to 194 * different room than initial</td> 195 * </tr> 196 * <tr> 197 * <td>Perturbations.AffectedStudentByBldgWeight</td> 198 * <td>{@link Double}</td> 199 * <td>Number of students which are enrolled in a class which is placed to a 200 * different building than initial</td> 201 * </tr> 202 * <tr> 203 * <td>Perturbations.AffectedInstructorByBldgWeight</td> 204 * <td>{@link Double}</td> 205 * <td>Number of instructors which are assigned to classes which are placed to 206 * different building than initial</td> 207 * </tr> 208 * </table> 209 * 210 * @author Tomáš Müller 211 * @version CourseTT 1.3 (University Course Timetabling)<br> 212 * Copyright (C) 2006 - 2014 Tomáš Müller<br> 213 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 214 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 215 * <br> 216 * This library is free software; you can redistribute it and/or modify 217 * it under the terms of the GNU Lesser General Public License as 218 * published by the Free Software Foundation; either version 3 of the 219 * License, or (at your option) any later version. <br> 220 * <br> 221 * This library is distributed in the hope that it will be useful, but 222 * WITHOUT ANY WARRANTY; without even the implied warranty of 223 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 224 * Lesser General Public License for more details. <br> 225 * <br> 226 * You should have received a copy of the GNU Lesser General Public 227 * License along with this library; if not see 228 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 229 */ 230 231public class UniversalPerturbationsCounter extends DefaultPerturbationsCounter<Lecture, Placement> { 232 private double iDifferentPlacement = 1.0; 233 private double iAffectedStudentWeight = 0.0; 234 private double iAffectedInstructorWeight = 0.0; 235 private double iAffectedStudentByTimeWeight = 0.0; 236 private double iAffectedInstructorByTimeWeight = 0.0; 237 private double iAffectedStudentByRoomWeight = 0.0; 238 private double iAffectedInstructorByRoomWeight = 0.0; 239 private double iAffectedStudentByBldgWeight = 0.0; 240 private double iAffectedInstructorByBldgWeight = 0.0; 241 private double iDifferentRoomWeight = 0.0; 242 private double iDifferentBuildingWeight = 0.0; 243 private double iDifferentTimeWeight = 0.0; 244 private double iDifferentDayWeight = 0.0; 245 private double iDifferentHourWeight = 0.0; 246 private double iNewStudentConflictsWeight = 0.0; 247 private double iDeltaStudentConflictsWeight = 0.0; 248 private double iTooFarForInstructorsWeight = 0.0; 249 private double iTooFarForStudentsWeight = 0.0; 250 private double iDeltaInstructorDistancePreferenceWeight = 0.0; 251 private double iDeltaRoomPreferenceWeight = 0.0; 252 private double iDeltaTimePreferenceWeight = 0.0; 253 private boolean iMPP = false; 254 private DistanceMetric iDistanceMetric = null; 255 256 public UniversalPerturbationsCounter(DataProperties properties) { 257 super(properties); 258 iMPP = properties.getPropertyBoolean("General.MPP", false); 259 iDifferentPlacement = properties.getPropertyDouble("Perturbations.DifferentPlacement", iDifferentPlacement); 260 iAffectedStudentWeight = properties.getPropertyDouble("Perturbations.AffectedStudentWeight", 261 iAffectedStudentWeight); 262 iAffectedInstructorWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorWeight", 263 iAffectedInstructorWeight); 264 iAffectedStudentByTimeWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByTimeWeight", 265 iAffectedStudentByTimeWeight); 266 iAffectedInstructorByTimeWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByTimeWeight", 267 iAffectedInstructorByTimeWeight); 268 iAffectedStudentByRoomWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByRoomWeight", 269 iAffectedStudentByRoomWeight); 270 iAffectedInstructorByRoomWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByRoomWeight", 271 iAffectedInstructorByRoomWeight); 272 iAffectedStudentByBldgWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByBldgWeight", 273 iAffectedStudentByBldgWeight); 274 iAffectedInstructorByBldgWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByBldgWeight", 275 iAffectedInstructorByBldgWeight); 276 iDifferentRoomWeight = properties.getPropertyDouble("Perturbations.DifferentRoomWeight", iDifferentRoomWeight); 277 iDifferentBuildingWeight = properties.getPropertyDouble("Perturbations.DifferentBuildingWeight", 278 iDifferentBuildingWeight); 279 iDifferentTimeWeight = properties.getPropertyDouble("Perturbations.DifferentTimeWeight", iDifferentTimeWeight); 280 iDifferentDayWeight = properties.getPropertyDouble("Perturbations.DifferentDayWeight", iDifferentDayWeight); 281 iDifferentHourWeight = properties.getPropertyDouble("Perturbations.DifferentHourWeight", iDifferentHourWeight); 282 iDeltaStudentConflictsWeight = properties.getPropertyDouble("Perturbations.DeltaStudentConflictsWeight", 283 iDeltaStudentConflictsWeight); 284 iNewStudentConflictsWeight = properties.getPropertyDouble("Perturbations.NewStudentConflictsWeight", 285 iNewStudentConflictsWeight); 286 iTooFarForInstructorsWeight = properties.getPropertyDouble("Perturbations.TooFarForInstructorsWeight", 287 iTooFarForInstructorsWeight); 288 iTooFarForStudentsWeight = properties.getPropertyDouble("Perturbations.TooFarForStudentsWeight", 289 iTooFarForStudentsWeight); 290 iDeltaInstructorDistancePreferenceWeight = properties.getPropertyDouble( 291 "Perturbations.DeltaInstructorDistancePreferenceWeight", iDeltaInstructorDistancePreferenceWeight); 292 iDeltaRoomPreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaRoomPreferenceWeight", 293 iDeltaRoomPreferenceWeight); 294 iDeltaTimePreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaTimePreferenceWeight", 295 iDeltaTimePreferenceWeight); 296 iDistanceMetric = new DistanceMetric(properties); 297 } 298 299 @Override 300 protected double getPenalty(Assignment<Lecture, Placement> assignment, Placement assignedPlacement, Placement initialPlacement) { 301 // assigned and initial value of the same lecture 302 // assigned might be null 303 Lecture lecture = initialPlacement.variable(); 304 double penalty = 0.0; 305 if (iDifferentPlacement != 0.0) 306 penalty += iDifferentPlacement; 307 if (iAffectedStudentWeight != 0.0) 308 penalty += iAffectedStudentWeight * lecture.classLimit(assignment); 309 if (iAffectedInstructorWeight != 0.0) 310 penalty += iAffectedInstructorWeight * lecture.getInstructorConstraints().size(); 311 if (assignedPlacement != null) { 312 if ((iDifferentRoomWeight != 0.0 || iAffectedInstructorByRoomWeight != 0.0 || iAffectedStudentByRoomWeight != 0.0)) { 313 int nrDiff = initialPlacement.nrDifferentRooms(assignedPlacement); 314 penalty += nrDiff * iDifferentRoomWeight; 315 penalty += nrDiff * iAffectedInstructorByRoomWeight * lecture.getInstructorConstraints().size(); 316 penalty += nrDiff * iAffectedStudentByRoomWeight * lecture.classLimit(assignment); 317 } 318 if ((iDifferentBuildingWeight != 0.0 || iAffectedInstructorByBldgWeight != 0.0 || iAffectedStudentByBldgWeight != 0.0)) { 319 int nrDiff = initialPlacement.nrDifferentBuildings(assignedPlacement); 320 penalty += nrDiff * iDifferentBuildingWeight; 321 penalty += nrDiff * iAffectedInstructorByBldgWeight * lecture.getInstructorConstraints().size(); 322 penalty += nrDiff * iAffectedStudentByBldgWeight * lecture.classLimit(assignment); 323 } 324 if ((iDifferentTimeWeight != 0.0 || iAffectedInstructorByTimeWeight != 0.0 || iAffectedStudentByTimeWeight != 0.0) 325 && !initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 326 penalty += iDifferentTimeWeight; 327 penalty += iAffectedInstructorByTimeWeight * lecture.getInstructorConstraints().size(); 328 penalty += iAffectedStudentByTimeWeight * lecture.classLimit(assignment); 329 } 330 if (iDifferentDayWeight != 0.0 331 && initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation() 332 .getDayCode()) 333 penalty += iDifferentDayWeight; 334 if (iDifferentHourWeight != 0.0 335 && initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation() 336 .getStartSlot()) 337 penalty += iDifferentHourWeight; 338 if ((iTooFarForInstructorsWeight != 0.0 || iTooFarForStudentsWeight != 0.0) 339 && !initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 340 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 341 if (!lecture.getInstructorConstraints().isEmpty() && iTooFarForInstructorsWeight != 0.0) { 342 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 343 penalty += Constants.sPreferenceLevelDiscouraged * iTooFarForInstructorsWeight 344 * lecture.getInstructorConstraints().size(); 345 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 346 penalty += Constants.sPreferenceLevelStronglyDiscouraged * iTooFarForInstructorsWeight 347 * lecture.getInstructorConstraints().size(); 348 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 349 penalty += Constants.sPreferenceLevelProhibited * iTooFarForInstructorsWeight 350 * lecture.getInstructorConstraints().size(); 351 } 352 } 353 if (iTooFarForStudentsWeight != 0.0 354 && distance > iDistanceMetric.minutes2meters(10)) 355 penalty += iTooFarForStudentsWeight * lecture.classLimit(assignment); 356 } 357 if (iDeltaStudentConflictsWeight != 0.0) { 358 int newStudentConflicts = lecture.countStudentConflicts(assignment, assignedPlacement); 359 int oldStudentConflicts = lecture.countInitialStudentConflicts(); 360 penalty += iDeltaStudentConflictsWeight * (newStudentConflicts - oldStudentConflicts); 361 } 362 if (iNewStudentConflictsWeight != 0.0) { 363 Set<Student> newStudentConflicts = lecture.conflictStudents(assignment, assignedPlacement); 364 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 365 for (Iterator<Student> i = newStudentConflicts.iterator(); i.hasNext();) 366 if (!initialStudentConflicts.contains(i.next())) 367 penalty += iNewStudentConflictsWeight; 368 } 369 if (iDeltaTimePreferenceWeight != 0.0) { 370 penalty += iDeltaTimePreferenceWeight * (assignedPlacement.getTimeLocation().getNormalizedPreference() - initialPlacement.getTimeLocation().getNormalizedPreference()); 371 } 372 if (iDeltaRoomPreferenceWeight != 0.0) { 373 penalty += iDeltaRoomPreferenceWeight * (assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference()); 374 } 375 if (iDeltaInstructorDistancePreferenceWeight != 0.0) { 376 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 377 for (Lecture lect : ic.variables()) { 378 if (lect.equals(lecture)) 379 continue; 380 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 381 int assignedPreference = (assignment.getValue(lect) == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignment.getValue(lect))); 382 penalty += iDeltaInstructorDistancePreferenceWeight * (assignedPreference - initialPreference); 383 } 384 } 385 } 386 } 387 return penalty; 388 } 389 390 public void getInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, Map<String, String> info) { 391 getInfo(assignment, model, info, null); 392 } 393 394 public void getInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, Map<String, String> info, List<Lecture> variables) { 395 if (variables == null) 396 super.getInfo(assignment, model, info); 397 else 398 super.getInfo(assignment, model, info, variables); 399 if (!iMPP) 400 return; 401 int perts = 0; 402 long affectedStudents = 0; 403 int affectedInstructors = 0; 404 long affectedStudentsByTime = 0; 405 int affectedInstructorsByTime = 0; 406 long affectedStudentsByRoom = 0; 407 int affectedInstructorsByRoom = 0; 408 long affectedStudentsByBldg = 0; 409 int affectedInstructorsByBldg = 0; 410 int differentRoom = 0; 411 int differentBuilding = 0; 412 int differentTime = 0; 413 int differentDay = 0; 414 int differentHour = 0; 415 int tooFarForInstructors = 0; 416 int tooFarForStudents = 0; 417 int deltaStudentConflicts = 0; 418 int newStudentConflicts = 0; 419 double deltaTimePreferences = 0; 420 int deltaRoomPreferences = 0; 421 int deltaInstructorDistancePreferences = 0; 422 for (Lecture lecture : (variables == null ? model.perturbVariables(assignment, model.variablesWithInitialValue(), false) : model.perturbVariables(assignment, variables, false))) { 423 if (assignment.getValue(lecture) == null || lecture.getInitialAssignment() == null || assignment.getValue(lecture).equals(lecture.getInitialAssignment())) 424 continue; 425 perts++; 426 Placement assignedPlacement = assignment.getValue(lecture); 427 Placement initialPlacement = lecture.getInitialAssignment(); 428 affectedStudents += lecture.classLimit(assignment); 429 affectedInstructors += lecture.getInstructorConstraints().size(); 430 431 int nrDiff = initialPlacement.nrDifferentRooms(assignedPlacement); 432 differentRoom += nrDiff; 433 affectedInstructorsByRoom += nrDiff * lecture.getInstructorConstraints().size(); 434 affectedStudentsByRoom += nrDiff * lecture.classLimit(assignment); 435 436 nrDiff = initialPlacement.nrDifferentBuildings(assignedPlacement); 437 differentBuilding += nrDiff; 438 affectedInstructorsByBldg += nrDiff * lecture.getInstructorConstraints().size(); 439 affectedStudentsByBldg += nrDiff * lecture.classLimit(assignment); 440 441 deltaRoomPreferences += assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference(); 442 443 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 444 differentTime++; 445 affectedInstructorsByTime += lecture.getInstructorConstraints().size(); 446 affectedStudentsByTime += lecture.classLimit(assignment); 447 } 448 if (initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation().getDayCode()) 449 differentDay++; 450 if (initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation().getStartSlot()) 451 differentHour++; 452 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 453 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 454 if (!lecture.getInstructorConstraints().isEmpty()) { 455 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 456 tooFarForInstructors += Constants.sPreferenceLevelDiscouraged * lecture.getInstructorConstraints().size(); 457 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 458 tooFarForInstructors += Constants.sPreferenceLevelStronglyDiscouraged * lecture.getInstructorConstraints().size(); 459 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 460 tooFarForInstructors += Constants.sPreferenceLevelProhibited * lecture.getInstructorConstraints().size(); 461 } 462 } 463 if (distance > iDistanceMetric.minutes2meters(10)) 464 tooFarForStudents += lecture.classLimit(assignment); 465 } 466 deltaStudentConflicts += lecture.countStudentConflicts(assignment, assignedPlacement) - lecture.countInitialStudentConflicts(); 467 Set<Student> newStudentConflictsSet = lecture.conflictStudents(assignment, assignedPlacement); 468 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 469 for (Iterator<Student> e1 = newStudentConflictsSet.iterator(); e1.hasNext();) 470 if (!initialStudentConflicts.contains(e1.next())) 471 newStudentConflicts++; 472 deltaTimePreferences += assignedPlacement.getTimeLocation().getNormalizedPreference() - initialPlacement.getTimeLocation().getNormalizedPreference(); 473 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 474 for (Lecture lect : ic.variables()) { 475 if (lect.equals(lecture)) 476 continue; 477 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral 478 : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 479 int assignedPreference = (assignedPlacement == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignedPlacement)); 480 deltaInstructorDistancePreferences += assignedPreference - initialPreference; 481 } 482 } 483 } 484 if (perts != 0) 485 info.put("Perturbations: Different placement", String.valueOf(perts) + " (weighted " + sDoubleFormat.format(iDifferentPlacement * perts) + ")"); 486 if (affectedStudents != 0) 487 info.put("Perturbations: Number of affected students", String.valueOf(affectedStudents) + " (weighted " + sDoubleFormat.format(iAffectedStudentWeight * affectedStudents) + ")"); 488 if (affectedInstructors != 0) 489 info.put("Perturbations: Number of affected instructors", String.valueOf(affectedInstructors) + " (weighted " + sDoubleFormat.format(iAffectedInstructorWeight * affectedInstructors) + ")"); 490 if (affectedStudentsByTime != 0) 491 info.put("Perturbations: Number of affected students [time]", String.valueOf(affectedStudentsByTime) + 492 " (weighted " + sDoubleFormat.format(iAffectedStudentByTimeWeight * affectedStudentsByTime) + ")"); 493 if (affectedInstructorsByTime != 0) 494 info.put("Perturbations: Number of affected instructors [time]", String.valueOf(affectedInstructorsByTime) + 495 " (weighted " + sDoubleFormat.format(iAffectedInstructorByTimeWeight * affectedInstructorsByTime) + ")"); 496 if (affectedStudentsByRoom != 0) 497 info.put("Perturbations: Number of affected students [room]", String.valueOf(affectedStudentsByRoom) + 498 " (weighted " + sDoubleFormat.format(iAffectedStudentByRoomWeight * affectedStudentsByRoom) + ")"); 499 if (affectedInstructorsByRoom != 0) 500 info.put("Perturbations: Number of affected instructors [room]", String.valueOf(affectedInstructorsByRoom) + 501 " (weighted " + sDoubleFormat.format(iAffectedInstructorByRoomWeight * affectedInstructorsByRoom) + ")"); 502 if (affectedStudentsByBldg != 0) 503 info.put("Perturbations: Number of affected students [bldg]", String.valueOf(affectedStudentsByBldg) + 504 " (weighted " + sDoubleFormat.format(iAffectedStudentByBldgWeight * affectedStudentsByBldg) + ")"); 505 if (affectedInstructorsByBldg != 0) 506 info.put("Perturbations: Number of affected instructors [bldg]", String.valueOf(affectedInstructorsByBldg) + 507 " (weighted " + sDoubleFormat.format(iAffectedInstructorByBldgWeight * affectedInstructorsByBldg) + ")"); 508 if (differentRoom != 0) 509 info.put("Perturbations: Different room", String.valueOf(differentRoom) + " (weighted " + sDoubleFormat.format(iDifferentRoomWeight * differentRoom) + ")"); 510 if (differentBuilding != 0) 511 info.put("Perturbations: Different building", String.valueOf(differentBuilding) + " (weighted " + sDoubleFormat.format(iDifferentBuildingWeight * differentBuilding) + ")"); 512 if (differentTime != 0) 513 info.put("Perturbations: Different time", String.valueOf(differentTime) + " (weighted " + sDoubleFormat.format(iDifferentTimeWeight * differentTime) + ")"); 514 if (differentDay != 0) 515 info.put("Perturbations: Different day", String.valueOf(differentDay) + " (weighted " + sDoubleFormat.format(iDifferentDayWeight * differentDay) + ")"); 516 if (differentHour != 0) 517 info.put("Perturbations: Different hour", String.valueOf(differentHour) + " (weighted " + sDoubleFormat.format(iDifferentHourWeight * differentHour) + ")"); 518 if (tooFarForInstructors != 0) 519 info.put("Perturbations: New placement too far from initial [instructors]", String.valueOf(tooFarForInstructors) + 520 " (weighted " + sDoubleFormat.format(iTooFarForInstructorsWeight * tooFarForInstructors) + ")"); 521 if (tooFarForStudents != 0) 522 info.put("Perturbations: New placement too far from initial [students]", String.valueOf(tooFarForStudents) + 523 " (weighted " + sDoubleFormat.format(iTooFarForStudentsWeight * tooFarForStudents) + ")"); 524 if (deltaStudentConflicts != 0) 525 info.put("Perturbations: Delta student conflicts", String.valueOf(deltaStudentConflicts) + " (weighted " + sDoubleFormat.format(iDeltaStudentConflictsWeight * deltaStudentConflicts) + ")"); 526 if (newStudentConflicts != 0) 527 info.put("Perturbations: New student conflicts", String.valueOf(newStudentConflicts) + " (weighted " + sDoubleFormat.format(iNewStudentConflictsWeight * newStudentConflicts) + ")"); 528 if (deltaTimePreferences != 0) 529 info.put("Perturbations: Delta time preferences", String.valueOf(deltaTimePreferences) + " (weighted " + sDoubleFormat.format(iDeltaTimePreferenceWeight * deltaTimePreferences) + ")"); 530 if (deltaRoomPreferences != 0) 531 info.put("Perturbations: Delta room preferences", String.valueOf(deltaRoomPreferences) + " (weighted " + sDoubleFormat.format(iDeltaRoomPreferenceWeight * deltaRoomPreferences) + ")"); 532 if (deltaInstructorDistancePreferences != 0) 533 info.put("Perturbations: Delta instructor distance preferences", String.valueOf(deltaInstructorDistancePreferences) + 534 " (weighted " + sDoubleFormat.format(iDeltaInstructorDistancePreferenceWeight * deltaInstructorDistancePreferences) + ")"); 535 } 536 537 public Map<String, Double> getCompactInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, boolean includeZero, boolean weighted) { 538 Map<String, Double> info = new HashMap<String, Double>(); 539 if (!iMPP) 540 return info; 541 int perts = 0; 542 long affectedStudents = 0; 543 int affectedInstructors = 0; 544 long affectedStudentsByTime = 0; 545 int affectedInstructorsByTime = 0; 546 long affectedStudentsByRoom = 0; 547 int affectedInstructorsByRoom = 0; 548 long affectedStudentsByBldg = 0; 549 int affectedInstructorsByBldg = 0; 550 int differentRoom = 0; 551 int differentBuilding = 0; 552 int differentTime = 0; 553 int differentDay = 0; 554 int differentHour = 0; 555 int tooFarForInstructors = 0; 556 int tooFarForStudents = 0; 557 int deltaStudentConflicts = 0; 558 int newStudentConflicts = 0; 559 double deltaTimePreferences = 0; 560 int deltaRoomPreferences = 0; 561 int deltaInstructorDistancePreferences = 0; 562 for (Lecture lecture : model.perturbVariables(assignment)) { 563 if (assignment.getValue(lecture) == null || lecture.getInitialAssignment() == null || assignment.getValue(lecture).equals(lecture.getInitialAssignment())) 564 continue; 565 perts++; 566 Placement assignedPlacement = assignment.getValue(lecture); 567 Placement initialPlacement = lecture.getInitialAssignment(); 568 affectedStudents += lecture.classLimit(assignment); 569 affectedInstructors += lecture.getInstructorConstraints().size(); 570 571 int nrDiff = initialPlacement.nrDifferentRooms(assignedPlacement); 572 differentRoom += nrDiff; 573 affectedInstructorsByRoom += nrDiff * lecture.getInstructorConstraints().size(); 574 affectedStudentsByRoom += nrDiff * lecture.classLimit(assignment); 575 576 nrDiff = initialPlacement.nrDifferentBuildings(initialPlacement); 577 differentBuilding += nrDiff; 578 affectedInstructorsByBldg += nrDiff * lecture.getInstructorConstraints().size(); 579 affectedStudentsByBldg += nrDiff * lecture.classLimit(assignment); 580 581 deltaRoomPreferences += assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference(); 582 583 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 584 differentTime++; 585 affectedInstructorsByTime += lecture.getInstructorConstraints().size(); 586 affectedStudentsByTime += lecture.classLimit(assignment); 587 } 588 if (initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation().getDayCode()) 589 differentDay++; 590 if (initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation().getStartSlot()) 591 differentHour++; 592 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 593 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 594 if (!lecture.getInstructorConstraints().isEmpty()) { 595 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 596 tooFarForInstructors += Constants.sPreferenceLevelDiscouraged; 597 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 598 tooFarForInstructors += Constants.sPreferenceLevelStronglyDiscouraged; 599 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 600 tooFarForInstructors += Constants.sPreferenceLevelProhibited; 601 } 602 } 603 if (distance > iDistanceMetric.minutes2meters(10)) 604 tooFarForStudents += lecture.classLimit(assignment); 605 } 606 deltaStudentConflicts += lecture.countStudentConflicts(assignment, assignedPlacement) - lecture.countInitialStudentConflicts(); 607 Set<Student> newStudentConflictsSet = lecture.conflictStudents(assignment, assignedPlacement); 608 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 609 for (Iterator<Student> e1 = newStudentConflictsSet.iterator(); e1.hasNext();) 610 if (!initialStudentConflicts.contains(e1.next())) 611 newStudentConflicts++; 612 deltaTimePreferences += assignedPlacement.getTimeLocation().getNormalizedPreference() - initialPlacement.getTimeLocation().getNormalizedPreference(); 613 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 614 if (ic != null) 615 for (Lecture lect : ic.variables()) { 616 if (lect.equals(lecture)) 617 continue; 618 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral 619 : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 620 int assignedPreference = (assignedPlacement == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignedPlacement)); 621 deltaInstructorDistancePreferences += assignedPreference - initialPreference; 622 } 623 } 624 } 625 if (includeZero || iDifferentPlacement != 0.0) 626 info.put("Different placement", Double.valueOf(weighted ? iDifferentPlacement * perts : perts)); 627 if (includeZero || iAffectedStudentWeight != 0.0) 628 info.put("Affected students", Double.valueOf(weighted ? iAffectedStudentWeight * affectedStudents : affectedStudents)); 629 if (includeZero || iAffectedInstructorWeight != 0.0) 630 info.put("Affected instructors", Double.valueOf(weighted ? iAffectedInstructorWeight * affectedInstructors : affectedInstructors)); 631 if (includeZero || iAffectedStudentByTimeWeight != 0.0) 632 info.put("Affected students [time]", Double.valueOf(weighted ? iAffectedStudentByTimeWeight * affectedStudentsByTime : affectedStudentsByTime)); 633 if (includeZero || iAffectedInstructorByTimeWeight != 0.0) 634 info.put("Affected instructors [time]", Double.valueOf(weighted ? iAffectedInstructorByTimeWeight * affectedInstructorsByTime : affectedInstructorsByTime)); 635 if (includeZero || iAffectedStudentByRoomWeight != 0.0) 636 info.put("Affected students [room]", Double.valueOf(weighted ? iAffectedStudentByRoomWeight * affectedStudentsByRoom : affectedStudentsByRoom)); 637 if (includeZero || iAffectedInstructorByRoomWeight != 0.0) 638 info.put("Affected instructors [room]", Double.valueOf(weighted ? iAffectedInstructorByRoomWeight * affectedInstructorsByRoom : affectedInstructorsByRoom)); 639 if (includeZero || iAffectedStudentByBldgWeight != 0.0) 640 info.put("Affected students [bldg]", Double.valueOf(weighted ? iAffectedStudentByBldgWeight * affectedStudentsByBldg : affectedStudentsByBldg)); 641 if (includeZero || iAffectedInstructorByBldgWeight != 0.0) 642 info.put("Affected instructors [bldg]", Double.valueOf(weighted ? iAffectedInstructorByBldgWeight * affectedInstructorsByBldg : affectedInstructorsByBldg)); 643 if (includeZero || iDifferentRoomWeight != 0.0) 644 info.put("Different room", Double.valueOf(weighted ? iDifferentRoomWeight * differentRoom : differentRoom)); 645 if (includeZero || iDifferentBuildingWeight != 0.0) 646 info.put("Different building", Double.valueOf(weighted ? iDifferentBuildingWeight * differentBuilding : differentBuilding)); 647 if (includeZero || iDifferentTimeWeight != 0.0) 648 info.put("Different time", Double.valueOf(weighted ? iDifferentTimeWeight * differentTime : differentTime)); 649 if (includeZero || iDifferentDayWeight != 0.0) 650 info.put("Different day", Double.valueOf(weighted ? iDifferentDayWeight * differentDay : differentDay)); 651 if (includeZero || iDifferentHourWeight != 0.0) 652 info.put("Different hour", Double.valueOf(weighted ? iDifferentHourWeight * differentHour : differentHour)); 653 if (includeZero || iTooFarForInstructorsWeight != 0.0) 654 info.put("New placement too far for initial [instructors]", Double.valueOf(weighted ? iTooFarForInstructorsWeight * tooFarForInstructors : tooFarForInstructors)); 655 if (includeZero || iTooFarForStudentsWeight != 0.0) 656 info.put("New placement too far for initial [students]", Double.valueOf(weighted ? iTooFarForStudentsWeight * tooFarForStudents : tooFarForStudents)); 657 if (includeZero || iDeltaStudentConflictsWeight != 0.0) 658 info.put("Delta student conflicts", Double.valueOf(weighted ? iDeltaStudentConflictsWeight * deltaStudentConflicts : deltaStudentConflicts)); 659 if (includeZero || iNewStudentConflictsWeight != 0.0) 660 info.put("New student conflicts", Double.valueOf(weighted ? iNewStudentConflictsWeight * newStudentConflicts : newStudentConflicts)); 661 if (includeZero || iDeltaTimePreferenceWeight != 0.0) 662 info.put("Delta time preferences", Double.valueOf(weighted ? iDeltaTimePreferenceWeight * deltaTimePreferences : deltaTimePreferences)); 663 if (includeZero || iDeltaRoomPreferenceWeight != 0.0) 664 info.put("Delta room preferences", Double.valueOf(weighted ? iDeltaRoomPreferenceWeight * deltaRoomPreferences : deltaRoomPreferences)); 665 if (includeZero || iDeltaInstructorDistancePreferenceWeight != 0.0) 666 info.put("Delta instructor distance preferences", Double.valueOf(weighted ? iDeltaInstructorDistancePreferenceWeight * deltaInstructorDistancePreferences : deltaInstructorDistancePreferences)); 667 return info; 668 } 669 670 public Map<String, Double> getCompactInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, Placement assignedPlacement, boolean includeZero, 671 boolean weighted) { 672 Map<String, Double> info = new HashMap<String, Double>(); 673 if (!iMPP) 674 return info; 675 Lecture lecture = assignedPlacement.variable(); 676 Placement initialPlacement = lecture.getInitialAssignment(); 677 if (initialPlacement == null || initialPlacement.equals(assignedPlacement)) 678 return info; 679 int perts = 1; 680 long affectedStudents = lecture.classLimit(assignment); 681 int affectedInstructors = lecture.getInstructorConstraints().size(); 682 long affectedStudentsByTime = (initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation()) ? 0 : lecture.classLimit(assignment)); 683 int affectedInstructorsByTime = (initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation()) ? 0 : lecture.getInstructorConstraints().size()); 684 685 int differentRoom = initialPlacement.nrDifferentRooms(assignedPlacement); 686 int affectedInstructorsByRoom = differentRoom * lecture.getInstructorConstraints().size(); 687 long affectedStudentsByRoom = differentRoom * lecture.classLimit(assignment); 688 689 int differentBuilding = initialPlacement.nrDifferentBuildings(initialPlacement); 690 int affectedInstructorsByBldg = differentBuilding * lecture.getInstructorConstraints().size(); 691 long affectedStudentsByBldg = differentBuilding * lecture.classLimit(assignment); 692 693 int deltaRoomPreferences = assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference(); 694 695 int differentTime = (initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation()) ? 0 : 1); 696 int differentDay = (initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation().getDayCode() ? 1 : 0); 697 int differentHour = (initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation().getStartSlot() ? 1 : 0); 698 int tooFarForInstructors = 0; 699 int tooFarForStudents = 0; 700 int deltaStudentConflicts = lecture.countStudentConflicts(assignment, assignedPlacement) - lecture.countInitialStudentConflicts(); 701 int newStudentConflicts = 0; 702 double deltaTimePreferences = (assignedPlacement.getTimeLocation().getNormalizedPreference() - 703 initialPlacement.getTimeLocation().getNormalizedPreference()); 704 int deltaInstructorDistancePreferences = 0; 705 706 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 707 if (!lecture.getInstructorConstraints().isEmpty()) { 708 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 709 tooFarForInstructors += lecture.getInstructorConstraints().size(); 710 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 711 tooFarForInstructors += 2 * lecture.getInstructorConstraints().size(); 712 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 713 tooFarForInstructors += 10 * lecture.getInstructorConstraints().size(); 714 } 715 } 716 if (distance > iDistanceMetric.minutes2meters(10)) 717 tooFarForStudents = lecture.classLimit(assignment); 718 719 Set<Student> newStudentConflictsVect = lecture.conflictStudents(assignment, assignedPlacement); 720 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 721 for (Iterator<Student> e = newStudentConflictsVect.iterator(); e.hasNext();) 722 if (!initialStudentConflicts.contains(e.next())) 723 newStudentConflicts++; 724 725 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 726 for (Lecture lect : ic.variables()) { 727 if (lect.equals(lecture)) 728 continue; 729 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 730 int assignedPreference = (assignment.getValue(lect) == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignment.getValue(lect))); 731 deltaInstructorDistancePreferences += (assignedPreference - initialPreference); 732 } 733 } 734 735 if (includeZero || iDifferentPlacement != 0.0) 736 info.put("Different placement", Double.valueOf(weighted ? iDifferentPlacement * perts : perts)); 737 if (includeZero || iAffectedStudentWeight != 0.0) 738 info.put("Affected students", Double.valueOf(weighted ? iAffectedStudentWeight * affectedStudents : affectedStudents)); 739 if (includeZero || iAffectedInstructorWeight != 0.0) 740 info.put("Affected instructors", Double.valueOf(weighted ? iAffectedInstructorWeight * affectedInstructors : affectedInstructors)); 741 if (includeZero || iAffectedStudentByTimeWeight != 0.0) 742 info.put("Affected students [time]", Double.valueOf(weighted ? iAffectedStudentByTimeWeight * affectedStudentsByTime : affectedStudentsByTime)); 743 if (includeZero || iAffectedInstructorByTimeWeight != 0.0) 744 info.put("Affected instructors [time]", Double.valueOf(weighted ? iAffectedInstructorByTimeWeight * affectedInstructorsByTime : affectedInstructorsByTime)); 745 if (includeZero || iAffectedStudentByRoomWeight != 0.0) 746 info.put("Affected students [room]", Double.valueOf(weighted ? iAffectedStudentByRoomWeight * affectedStudentsByRoom : affectedStudentsByRoom)); 747 if (includeZero || iAffectedInstructorByRoomWeight != 0.0) 748 info.put("Affected instructors [room]", Double.valueOf(weighted ? iAffectedInstructorByRoomWeight * affectedInstructorsByRoom : affectedInstructorsByRoom)); 749 if (includeZero || iAffectedStudentByBldgWeight != 0.0) 750 info.put("Affected students [bldg]", Double.valueOf(weighted ? iAffectedStudentByBldgWeight * affectedStudentsByBldg : affectedStudentsByBldg)); 751 if (includeZero || iAffectedInstructorByBldgWeight != 0.0) 752 info.put("Affected instructors [bldg]", Double.valueOf(weighted ? iAffectedInstructorByBldgWeight * affectedInstructorsByBldg : affectedInstructorsByBldg)); 753 if (includeZero || iDifferentRoomWeight != 0.0) 754 info.put("Different room", Double.valueOf(weighted ? iDifferentRoomWeight * differentRoom : differentRoom)); 755 if (includeZero || iDifferentBuildingWeight != 0.0) 756 info.put("Different building", Double.valueOf(weighted ? iDifferentBuildingWeight * differentBuilding : differentBuilding)); 757 if (includeZero || iDifferentTimeWeight != 0.0) 758 info.put("Different time", Double.valueOf(weighted ? iDifferentTimeWeight * differentTime : differentTime)); 759 if (includeZero || iDifferentDayWeight != 0.0) 760 info.put("Different day", Double.valueOf(weighted ? iDifferentDayWeight * differentDay : differentDay)); 761 if (includeZero || iDifferentHourWeight != 0.0) 762 info.put("Different hour", Double.valueOf(weighted ? iDifferentHourWeight * differentHour : differentHour)); 763 if (includeZero || iTooFarForInstructorsWeight != 0.0) 764 info.put("New placement too far for initial [instructors]", Double.valueOf(weighted ? iTooFarForInstructorsWeight * tooFarForInstructors : tooFarForInstructors)); 765 if (includeZero || iTooFarForStudentsWeight != 0.0) 766 info.put("New placement too far for initial [students]", Double.valueOf(weighted ? iTooFarForStudentsWeight * tooFarForStudents : tooFarForStudents)); 767 if (includeZero || iDeltaStudentConflictsWeight != 0.0) 768 info.put("Delta student conflicts", Double.valueOf(weighted ? iDeltaStudentConflictsWeight * deltaStudentConflicts : deltaStudentConflicts)); 769 if (includeZero || iNewStudentConflictsWeight != 0.0) 770 info.put("New student conflicts", Double.valueOf(weighted ? iNewStudentConflictsWeight * newStudentConflicts : newStudentConflicts)); 771 if (includeZero || iDeltaTimePreferenceWeight != 0.0) 772 info.put("Delta time preferences", Double.valueOf(weighted ? iDeltaTimePreferenceWeight * deltaTimePreferences : deltaTimePreferences)); 773 if (includeZero || iDeltaRoomPreferenceWeight != 0.0) 774 info.put("Delta room preferences", Double.valueOf(weighted ? iDeltaRoomPreferenceWeight * deltaRoomPreferences : deltaRoomPreferences)); 775 if (includeZero || iDeltaInstructorDistancePreferenceWeight != 0.0) 776 info.put("Delta instructor distance preferences", Double.valueOf(weighted ? iDeltaInstructorDistancePreferenceWeight * deltaInstructorDistancePreferences : deltaInstructorDistancePreferences)); 777 return info; 778 } 779}