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}