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