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