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' summary='Related Solver Parameters'> 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 * @version CourseTT 1.3 (University Course Timetabling)<br> 211 * Copyright (C) 2006 - 2014 Tomáš Müller<br> 212 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 213 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 214 * <br> 215 * This library is free software; you can redistribute it and/or modify 216 * it under the terms of the GNU Lesser General Public License as 217 * published by the Free Software Foundation; either version 3 of the 218 * License, or (at your option) any later version. <br> 219 * <br> 220 * This library is distributed in the hope that it will be useful, but 221 * WITHOUT ANY WARRANTY; without even the implied warranty of 222 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 223 * Lesser General Public License for more details. <br> 224 * <br> 225 * You should have received a copy of the GNU Lesser General Public 226 * License along with this library; if not see 227 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 228 */ 229 230public class UniversalPerturbationsCounter extends DefaultPerturbationsCounter<Lecture, Placement> { 231 private double iDifferentPlacement = 1.0; 232 private double iAffectedStudentWeight = 0.0; 233 private double iAffectedInstructorWeight = 0.0; 234 private double iAffectedStudentByTimeWeight = 0.0; 235 private double iAffectedInstructorByTimeWeight = 0.0; 236 private double iAffectedStudentByRoomWeight = 0.0; 237 private double iAffectedInstructorByRoomWeight = 0.0; 238 private double iAffectedStudentByBldgWeight = 0.0; 239 private double iAffectedInstructorByBldgWeight = 0.0; 240 private double iDifferentRoomWeight = 0.0; 241 private double iDifferentBuildingWeight = 0.0; 242 private double iDifferentTimeWeight = 0.0; 243 private double iDifferentDayWeight = 0.0; 244 private double iDifferentHourWeight = 0.0; 245 private double iNewStudentConflictsWeight = 0.0; 246 private double iDeltaStudentConflictsWeight = 0.0; 247 private double iTooFarForInstructorsWeight = 0.0; 248 private double iTooFarForStudentsWeight = 0.0; 249 private double iDeltaInstructorDistancePreferenceWeight = 0.0; 250 private double iDeltaRoomPreferenceWeight = 0.0; 251 private double iDeltaTimePreferenceWeight = 0.0; 252 private boolean iMPP = false; 253 private DistanceMetric iDistanceMetric = null; 254 255 public UniversalPerturbationsCounter(DataProperties properties) { 256 super(properties); 257 iMPP = properties.getPropertyBoolean("General.MPP", false); 258 iDifferentPlacement = properties.getPropertyDouble("Perturbations.DifferentPlacement", iDifferentPlacement); 259 iAffectedStudentWeight = properties.getPropertyDouble("Perturbations.AffectedStudentWeight", 260 iAffectedStudentWeight); 261 iAffectedInstructorWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorWeight", 262 iAffectedInstructorWeight); 263 iAffectedStudentByTimeWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByTimeWeight", 264 iAffectedStudentByTimeWeight); 265 iAffectedInstructorByTimeWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByTimeWeight", 266 iAffectedInstructorByTimeWeight); 267 iAffectedStudentByRoomWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByRoomWeight", 268 iAffectedStudentByRoomWeight); 269 iAffectedInstructorByRoomWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByRoomWeight", 270 iAffectedInstructorByRoomWeight); 271 iAffectedStudentByBldgWeight = properties.getPropertyDouble("Perturbations.AffectedStudentByBldgWeight", 272 iAffectedStudentByBldgWeight); 273 iAffectedInstructorByBldgWeight = properties.getPropertyDouble("Perturbations.AffectedInstructorByBldgWeight", 274 iAffectedInstructorByBldgWeight); 275 iDifferentRoomWeight = properties.getPropertyDouble("Perturbations.DifferentRoomWeight", iDifferentRoomWeight); 276 iDifferentBuildingWeight = properties.getPropertyDouble("Perturbations.DifferentBuildingWeight", 277 iDifferentBuildingWeight); 278 iDifferentTimeWeight = properties.getPropertyDouble("Perturbations.DifferentTimeWeight", iDifferentTimeWeight); 279 iDifferentDayWeight = properties.getPropertyDouble("Perturbations.DifferentDayWeight", iDifferentDayWeight); 280 iDifferentHourWeight = properties.getPropertyDouble("Perturbations.DifferentHourWeight", iDifferentHourWeight); 281 iDeltaStudentConflictsWeight = properties.getPropertyDouble("Perturbations.DeltaStudentConflictsWeight", 282 iDeltaStudentConflictsWeight); 283 iNewStudentConflictsWeight = properties.getPropertyDouble("Perturbations.NewStudentConflictsWeight", 284 iNewStudentConflictsWeight); 285 iTooFarForInstructorsWeight = properties.getPropertyDouble("Perturbations.TooFarForInstructorsWeight", 286 iTooFarForInstructorsWeight); 287 iTooFarForStudentsWeight = properties.getPropertyDouble("Perturbations.TooFarForStudentsWeight", 288 iTooFarForStudentsWeight); 289 iDeltaInstructorDistancePreferenceWeight = properties.getPropertyDouble( 290 "Perturbations.DeltaInstructorDistancePreferenceWeight", iDeltaInstructorDistancePreferenceWeight); 291 iDeltaRoomPreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaRoomPreferenceWeight", 292 iDeltaRoomPreferenceWeight); 293 iDeltaTimePreferenceWeight = properties.getPropertyDouble("Perturbations.DeltaTimePreferenceWeight", 294 iDeltaTimePreferenceWeight); 295 iDistanceMetric = new DistanceMetric(properties); 296 } 297 298 @Override 299 protected double getPenalty(Assignment<Lecture, Placement> assignment, Placement assignedPlacement, Placement initialPlacement) { 300 // assigned and initial value of the same lecture 301 // assigned might be null 302 Lecture lecture = initialPlacement.variable(); 303 double penalty = 0.0; 304 if (iDifferentPlacement != 0.0) 305 penalty += iDifferentPlacement; 306 if (iAffectedStudentWeight != 0.0) 307 penalty += iAffectedStudentWeight * lecture.classLimit(assignment); 308 if (iAffectedInstructorWeight != 0.0) 309 penalty += iAffectedInstructorWeight * lecture.getInstructorConstraints().size(); 310 if (assignedPlacement != null) { 311 if ((iDifferentRoomWeight != 0.0 || iAffectedInstructorByRoomWeight != 0.0 || iAffectedStudentByRoomWeight != 0.0)) { 312 int nrDiff = initialPlacement.nrDifferentRooms(assignedPlacement); 313 penalty += nrDiff * iDifferentRoomWeight; 314 penalty += nrDiff * iAffectedInstructorByRoomWeight * lecture.getInstructorConstraints().size(); 315 penalty += nrDiff * iAffectedStudentByRoomWeight * lecture.classLimit(assignment); 316 } 317 if ((iDifferentBuildingWeight != 0.0 || iAffectedInstructorByBldgWeight != 0.0 || iAffectedStudentByBldgWeight != 0.0)) { 318 int nrDiff = initialPlacement.nrDifferentBuildings(assignedPlacement); 319 penalty += nrDiff * iDifferentBuildingWeight; 320 penalty += nrDiff * iAffectedInstructorByBldgWeight * lecture.getInstructorConstraints().size(); 321 penalty += nrDiff * iAffectedStudentByBldgWeight * lecture.classLimit(assignment); 322 } 323 if ((iDifferentTimeWeight != 0.0 || iAffectedInstructorByTimeWeight != 0.0 || iAffectedStudentByTimeWeight != 0.0) 324 && !initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 325 penalty += iDifferentTimeWeight; 326 penalty += iAffectedInstructorByTimeWeight * lecture.getInstructorConstraints().size(); 327 penalty += iAffectedStudentByTimeWeight * lecture.classLimit(assignment); 328 } 329 if (iDifferentDayWeight != 0.0 330 && initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation() 331 .getDayCode()) 332 penalty += iDifferentDayWeight; 333 if (iDifferentHourWeight != 0.0 334 && initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation() 335 .getStartSlot()) 336 penalty += iDifferentHourWeight; 337 if ((iTooFarForInstructorsWeight != 0.0 || iTooFarForStudentsWeight != 0.0) 338 && !initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 339 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 340 if (!lecture.getInstructorConstraints().isEmpty() && iTooFarForInstructorsWeight != 0.0) { 341 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 342 penalty += Constants.sPreferenceLevelDiscouraged * iTooFarForInstructorsWeight 343 * lecture.getInstructorConstraints().size(); 344 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 345 penalty += Constants.sPreferenceLevelStronglyDiscouraged * iTooFarForInstructorsWeight 346 * lecture.getInstructorConstraints().size(); 347 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 348 penalty += Constants.sPreferenceLevelProhibited * iTooFarForInstructorsWeight 349 * lecture.getInstructorConstraints().size(); 350 } 351 } 352 if (iTooFarForStudentsWeight != 0.0 353 && distance > iDistanceMetric.minutes2meters(10)) 354 penalty += iTooFarForStudentsWeight * lecture.classLimit(assignment); 355 } 356 if (iDeltaStudentConflictsWeight != 0.0) { 357 int newStudentConflicts = lecture.countStudentConflicts(assignment, assignedPlacement); 358 int oldStudentConflicts = lecture.countInitialStudentConflicts(); 359 penalty += iDeltaStudentConflictsWeight * (newStudentConflicts - oldStudentConflicts); 360 } 361 if (iNewStudentConflictsWeight != 0.0) { 362 Set<Student> newStudentConflicts = lecture.conflictStudents(assignment, assignedPlacement); 363 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 364 for (Iterator<Student> i = newStudentConflicts.iterator(); i.hasNext();) 365 if (!initialStudentConflicts.contains(i.next())) 366 penalty += iNewStudentConflictsWeight; 367 } 368 if (iDeltaTimePreferenceWeight != 0.0) { 369 penalty += iDeltaTimePreferenceWeight * (assignedPlacement.getTimeLocation().getNormalizedPreference() - initialPlacement.getTimeLocation().getNormalizedPreference()); 370 } 371 if (iDeltaRoomPreferenceWeight != 0.0) { 372 penalty += iDeltaRoomPreferenceWeight * (assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference()); 373 } 374 if (iDeltaInstructorDistancePreferenceWeight != 0.0) { 375 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 376 for (Lecture lect : ic.variables()) { 377 if (lect.equals(lecture)) 378 continue; 379 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 380 int assignedPreference = (assignment.getValue(lect) == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignment.getValue(lect))); 381 penalty += iDeltaInstructorDistancePreferenceWeight * (assignedPreference - initialPreference); 382 } 383 } 384 } 385 } 386 return penalty; 387 } 388 389 public void getInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, Map<String, String> info) { 390 getInfo(assignment, model, info, null); 391 } 392 393 public void getInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, Map<String, String> info, List<Lecture> variables) { 394 if (variables == null) 395 super.getInfo(assignment, model, info); 396 else 397 super.getInfo(assignment, model, info, variables); 398 if (!iMPP) 399 return; 400 int perts = 0; 401 long affectedStudents = 0; 402 int affectedInstructors = 0; 403 long affectedStudentsByTime = 0; 404 int affectedInstructorsByTime = 0; 405 long affectedStudentsByRoom = 0; 406 int affectedInstructorsByRoom = 0; 407 long affectedStudentsByBldg = 0; 408 int affectedInstructorsByBldg = 0; 409 int differentRoom = 0; 410 int differentBuilding = 0; 411 int differentTime = 0; 412 int differentDay = 0; 413 int differentHour = 0; 414 int tooFarForInstructors = 0; 415 int tooFarForStudents = 0; 416 int deltaStudentConflicts = 0; 417 int newStudentConflicts = 0; 418 double deltaTimePreferences = 0; 419 int deltaRoomPreferences = 0; 420 int deltaInstructorDistancePreferences = 0; 421 for (Lecture lecture : (variables == null ? model.perturbVariables(assignment) : model.perturbVariables(assignment, variables))) { 422 if (assignment.getValue(lecture) == null || lecture.getInitialAssignment() == null || assignment.getValue(lecture).equals(lecture.getInitialAssignment())) 423 continue; 424 perts++; 425 Placement assignedPlacement = assignment.getValue(lecture); 426 Placement initialPlacement = lecture.getInitialAssignment(); 427 affectedStudents += lecture.classLimit(assignment); 428 affectedInstructors += lecture.getInstructorConstraints().size(); 429 430 int nrDiff = initialPlacement.nrDifferentRooms(assignedPlacement); 431 differentRoom += nrDiff; 432 affectedInstructorsByRoom += nrDiff * lecture.getInstructorConstraints().size(); 433 affectedStudentsByRoom += nrDiff * lecture.classLimit(assignment); 434 435 nrDiff = initialPlacement.nrDifferentBuildings(assignedPlacement); 436 differentBuilding += nrDiff; 437 affectedInstructorsByBldg += nrDiff * lecture.getInstructorConstraints().size(); 438 affectedStudentsByBldg += nrDiff * lecture.classLimit(assignment); 439 440 deltaRoomPreferences += assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference(); 441 442 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 443 differentTime++; 444 affectedInstructorsByTime += lecture.getInstructorConstraints().size(); 445 affectedStudentsByTime += lecture.classLimit(assignment); 446 } 447 if (initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation().getDayCode()) 448 differentDay++; 449 if (initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation().getStartSlot()) 450 differentHour++; 451 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 452 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 453 if (!lecture.getInstructorConstraints().isEmpty()) { 454 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 455 tooFarForInstructors += Constants.sPreferenceLevelDiscouraged * lecture.getInstructorConstraints().size(); 456 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 457 tooFarForInstructors += Constants.sPreferenceLevelStronglyDiscouraged * lecture.getInstructorConstraints().size(); 458 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 459 tooFarForInstructors += Constants.sPreferenceLevelProhibited * lecture.getInstructorConstraints().size(); 460 } 461 } 462 if (distance > iDistanceMetric.minutes2meters(10)) 463 tooFarForStudents += lecture.classLimit(assignment); 464 } 465 deltaStudentConflicts += lecture.countStudentConflicts(assignment, assignedPlacement) - lecture.countInitialStudentConflicts(); 466 Set<Student> newStudentConflictsSet = lecture.conflictStudents(assignment, assignedPlacement); 467 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 468 for (Iterator<Student> e1 = newStudentConflictsSet.iterator(); e1.hasNext();) 469 if (!initialStudentConflicts.contains(e1.next())) 470 newStudentConflicts++; 471 deltaTimePreferences += assignedPlacement.getTimeLocation().getNormalizedPreference() - initialPlacement.getTimeLocation().getNormalizedPreference(); 472 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 473 for (Lecture lect : ic.variables()) { 474 if (lect.equals(lecture)) 475 continue; 476 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral 477 : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 478 int assignedPreference = (assignedPlacement == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignedPlacement)); 479 deltaInstructorDistancePreferences += assignedPreference - initialPreference; 480 } 481 } 482 } 483 if (perts != 0) 484 info.put("Perturbations: Different placement", String.valueOf(perts) + " (weighted " + sDoubleFormat.format(iDifferentPlacement * perts) + ")"); 485 if (affectedStudents != 0) 486 info.put("Perturbations: Number of affected students", String.valueOf(affectedStudents) + " (weighted " + sDoubleFormat.format(iAffectedStudentWeight * affectedStudents) + ")"); 487 if (affectedInstructors != 0) 488 info.put("Perturbations: Number of affected instructors", String.valueOf(affectedInstructors) + " (weighted " + sDoubleFormat.format(iAffectedInstructorWeight * affectedInstructors) + ")"); 489 if (affectedStudentsByTime != 0) 490 info.put("Perturbations: Number of affected students [time]", String.valueOf(affectedStudentsByTime) + 491 " (weighted " + sDoubleFormat.format(iAffectedStudentByTimeWeight * affectedStudentsByTime) + ")"); 492 if (affectedInstructorsByTime != 0) 493 info.put("Perturbations: Number of affected instructors [time]", String.valueOf(affectedInstructorsByTime) + 494 " (weighted " + sDoubleFormat.format(iAffectedInstructorByTimeWeight * affectedInstructorsByTime) + ")"); 495 if (affectedStudentsByRoom != 0) 496 info.put("Perturbations: Number of affected students [room]", String.valueOf(affectedStudentsByRoom) + 497 " (weighted " + sDoubleFormat.format(iAffectedStudentByRoomWeight * affectedStudentsByRoom) + ")"); 498 if (affectedInstructorsByRoom != 0) 499 info.put("Perturbations: Number of affected instructors [room]", String.valueOf(affectedInstructorsByRoom) + 500 " (weighted " + sDoubleFormat.format(iAffectedInstructorByRoomWeight * affectedInstructorsByRoom) + ")"); 501 if (affectedStudentsByBldg != 0) 502 info.put("Perturbations: Number of affected students [bldg]", String.valueOf(affectedStudentsByBldg) + 503 " (weighted " + sDoubleFormat.format(iAffectedStudentByBldgWeight * affectedStudentsByBldg) + ")"); 504 if (affectedInstructorsByBldg != 0) 505 info.put("Perturbations: Number of affected instructors [bldg]", String.valueOf(affectedInstructorsByBldg) + 506 " (weighted " + sDoubleFormat.format(iAffectedInstructorByBldgWeight * affectedInstructorsByBldg) + ")"); 507 if (differentRoom != 0) 508 info.put("Perturbations: Different room", String.valueOf(differentRoom) + " (weighted " + sDoubleFormat.format(iDifferentRoomWeight * differentRoom) + ")"); 509 if (differentBuilding != 0) 510 info.put("Perturbations: Different building", String.valueOf(differentBuilding) + " (weighted " + sDoubleFormat.format(iDifferentBuildingWeight * differentBuilding) + ")"); 511 if (differentTime != 0) 512 info.put("Perturbations: Different time", String.valueOf(differentTime) + " (weighted " + sDoubleFormat.format(iDifferentTimeWeight * differentTime) + ")"); 513 if (differentDay != 0) 514 info.put("Perturbations: Different day", String.valueOf(differentDay) + " (weighted " + sDoubleFormat.format(iDifferentDayWeight * differentDay) + ")"); 515 if (differentHour != 0) 516 info.put("Perturbations: Different hour", String.valueOf(differentHour) + " (weighted " + sDoubleFormat.format(iDifferentHourWeight * differentHour) + ")"); 517 if (tooFarForInstructors != 0) 518 info.put("Perturbations: New placement too far from initial [instructors]", String.valueOf(tooFarForInstructors) + 519 " (weighted " + sDoubleFormat.format(iTooFarForInstructorsWeight * tooFarForInstructors) + ")"); 520 if (tooFarForStudents != 0) 521 info.put("Perturbations: New placement too far from initial [students]", String.valueOf(tooFarForStudents) + 522 " (weighted " + sDoubleFormat.format(iTooFarForStudentsWeight * tooFarForStudents) + ")"); 523 if (deltaStudentConflicts != 0) 524 info.put("Perturbations: Delta student conflicts", String.valueOf(deltaStudentConflicts) + " (weighted " + sDoubleFormat.format(iDeltaStudentConflictsWeight * deltaStudentConflicts) + ")"); 525 if (newStudentConflicts != 0) 526 info.put("Perturbations: New student conflicts", String.valueOf(newStudentConflicts) + " (weighted " + sDoubleFormat.format(iNewStudentConflictsWeight * newStudentConflicts) + ")"); 527 if (deltaTimePreferences != 0) 528 info.put("Perturbations: Delta time preferences", String.valueOf(deltaTimePreferences) + " (weighted " + sDoubleFormat.format(iDeltaTimePreferenceWeight * deltaTimePreferences) + ")"); 529 if (deltaRoomPreferences != 0) 530 info.put("Perturbations: Delta room preferences", String.valueOf(deltaRoomPreferences) + " (weighted " + sDoubleFormat.format(iDeltaRoomPreferenceWeight * deltaRoomPreferences) + ")"); 531 if (deltaInstructorDistancePreferences != 0) 532 info.put("Perturbations: Delta instructor distance preferences", String.valueOf(deltaInstructorDistancePreferences) + 533 " (weighted " + sDoubleFormat.format(iDeltaInstructorDistancePreferenceWeight * deltaInstructorDistancePreferences) + ")"); 534 } 535 536 public Map<String, Double> getCompactInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, boolean includeZero, boolean weighted) { 537 Map<String, Double> info = new HashMap<String, Double>(); 538 if (!iMPP) 539 return info; 540 int perts = 0; 541 long affectedStudents = 0; 542 int affectedInstructors = 0; 543 long affectedStudentsByTime = 0; 544 int affectedInstructorsByTime = 0; 545 long affectedStudentsByRoom = 0; 546 int affectedInstructorsByRoom = 0; 547 long affectedStudentsByBldg = 0; 548 int affectedInstructorsByBldg = 0; 549 int differentRoom = 0; 550 int differentBuilding = 0; 551 int differentTime = 0; 552 int differentDay = 0; 553 int differentHour = 0; 554 int tooFarForInstructors = 0; 555 int tooFarForStudents = 0; 556 int deltaStudentConflicts = 0; 557 int newStudentConflicts = 0; 558 double deltaTimePreferences = 0; 559 int deltaRoomPreferences = 0; 560 int deltaInstructorDistancePreferences = 0; 561 for (Lecture lecture : model.perturbVariables(assignment)) { 562 if (assignment.getValue(lecture) == null || lecture.getInitialAssignment() == null || assignment.getValue(lecture).equals(lecture.getInitialAssignment())) 563 continue; 564 perts++; 565 Placement assignedPlacement = assignment.getValue(lecture); 566 Placement initialPlacement = lecture.getInitialAssignment(); 567 affectedStudents += lecture.classLimit(assignment); 568 affectedInstructors += lecture.getInstructorConstraints().size(); 569 570 int nrDiff = initialPlacement.nrDifferentRooms(assignedPlacement); 571 differentRoom += nrDiff; 572 affectedInstructorsByRoom += nrDiff * lecture.getInstructorConstraints().size(); 573 affectedStudentsByRoom += nrDiff * lecture.classLimit(assignment); 574 575 nrDiff = initialPlacement.nrDifferentBuildings(initialPlacement); 576 differentBuilding += nrDiff; 577 affectedInstructorsByBldg += nrDiff * lecture.getInstructorConstraints().size(); 578 affectedStudentsByBldg += nrDiff * lecture.classLimit(assignment); 579 580 deltaRoomPreferences += assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference(); 581 582 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 583 differentTime++; 584 affectedInstructorsByTime += lecture.getInstructorConstraints().size(); 585 affectedStudentsByTime += lecture.classLimit(assignment); 586 } 587 if (initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation().getDayCode()) 588 differentDay++; 589 if (initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation().getStartSlot()) 590 differentHour++; 591 if (!initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation())) { 592 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 593 if (!lecture.getInstructorConstraints().isEmpty()) { 594 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 595 tooFarForInstructors += Constants.sPreferenceLevelDiscouraged; 596 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 597 tooFarForInstructors += Constants.sPreferenceLevelStronglyDiscouraged; 598 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 599 tooFarForInstructors += Constants.sPreferenceLevelProhibited; 600 } 601 } 602 if (distance > iDistanceMetric.minutes2meters(10)) 603 tooFarForStudents += lecture.classLimit(assignment); 604 } 605 deltaStudentConflicts += lecture.countStudentConflicts(assignment, assignedPlacement) - lecture.countInitialStudentConflicts(); 606 Set<Student> newStudentConflictsSet = lecture.conflictStudents(assignment, assignedPlacement); 607 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 608 for (Iterator<Student> e1 = newStudentConflictsSet.iterator(); e1.hasNext();) 609 if (!initialStudentConflicts.contains(e1.next())) 610 newStudentConflicts++; 611 deltaTimePreferences += assignedPlacement.getTimeLocation().getNormalizedPreference() - initialPlacement.getTimeLocation().getNormalizedPreference(); 612 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 613 if (ic != null) 614 for (Lecture lect : ic.variables()) { 615 if (lect.equals(lecture)) 616 continue; 617 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral 618 : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 619 int assignedPreference = (assignedPlacement == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignedPlacement)); 620 deltaInstructorDistancePreferences += assignedPreference - initialPreference; 621 } 622 } 623 } 624 if (includeZero || iDifferentPlacement != 0.0) 625 info.put("Different placement", new Double(weighted ? iDifferentPlacement * perts : perts)); 626 if (includeZero || iAffectedStudentWeight != 0.0) 627 info.put("Affected students", new Double(weighted ? iAffectedStudentWeight * affectedStudents : affectedStudents)); 628 if (includeZero || iAffectedInstructorWeight != 0.0) 629 info.put("Affected instructors", new Double(weighted ? iAffectedInstructorWeight * affectedInstructors : affectedInstructors)); 630 if (includeZero || iAffectedStudentByTimeWeight != 0.0) 631 info.put("Affected students [time]", new Double(weighted ? iAffectedStudentByTimeWeight * affectedStudentsByTime : affectedStudentsByTime)); 632 if (includeZero || iAffectedInstructorByTimeWeight != 0.0) 633 info.put("Affected instructors [time]", new Double(weighted ? iAffectedInstructorByTimeWeight * affectedInstructorsByTime : affectedInstructorsByTime)); 634 if (includeZero || iAffectedStudentByRoomWeight != 0.0) 635 info.put("Affected students [room]", new Double(weighted ? iAffectedStudentByRoomWeight * affectedStudentsByRoom : affectedStudentsByRoom)); 636 if (includeZero || iAffectedInstructorByRoomWeight != 0.0) 637 info.put("Affected instructors [room]", new Double(weighted ? iAffectedInstructorByRoomWeight * affectedInstructorsByRoom : affectedInstructorsByRoom)); 638 if (includeZero || iAffectedStudentByBldgWeight != 0.0) 639 info.put("Affected students [bldg]", new Double(weighted ? iAffectedStudentByBldgWeight * affectedStudentsByBldg : affectedStudentsByBldg)); 640 if (includeZero || iAffectedInstructorByBldgWeight != 0.0) 641 info.put("Affected instructors [bldg]", new Double(weighted ? iAffectedInstructorByBldgWeight * affectedInstructorsByBldg : affectedInstructorsByBldg)); 642 if (includeZero || iDifferentRoomWeight != 0.0) 643 info.put("Different room", new Double(weighted ? iDifferentRoomWeight * differentRoom : differentRoom)); 644 if (includeZero || iDifferentBuildingWeight != 0.0) 645 info.put("Different building", new Double(weighted ? iDifferentBuildingWeight * differentBuilding : differentBuilding)); 646 if (includeZero || iDifferentTimeWeight != 0.0) 647 info.put("Different time", new Double(weighted ? iDifferentTimeWeight * differentTime : differentTime)); 648 if (includeZero || iDifferentDayWeight != 0.0) 649 info.put("Different day", new Double(weighted ? iDifferentDayWeight * differentDay : differentDay)); 650 if (includeZero || iDifferentHourWeight != 0.0) 651 info.put("Different hour", new Double(weighted ? iDifferentHourWeight * differentHour : differentHour)); 652 if (includeZero || iTooFarForInstructorsWeight != 0.0) 653 info.put("New placement too far for initial [instructors]", new Double(weighted ? iTooFarForInstructorsWeight * tooFarForInstructors : tooFarForInstructors)); 654 if (includeZero || iTooFarForStudentsWeight != 0.0) 655 info.put("New placement too far for initial [students]", new Double(weighted ? iTooFarForStudentsWeight * tooFarForStudents : tooFarForStudents)); 656 if (includeZero || iDeltaStudentConflictsWeight != 0.0) 657 info.put("Delta student conflicts", new Double(weighted ? iDeltaStudentConflictsWeight * deltaStudentConflicts : deltaStudentConflicts)); 658 if (includeZero || iNewStudentConflictsWeight != 0.0) 659 info.put("New student conflicts", new Double(weighted ? iNewStudentConflictsWeight * newStudentConflicts : newStudentConflicts)); 660 if (includeZero || iDeltaTimePreferenceWeight != 0.0) 661 info.put("Delta time preferences", new Double(weighted ? iDeltaTimePreferenceWeight * deltaTimePreferences : deltaTimePreferences)); 662 if (includeZero || iDeltaRoomPreferenceWeight != 0.0) 663 info.put("Delta room preferences", new Double(weighted ? iDeltaRoomPreferenceWeight * deltaRoomPreferences : deltaRoomPreferences)); 664 if (includeZero || iDeltaInstructorDistancePreferenceWeight != 0.0) 665 info.put("Delta instructor distance preferences", new Double(weighted ? iDeltaInstructorDistancePreferenceWeight * deltaInstructorDistancePreferences : deltaInstructorDistancePreferences)); 666 return info; 667 } 668 669 public Map<String, Double> getCompactInfo(Assignment<Lecture, Placement> assignment, TimetableModel model, Placement assignedPlacement, boolean includeZero, 670 boolean weighted) { 671 Map<String, Double> info = new HashMap<String, Double>(); 672 if (!iMPP) 673 return info; 674 Lecture lecture = assignedPlacement.variable(); 675 Placement initialPlacement = lecture.getInitialAssignment(); 676 if (initialPlacement == null || initialPlacement.equals(assignedPlacement)) 677 return info; 678 int perts = 1; 679 long affectedStudents = lecture.classLimit(assignment); 680 int affectedInstructors = lecture.getInstructorConstraints().size(); 681 long affectedStudentsByTime = (initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation()) ? 0 : lecture.classLimit(assignment)); 682 int affectedInstructorsByTime = (initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation()) ? 0 : lecture.getInstructorConstraints().size()); 683 684 int differentRoom = initialPlacement.nrDifferentRooms(assignedPlacement); 685 int affectedInstructorsByRoom = differentRoom * lecture.getInstructorConstraints().size(); 686 long affectedStudentsByRoom = differentRoom * lecture.classLimit(assignment); 687 688 int differentBuilding = initialPlacement.nrDifferentBuildings(initialPlacement); 689 int affectedInstructorsByBldg = differentBuilding * lecture.getInstructorConstraints().size(); 690 long affectedStudentsByBldg = differentBuilding * lecture.classLimit(assignment); 691 692 int deltaRoomPreferences = assignedPlacement.sumRoomPreference() - initialPlacement.sumRoomPreference(); 693 694 int differentTime = (initialPlacement.getTimeLocation().equals(assignedPlacement.getTimeLocation()) ? 0 : 1); 695 int differentDay = (initialPlacement.getTimeLocation().getDayCode() != assignedPlacement.getTimeLocation().getDayCode() ? 1 : 0); 696 int differentHour = (initialPlacement.getTimeLocation().getStartSlot() != assignedPlacement.getTimeLocation().getStartSlot() ? 1 : 0); 697 int tooFarForInstructors = 0; 698 int tooFarForStudents = 0; 699 int deltaStudentConflicts = lecture.countStudentConflicts(assignment, assignedPlacement) - lecture.countInitialStudentConflicts(); 700 int newStudentConflicts = 0; 701 double deltaTimePreferences = (assignedPlacement.getTimeLocation().getNormalizedPreference() - 702 initialPlacement.getTimeLocation().getNormalizedPreference()); 703 int deltaInstructorDistancePreferences = 0; 704 705 double distance = Placement.getDistanceInMeters(iDistanceMetric, initialPlacement, assignedPlacement); 706 if (!lecture.getInstructorConstraints().isEmpty()) { 707 if (distance > iDistanceMetric.getInstructorNoPreferenceLimit() && distance <= iDistanceMetric.getInstructorDiscouragedLimit()) { 708 tooFarForInstructors += lecture.getInstructorConstraints().size(); 709 } else if (distance > iDistanceMetric.getInstructorDiscouragedLimit() && distance <= iDistanceMetric.getInstructorProhibitedLimit()) { 710 tooFarForInstructors += 2 * lecture.getInstructorConstraints().size(); 711 } else if (distance > iDistanceMetric.getInstructorProhibitedLimit()) { 712 tooFarForInstructors += 10 * lecture.getInstructorConstraints().size(); 713 } 714 } 715 if (distance > iDistanceMetric.minutes2meters(10)) 716 tooFarForStudents = lecture.classLimit(assignment); 717 718 Set<Student> newStudentConflictsVect = lecture.conflictStudents(assignment, assignedPlacement); 719 Set<Student> initialStudentConflicts = lecture.initialStudentConflicts(); 720 for (Iterator<Student> e = newStudentConflictsVect.iterator(); e.hasNext();) 721 if (!initialStudentConflicts.contains(e.next())) 722 newStudentConflicts++; 723 724 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 725 for (Lecture lect : ic.variables()) { 726 if (lect.equals(lecture)) 727 continue; 728 int initialPreference = (lect.getInitialAssignment() == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(initialPlacement, lect.getInitialAssignment())); 729 int assignedPreference = (assignment.getValue(lect) == null ? Constants.sPreferenceLevelNeutral : ic.getDistancePreference(assignedPlacement, assignment.getValue(lect))); 730 deltaInstructorDistancePreferences += (assignedPreference - initialPreference); 731 } 732 } 733 734 if (includeZero || iDifferentPlacement != 0.0) 735 info.put("Different placement", new Double(weighted ? iDifferentPlacement * perts : perts)); 736 if (includeZero || iAffectedStudentWeight != 0.0) 737 info.put("Affected students", new Double(weighted ? iAffectedStudentWeight * affectedStudents : affectedStudents)); 738 if (includeZero || iAffectedInstructorWeight != 0.0) 739 info.put("Affected instructors", new Double(weighted ? iAffectedInstructorWeight * affectedInstructors : affectedInstructors)); 740 if (includeZero || iAffectedStudentByTimeWeight != 0.0) 741 info.put("Affected students [time]", new Double(weighted ? iAffectedStudentByTimeWeight * affectedStudentsByTime : affectedStudentsByTime)); 742 if (includeZero || iAffectedInstructorByTimeWeight != 0.0) 743 info.put("Affected instructors [time]", new Double(weighted ? iAffectedInstructorByTimeWeight * affectedInstructorsByTime : affectedInstructorsByTime)); 744 if (includeZero || iAffectedStudentByRoomWeight != 0.0) 745 info.put("Affected students [room]", new Double(weighted ? iAffectedStudentByRoomWeight * affectedStudentsByRoom : affectedStudentsByRoom)); 746 if (includeZero || iAffectedInstructorByRoomWeight != 0.0) 747 info.put("Affected instructors [room]", new Double(weighted ? iAffectedInstructorByRoomWeight * affectedInstructorsByRoom : affectedInstructorsByRoom)); 748 if (includeZero || iAffectedStudentByBldgWeight != 0.0) 749 info.put("Affected students [bldg]", new Double(weighted ? iAffectedStudentByBldgWeight * affectedStudentsByBldg : affectedStudentsByBldg)); 750 if (includeZero || iAffectedInstructorByBldgWeight != 0.0) 751 info.put("Affected instructors [bldg]", new Double(weighted ? iAffectedInstructorByBldgWeight * affectedInstructorsByBldg : affectedInstructorsByBldg)); 752 if (includeZero || iDifferentRoomWeight != 0.0) 753 info.put("Different room", new Double(weighted ? iDifferentRoomWeight * differentRoom : differentRoom)); 754 if (includeZero || iDifferentBuildingWeight != 0.0) 755 info.put("Different building", new Double(weighted ? iDifferentBuildingWeight * differentBuilding : differentBuilding)); 756 if (includeZero || iDifferentTimeWeight != 0.0) 757 info.put("Different time", new Double(weighted ? iDifferentTimeWeight * differentTime : differentTime)); 758 if (includeZero || iDifferentDayWeight != 0.0) 759 info.put("Different day", new Double(weighted ? iDifferentDayWeight * differentDay : differentDay)); 760 if (includeZero || iDifferentHourWeight != 0.0) 761 info.put("Different hour", new Double(weighted ? iDifferentHourWeight * differentHour : differentHour)); 762 if (includeZero || iTooFarForInstructorsWeight != 0.0) 763 info.put("New placement too far for initial [instructors]", new Double(weighted ? iTooFarForInstructorsWeight * tooFarForInstructors : tooFarForInstructors)); 764 if (includeZero || iTooFarForStudentsWeight != 0.0) 765 info.put("New placement too far for initial [students]", new Double(weighted ? iTooFarForStudentsWeight * tooFarForStudents : tooFarForStudents)); 766 if (includeZero || iDeltaStudentConflictsWeight != 0.0) 767 info.put("Delta student conflicts", new Double(weighted ? iDeltaStudentConflictsWeight * deltaStudentConflicts : deltaStudentConflicts)); 768 if (includeZero || iNewStudentConflictsWeight != 0.0) 769 info.put("New student conflicts", new Double(weighted ? iNewStudentConflictsWeight * newStudentConflicts : newStudentConflicts)); 770 if (includeZero || iDeltaTimePreferenceWeight != 0.0) 771 info.put("Delta time preferences", new Double(weighted ? iDeltaTimePreferenceWeight * deltaTimePreferences : deltaTimePreferences)); 772 if (includeZero || iDeltaRoomPreferenceWeight != 0.0) 773 info.put("Delta room preferences", new Double(weighted ? iDeltaRoomPreferenceWeight * deltaRoomPreferences : deltaRoomPreferences)); 774 if (includeZero || iDeltaInstructorDistancePreferenceWeight != 0.0) 775 info.put("Delta instructor distance preferences", new Double(weighted ? iDeltaInstructorDistancePreferenceWeight * deltaInstructorDistancePreferences : deltaInstructorDistancePreferences)); 776 return info; 777 } 778}