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