001package org.cpsolver.studentsct.weights; 002 003import java.text.DecimalFormat; 004import java.util.ArrayList; 005import java.util.BitSet; 006import java.util.HashSet; 007import java.util.Set; 008 009import org.cpsolver.coursett.model.Placement; 010import org.cpsolver.coursett.model.RoomLocation; 011import org.cpsolver.coursett.model.TimeLocation; 012import org.cpsolver.ifs.assignment.Assignment; 013import org.cpsolver.ifs.assignment.DefaultSingleAssignment; 014import org.cpsolver.ifs.solution.Solution; 015import org.cpsolver.ifs.util.DataProperties; 016import org.cpsolver.ifs.util.ToolBox; 017import org.cpsolver.studentsct.StudentSectioningModel; 018import org.cpsolver.studentsct.extension.DistanceConflict; 019import org.cpsolver.studentsct.extension.TimeOverlapsCounter; 020import org.cpsolver.studentsct.model.Choice; 021import org.cpsolver.studentsct.model.Config; 022import org.cpsolver.studentsct.model.Course; 023import org.cpsolver.studentsct.model.CourseRequest; 024import org.cpsolver.studentsct.model.Enrollment; 025import org.cpsolver.studentsct.model.Instructor; 026import org.cpsolver.studentsct.model.Offering; 027import org.cpsolver.studentsct.model.Request; 028import org.cpsolver.studentsct.model.SctAssignment; 029import org.cpsolver.studentsct.model.Section; 030import org.cpsolver.studentsct.model.Student; 031import org.cpsolver.studentsct.model.Subpart; 032 033 034/** 035 * Student weight is spread equally among student's course requests. Only alternatives have lower weight. 036 * The rest is inherited from {@link PriorityStudentWeights}. 037 * 038 * @version StudentSct 1.3 (Student Sectioning)<br> 039 * Copyright (C) 2007 - 2014 Tomáš Müller<br> 040 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 041 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 042 * <br> 043 * This library is free software; you can redistribute it and/or modify 044 * it under the terms of the GNU Lesser General Public License as 045 * published by the Free Software Foundation; either version 3 of the 046 * License, or (at your option) any later version. <br> 047 * <br> 048 * This library is distributed in the hope that it will be useful, but 049 * WITHOUT ANY WARRANTY; without even the implied warranty of 050 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 051 * Lesser General Public License for more details. <br> 052 * <br> 053 * You should have received a copy of the GNU Lesser General Public 054 * License along with this library; if not see 055 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 056 */ 057 058public class EqualStudentWeights extends PriorityStudentWeights { 059 060 public EqualStudentWeights(DataProperties config) { 061 super(config); 062 } 063 064 @Override 065 public double getWeight(Request request) { 066 if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) { 067 double weight = iProjectedStudentWeight; 068 if (request.isAlternative()) 069 weight *= iAlternativeRequestFactor; 070 return weight; 071 } 072 double weight = 1.0 / request.getStudent().nrRequests(); 073 if (request.isAlternative()) 074 weight *= iAlternativeRequestFactor; 075 return round(weight); 076 } 077 078 @Override 079 public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) { 080 if (currentSolution.getBestInfo() == null) return true; 081 if (iMPP) return super.isBetterThanBestSolution(currentSolution); 082 int unassigned = currentSolution.getModel().nrUnassignedVariables(currentSolution.getAssignment()); 083 if (currentSolution.getModel().getBestUnassignedVariables() != unassigned) 084 return currentSolution.getModel().getBestUnassignedVariables() > unassigned; 085 return ((StudentSectioningModel)currentSolution.getModel()).getTotalValue(currentSolution.getAssignment(), iPreciseComparison) < currentSolution.getBestValue(); 086 } 087 088 @Override 089 public boolean isFreeTimeAllowOverlaps() { 090 return true; 091 } 092 093 /** 094 * Test case -- run to see the weights for a few courses 095 * @param args program arguments 096 */ 097 public static void main(String[] args) { 098 EqualStudentWeights pw = new EqualStudentWeights(new DataProperties()); 099 DecimalFormat df = new DecimalFormat("0.0000"); 100 Student s = new Student(0l); 101 new CourseRequest(1l, 0, false, s, ToolBox.toList( 102 new Course(1, "A", "1", new Offering(0, "A")), 103 new Course(1, "A", "2", new Offering(0, "A")), 104 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 105 new CourseRequest(2l, 1, false, s, ToolBox.toList( 106 new Course(1, "B", "1", new Offering(0, "B")), 107 new Course(1, "B", "2", new Offering(0, "B")), 108 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 109 new CourseRequest(3l, 2, false, s, ToolBox.toList( 110 new Course(1, "C", "1", new Offering(0, "C")), 111 new Course(1, "C", "2", new Offering(0, "C")), 112 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 113 new CourseRequest(5l, 4, false, s, ToolBox.toList( 114 new Course(1, "E", "1", new Offering(0, "E")), 115 new Course(1, "E", "2", new Offering(0, "E")), 116 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 117 new CourseRequest(6l, 5, true, s, ToolBox.toList( 118 new Course(1, "F", "1", new Offering(0, "F")), 119 new Course(1, "F", "2", new Offering(0, "F")), 120 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 121 new CourseRequest(7l, 6, true, s, ToolBox.toList( 122 new Course(1, "G", "1", new Offering(0, "G")), 123 new Course(1, "G", "2", new Offering(0, "G")), 124 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 125 126 Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>(); 127 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 128 for (Request r: s.getRequests()) { 129 CourseRequest cr = (CourseRequest)r; 130 double[] w = new double[] {0.0, 0.0, 0.0}; 131 for (int i = 0; i < cr.getCourses().size(); i++) { 132 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 133 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 134 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 135 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 136 w[i] = pw.getWeight(assignment, e, null, null); 137 } 138 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 139 } 140 141 System.out.println("With one distance conflict:"); 142 for (Request r: s.getRequests()) { 143 CourseRequest cr = (CourseRequest)r; 144 double[] w = new double[] {0.0, 0.0, 0.0}; 145 for (int i = 0; i < cr.getCourses().size(); i++) { 146 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 147 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 148 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 149 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 150 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 151 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 152 w[i] = pw.getWeight(assignment, e, dc, null); 153 } 154 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 155 } 156 157 System.out.println("With two distance conflicts:"); 158 for (Request r: s.getRequests()) { 159 CourseRequest cr = (CourseRequest)r; 160 double[] w = new double[] {0.0, 0.0, 0.0}; 161 for (int i = 0; i < cr.getCourses().size(); i++) { 162 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 163 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 164 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 165 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 166 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 167 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 168 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 169 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null))); 170 w[i] = pw.getWeight(assignment, e, dc, null); 171 } 172 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 173 } 174 175 System.out.println("With 25% time overlapping conflict:"); 176 for (Request r: s.getRequests()) { 177 CourseRequest cr = (CourseRequest)r; 178 double[] w = new double[] {0.0, 0.0, 0.0}; 179 for (int i = 0; i < cr.getCourses().size(); i++) { 180 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 181 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 182 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 183 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 184 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 185 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 186 w[i] = pw.getWeight(assignment, e, null, toc); 187 } 188 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 189 } 190 191 System.out.println("Disbalanced sections (by 2 / 10 students):"); 192 for (Request r: s.getRequests()) { 193 CourseRequest cr = (CourseRequest)r; 194 double[] w = new double[] {0.0, 0.0, 0.0}; 195 for (int i = 0; i < cr.getCourses().size(); i++) { 196 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 197 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 198 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 199 Section a = new Section(0, 10, "x", x, p, null); 200 new Section(1, 10, "y", x, p, null); 201 sections.add(a); 202 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 203 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 204 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 205 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 206 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 207 w[i] = pw.getWeight(assignment, e, null, null); 208 } 209 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 210 } 211 212 System.out.println("Same sections:"); 213 pw.iMPP = true; 214 for (Request r: s.getRequests()) { 215 CourseRequest cr = (CourseRequest)r; 216 double[] w = new double[] {0.0, 0.0, 0.0}; 217 double dif = 0; 218 for (int i = 0; i < cr.getCourses().size(); i++) { 219 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 220 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 221 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 222 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 223 cr.setInitialAssignment(new Enrollment(cr, i, cfg, sections, assignment)); 224 w[i] = pw.getWeight(assignment, e, null, null); 225 dif = pw.getDifference(e); 226 } 227 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 228 } 229 230 System.out.println("Same choice sections:"); 231 pw.iMPP = true; 232 for (Request r: s.getRequests()) { 233 CourseRequest cr = (CourseRequest)r; 234 double[] w = new double[] {0.0, 0.0, 0.0}; 235 double dif = 0; 236 for (int i = 0; i < cr.getCourses().size(); i++) { 237 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 238 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 239 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 240 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 241 Set<SctAssignment> other = new HashSet<SctAssignment>(); 242 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 243 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 244 w[i] = pw.getWeight(assignment, e, null, null); 245 dif = pw.getDifference(e); 246 } 247 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 248 } 249 250 System.out.println("Same time sections:"); 251 for (Request r: s.getRequests()) { 252 CourseRequest cr = (CourseRequest)r; 253 double dif = 0; 254 double[] w = new double[] {0.0, 0.0, 0.0}; 255 for (int i = 0; i < cr.getCourses().size(); i++) { 256 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 257 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 258 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 259 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 260 Set<SctAssignment> other = new HashSet<SctAssignment>(); 261 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1, null, "Josef Novak", null))); 262 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 263 w[i] = pw.getWeight(assignment, e, null, null); 264 dif = pw.getDifference(e); 265 } 266 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 267 } 268 269 System.out.println("Same configuration sections:"); 270 for (Request r: s.getRequests()) { 271 CourseRequest cr = (CourseRequest)r; 272 double[] w = new double[] {0.0, 0.0, 0.0}; 273 double dif = 0; 274 for (int i = 0; i < cr.getCourses().size(); i++) { 275 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 276 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 277 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 278 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 279 cr.getSelectedChoices().add(new Choice(cfg)); 280 cr.setInitialAssignment(null); 281 w[i] = pw.getWeight(assignment, e, null, null); 282 dif = pw.getDifference(e); 283 } 284 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 285 } 286 287 System.out.println("Different time sections:"); 288 Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 289 for (Request r: s.getRequests()) { 290 CourseRequest cr = (CourseRequest)r; 291 double[] w = new double[] {0.0, 0.0, 0.0}; 292 double dif = 0; 293 for (int i = 0; i < cr.getCourses().size(); i++) { 294 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 295 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 296 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 297 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 298 Set<SctAssignment> other = new HashSet<SctAssignment>(); 299 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null)); 300 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 301 w[i] = pw.getWeight(assignment, e, null, null); 302 dif = pw.getDifference(e); 303 } 304 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 305 } 306 307 System.out.println("Two sections, one same choice, one same time:"); 308 for (Request r: s.getRequests()) { 309 CourseRequest cr = (CourseRequest)r; 310 double[] w = new double[] {0.0, 0.0, 0.0}; 311 double dif = 0; 312 for (int i = 0; i < cr.getCourses().size(); i++) { 313 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 314 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 315 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 316 sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null)); 317 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 318 Set<SctAssignment> other = new HashSet<SctAssignment>(); 319 other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 320 other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1, null, "Josef Novak", null))); 321 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 322 w[i] = pw.getWeight(assignment, e, null, null); 323 dif = pw.getDifference(e); 324 } 325 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2]) + " (" + df.format(dif) + ")"); 326 } 327 } 328}