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