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