    001package org.cpsolver.studentsct.online.selection;
    002
    003import java.util.List;
    004
    005import org.cpsolver.coursett.model.RoomLocation;
    006import org.cpsolver.coursett.model.TimeLocation;
    007import org.cpsolver.ifs.assignment.Assignment;
    008import org.cpsolver.ifs.util.DataProperties;
    009import org.cpsolver.ifs.util.ToolBox;
    010import org.cpsolver.studentsct.model.Choice;
    011import org.cpsolver.studentsct.model.Course;
    012import org.cpsolver.studentsct.model.CourseRequest;
    013import org.cpsolver.studentsct.model.Enrollment;
    014import org.cpsolver.studentsct.model.Request;
    015import org.cpsolver.studentsct.model.Section;
    016import org.cpsolver.studentsct.weights.StudentWeights;
    017
    018/**
    019 * Re-scheduling variant of {@link StudentWeights} model. It is based on the
    020 * {@link StudentSchedulingAssistantWeights}. This model is used when a single
    021 * course of a student is rescheduled. Following criteria are included:
    022 * <ul>
    023 * <li>StudentWeights.SameChoiceFactor .. penalization of selecting a different
    024 * choice (see {@link Choice})
    025 * <li>StudentWeights.SameRoomsFactor .. penalization of selecting different
    026 * room
    027 * <li>StudentWeights.SameTimeFactor .. penalization of selecting different time
    028 * <li>StudentWeights.SameNameFactor .. penalization of selecting different
    029 * section (section name / external id does not match)
    030 * </ul>
    031 *
    032 * @author  Tomáš Müller
    033 * @version StudentSct 1.3 (Student Sectioning)<br>
    034 *          Copyright (C) 2014 Tomáš Müller<br>
    035 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    036 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    037 * <br>
    038 *          This library is free software; you can redistribute it and/or modify
    039 *          it under the terms of the GNU Lesser General Public License as
    040 *          published by the Free Software Foundation; either version 3 of the
    041 *          License, or (at your option) any later version. <br>
    042 * <br>
    043 *          This library is distributed in the hope that it will be useful, but
    044 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    045 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    046 *          Lesser General Public License for more details. <br>
    047 * <br>
    048 *          You should have received a copy of the GNU Lesser General Public
    049 *          License along with this library; if not see <a
    050 *          href='http://www.gnu.org/licenses'>http://www.gnu.org/licenses</a>.
    051 *
    052 */
    053public class ResectioningWeights extends StudentSchedulingAssistantWeights {
    054    private double iSameChoiceFactor = 0.125;
    055    private double iSameRoomsFactor = 0.007;
    056    private double iSameTimeFactor = 0.070;
    057    private double iSameNameFactor = 0.014;
    058    private LastSectionProvider iLastSectionProvider = null;
    059
    060    public ResectioningWeights(DataProperties properties) {
    061        super(properties);
    062        iSameChoiceFactor = properties.getPropertyDouble("StudentWeights.SameChoiceFactor", iSameChoiceFactor);
    063        iSameRoomsFactor = properties.getPropertyDouble("StudentWeights.SameRoomsFactor", iSameRoomsFactor);
    064        iSameTimeFactor = properties.getPropertyDouble("StudentWeights.SameTimeFactor", iSameTimeFactor);
    065        iSameNameFactor = properties.getPropertyDouble("StudentWeights.SameNameFactor", iSameNameFactor);
    066    }
    067
    068    public void setLastSectionProvider(LastSectionProvider lastSectionProvider) {
    069        iLastSectionProvider = lastSectionProvider;
    070    }
    071
    072    @Override
    073    public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) {
    074        double weight = super.getWeight(assignment, enrollment);
    075
    076        if (enrollment.isCourseRequest() && enrollment.getAssignments() != null && iLastSectionProvider != null) {
    077            int sameChoice = 0;
    078            int sameTime = 0;
    079            int sameRooms = 0;
    080            int sameName = 0;
    081            for (Section section : enrollment.getSections()) {
    082                if (iLastSectionProvider.sameLastChoice(section))
    083                    sameChoice++;
    084                if (iLastSectionProvider.sameLastTime(section))
    085                    sameTime++;
    086                if (iLastSectionProvider.sameLastRoom(section))
    087                    sameRooms++;
    088                if (iLastSectionProvider.sameLastName(section, enrollment.getCourse()))
    089                    sameName++;
    090            }
    091            CourseRequest cr = (CourseRequest) enrollment.getRequest();
    092            if (sameChoice == 0 && !cr.getSelectedChoices().isEmpty()) {
    093                for (Section section : enrollment.getSections()) {
    094                    if (cr.isSelected(section)) {
    095                        sameChoice++;
    096                        continue;
    097                    }
    098                }
    099            }
    100            double size = enrollment.getAssignments().size();
    101            double sameChoiceFraction = (size - sameChoice) / size;
    102            double sameTimeFraction = (size - sameTime) / size;
    103            double sameRoomsFraction = (size - sameRooms) / size;
    104            double sameNameFraction = (size - sameName) / size;
    105            double base = getBaseWeight(assignment, enrollment);
    106            weight -= sameChoiceFraction * base * iSameChoiceFactor;
    107            weight -= sameTimeFraction * base * iSameTimeFactor;
    108            weight -= sameRoomsFraction * base * iSameRoomsFactor;
    109            weight -= sameNameFraction * base * iSameNameFactor;
    110        }
    111
    112        return weight;
    113    }
    114
    115    public static boolean isSame(Enrollment e1, Enrollment e2) {
    116        if (e1.getSections().size() != e2.getSections().size())
    117            return false;
    118        s1: for (Section s1 : e1.getSections()) {
    119            for (Section s2 : e2.getSections())
    120                if (s1.sameChoice(s2))
    121                    continue s1;
    122            return false;
    123        }
    124        return true;
    125    }
    126
    127    public static boolean sameRooms(Section s, List<RoomLocation> rooms) {
    128        if (s.getRooms() == null && rooms == null)
    129            return true;
    130        if (s.getRooms() == null || rooms == null)
    131            return false;
    132        return s.getRooms().size() == rooms.size() && s.getRooms().containsAll(rooms);
    133    }
    134
    135    public static boolean sameTime(Section s, TimeLocation t) {
    136        if (s.getTime() == null && t == null)
    137            return true;
    138        if (s.getTime() == null || t == null)
    139            return false;
    140        return s.getTime().getStartSlot() == t.getStartSlot() && s.getTime().getLength() == t.getLength()
    141                && s.getTime().getDayCode() == t.getDayCode()
    142                && ToolBox.equals(s.getTime().getDatePatternName(), t.getDatePatternName());
    143    }
    144
    145    public static boolean sameName(Long courseId, Section s1, Section s2) {
    146        return s1.getName(courseId).equals(s2.getName(courseId));
    147    }
    148
    149    public static boolean sameChoice(Section section, Choice choice) {
    150        return choice.sameChoice(section);
    151    }
    152
    153    /**
    154     * Compare the old assignment with the current one
    155     */
    156    public static interface LastSectionProvider {
    157        /**
    158         * Check the choice (see {@link Choice})
    159         *
    160         * @param current
    161         *            current section
    162         * @return true if the choice matches
    163         */
    164        public boolean sameLastChoice(Section current);
    165
    166        /**
    167         * Check the time
    168         *
    169         * @param current
    170         *            current section
    171         * @return true if the time matches
    172         */
    173        public boolean sameLastTime(Section current);
    174
    175        /**
    176         * Check the room
    177         *
    178         * @param current
    179         *            current section
    180         * @return true if the room matches
    181         */
    182        public boolean sameLastRoom(Section current);
    183
    184        /**
    185         * Check section name (external id)
    186         *
    187         * @param current
    188         *            current section
    189         * @param course
    190         *            current course
    191         * @return true if the section name matches
    192         */
    193        public boolean sameLastName(Section current, Course course);
    194    }
    195}