001    package net.sf.cpsolver.coursett.heuristics;
002    
003    import java.util.HashMap;
004    import java.util.Iterator;
005    import java.util.List;
006    import java.util.Map;
007    import java.util.Set;
008    
009    import net.sf.cpsolver.coursett.Constants;
010    import net.sf.cpsolver.coursett.constraint.InstructorConstraint;
011    import net.sf.cpsolver.coursett.model.Lecture;
012    import net.sf.cpsolver.coursett.model.Placement;
013    import net.sf.cpsolver.coursett.model.Student;
014    import net.sf.cpsolver.coursett.model.TimetableModel;
015    import net.sf.cpsolver.ifs.perturbations.DefaultPerturbationsCounter;
016    import net.sf.cpsolver.ifs.util.DataProperties;
017    import 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 Tomas Muller<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    
228    public 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    }