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.extension.DistanceConflict; 018import org.cpsolver.studentsct.extension.TimeOverlapsCounter; 019import org.cpsolver.studentsct.model.Choice; 020import org.cpsolver.studentsct.model.Config; 021import org.cpsolver.studentsct.model.Course; 022import org.cpsolver.studentsct.model.CourseRequest; 023import org.cpsolver.studentsct.model.Enrollment; 024import org.cpsolver.studentsct.model.Instructor; 025import org.cpsolver.studentsct.model.Offering; 026import org.cpsolver.studentsct.model.Request; 027import org.cpsolver.studentsct.model.RequestGroup; 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 * New weighting model. It tries to obey the following principles: 036 * <ul> 037 * <li> Total student weight is between zero and one (one means student got the best schedule) 038 * <li> Weight of the given priority course is higher than sum of the remaining weights the student can get 039 * <li> First alternative is better than the following course 040 * <li> Second alternative is better than the second following course 041 * <li> Distance conflicts are considered secondary (priorities should be maximized first) 042 * <li> If alternative sections are otherwise equal, use the better balanced one 043 * </ul> 044 * 045 * @version StudentSct 1.3 (Student Sectioning)<br> 046 * Copyright (C) 2007 - 2014 Tomas Muller<br> 047 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 048 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 049 * <br> 050 * This library is free software; you can redistribute it and/or modify 051 * it under the terms of the GNU Lesser General Public License as 052 * published by the Free Software Foundation; either version 3 of the 053 * License, or (at your option) any later version. <br> 054 * <br> 055 * This library is distributed in the hope that it will be useful, but 056 * WITHOUT ANY WARRANTY; without even the implied warranty of 057 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 058 * Lesser General Public License for more details. <br> 059 * <br> 060 * You should have received a copy of the GNU Lesser General Public 061 * License along with this library; if not see 062 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 063 */ 064 065public class PriorityStudentWeights implements StudentWeights { 066 protected double iPriorityFactor = 0.5010; 067 protected double iFirstAlternativeFactor = 0.5010; 068 protected double iSecondAlternativeFactor = 0.2510; 069 protected double iDistanceConflict = 0.0100; 070 protected double iTimeOverlapFactor = 0.5000; 071 protected double iTimeOverlapMaxLimit = 0.5000; 072 protected boolean iLeftoverSpread = false; 073 protected double iBalancingFactor = 0.0050; 074 protected double iAlternativeRequestFactor = 0.1260; 075 protected double iProjectedStudentWeight = 0.0100; 076 protected boolean iMPP = false; 077 protected double iPerturbationFactor = 0.100; 078 protected double iSelectionFactor = 0.100; 079 protected double iSameChoiceWeight = 0.900; 080 protected double iSameTimeWeight = 0.700; 081 protected double iSameConfigWeight = 0.500; 082 protected double iGroupFactor = 0.100; 083 protected double iGroupBestRatio = 0.95; 084 protected double iGroupFillRatio = 0.05; 085 086 public PriorityStudentWeights(DataProperties config) { 087 iPriorityFactor = config.getPropertyDouble("StudentWeights.Priority", iPriorityFactor); 088 iFirstAlternativeFactor = config.getPropertyDouble("StudentWeights.FirstAlternative", iFirstAlternativeFactor); 089 iSecondAlternativeFactor = config.getPropertyDouble("StudentWeights.SecondAlternative", iSecondAlternativeFactor); 090 iDistanceConflict = config.getPropertyDouble("StudentWeights.DistanceConflict", iDistanceConflict); 091 iTimeOverlapFactor = config.getPropertyDouble("StudentWeights.TimeOverlapFactor", iTimeOverlapFactor); 092 iTimeOverlapMaxLimit = config.getPropertyDouble("StudentWeights.TimeOverlapMaxLimit", iTimeOverlapMaxLimit); 093 iLeftoverSpread = config.getPropertyBoolean("StudentWeights.LeftoverSpread", iLeftoverSpread); 094 iBalancingFactor = config.getPropertyDouble("StudentWeights.BalancingFactor", iBalancingFactor); 095 iAlternativeRequestFactor = config.getPropertyDouble("StudentWeights.AlternativeRequestFactor", iAlternativeRequestFactor); 096 iProjectedStudentWeight = config.getPropertyDouble("StudentWeights.ProjectedStudentWeight", iProjectedStudentWeight); 097 iMPP = config.getPropertyBoolean("General.MPP", false); 098 iPerturbationFactor = config.getPropertyDouble("StudentWeights.Perturbation", iPerturbationFactor); 099 iSelectionFactor = config.getPropertyDouble("StudentWeights.Selection", iSelectionFactor); 100 iSameChoiceWeight = config.getPropertyDouble("StudentWeights.SameChoice", iSameChoiceWeight); 101 iSameTimeWeight = config.getPropertyDouble("StudentWeights.SameTime", iSameTimeWeight); 102 iSameConfigWeight = config.getPropertyDouble("StudentWeights.SameConfig", iSameConfigWeight); 103 iGroupFactor = config.getPropertyDouble("StudentWeights.SameGroup", iGroupFactor); 104 iGroupBestRatio = config.getPropertyDouble("StudentWeights.GroupBestRatio", iGroupBestRatio); 105 iGroupFillRatio = config.getPropertyDouble("StudentWeights.GroupFillRatio", iGroupFillRatio); 106 } 107 108 public double getWeight(Request request) { 109 if (request.getStudent().isDummy() && iProjectedStudentWeight >= 0.0) { 110 double weight = iProjectedStudentWeight; 111 if (request.isAlternative()) 112 weight *= iAlternativeRequestFactor; 113 return weight; 114 } 115 double total = 10000.0; 116 int nrReq = request.getStudent().nrRequests(); 117 double remain = (iLeftoverSpread ? Math.floor(10000.0 * Math.pow(iPriorityFactor, nrReq) / nrReq) : 0.0); 118 for (int idx = 0; idx < request.getStudent().getRequests().size(); idx++) { 119 Request r = request.getStudent().getRequests().get(idx); 120 boolean last = (idx + 1 == request.getStudent().getRequests().size()); 121 boolean lastNotAlt = !r.isAlternative() && (last || request.getStudent().getRequests().get(1 + idx).isAlternative()); 122 double w = Math.ceil(iPriorityFactor * total) + remain; 123 if (lastNotAlt || last) { 124 w = total; 125 } else { 126 total -= w; 127 } 128 if (r.equals(request)) { 129 return w / 10000.0; 130 } 131 } 132 return 0.0; 133 } 134 135 public double getCachedWeight(Request request) { 136 Double w = (Double)request.getExtra(); 137 if (w == null) { 138 w = getWeight(request); 139 request.setExtra(w); 140 } 141 return w; 142 } 143 144 /** 145 * Return how much the given enrollment is different from the initial enrollment 146 * @param enrollment given enrollment 147 * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times) 148 */ 149 protected double getDifference(Enrollment enrollment) { 150 if (enrollment.getStudent().isDummy()) return 1.0; 151 Enrollment other = enrollment.getRequest().getInitialAssignment(); 152 if (other != null) { 153 double similarSections = 0.0; 154 if (enrollment.getConfig().equals(other.getConfig())) { 155 // same configurations -- compare sections of matching subpart 156 for (Section section: enrollment.getSections()) { 157 for (Section initial: other.getSections()) { 158 if (section.getSubpart().equals(initial.getSubpart())) { 159 if (section.equals(initial)) { 160 similarSections += 1.0; 161 } else if (section.sameChoice(initial)) { 162 similarSections += iSameChoiceWeight; 163 } else if (section.sameTime(initial)) { 164 similarSections += iSameTimeWeight; 165 } 166 break; 167 } 168 } 169 } 170 } else { 171 // different configurations -- compare sections of matching itype 172 for (Section section: enrollment.getSections()) { 173 for (Section initial: other.getSections()) { 174 if (section.sameChoice(initial)) { 175 similarSections += iSameChoiceWeight; 176 break; 177 } else if (section.sameInstructionalType(initial) && section.sameTime(initial)) { 178 similarSections += iSameTimeWeight; 179 break; 180 } 181 } 182 } 183 } 184 return 1.0 - similarSections / enrollment.getAssignments().size(); 185 } 186 return 1.0; 187 } 188 189 /** 190 * Return how much the given enrollment is different from the selection (if any) 191 * @param enrollment given enrollment 192 * @return 0.0 when all the sections are the same, 1.0 when all the section are different (including different times) 193 */ 194 public double getSelection(Enrollment enrollment) { 195 if (enrollment.getStudent().isDummy()) return 1.0; 196 if (enrollment.isCourseRequest()) { 197 CourseRequest cr = (CourseRequest)enrollment.getRequest(); 198 if (!cr.getSelectedChoices().isEmpty()) { 199 double similarSections = 0.0; 200 for (Section section: enrollment.getSections()) { 201 double bestChoice = 0.0; 202 for (Choice ch: cr.getSelectedChoices()) { 203 if (bestChoice < 1.0 && ch.sameSection(section)) { 204 bestChoice = 1.0; 205 } else if (bestChoice < iSameChoiceWeight && ch.sameChoice(section)) { 206 bestChoice = iSameChoiceWeight; 207 } else if (bestChoice < iSameTimeWeight && ch.sameInstructionalType(section) && ch.sameTime(section)) { 208 bestChoice = iSameTimeWeight; 209 } else if (bestChoice < iSameConfigWeight && ch.sameConfiguration(section)) { 210 bestChoice = iSameConfigWeight; 211 } 212 } 213 similarSections += bestChoice; 214 } 215 return 1.0 - similarSections / enrollment.getAssignments().size(); 216 } else { 217 return 1.0; 218 } 219 } else { 220 return 1.0; 221 } 222 } 223 224 225 @Override 226 public double getBound(Request request) { 227 return getCachedWeight(request); 228 } 229 230 protected double round(double value) { 231 return Math.ceil(10000.0 * value) / 10000.0; 232 } 233 234 @Override 235 public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 236 double weight = getCachedWeight(enrollment.getRequest()); 237 switch (enrollment.getPriority()) { 238 case 1: weight *= iFirstAlternativeFactor; break; 239 case 2: weight *= iSecondAlternativeFactor; break; 240 } 241 if (enrollment.isCourseRequest() && iBalancingFactor != 0.0) { 242 double configUsed = enrollment.getConfig().getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight(); 243 double disbalanced = 0; 244 double total = 0; 245 for (Section section: enrollment.getSections()) { 246 Subpart subpart = section.getSubpart(); 247 if (subpart.getSections().size() <= 1) continue; 248 double used = section.getEnrollmentTotalWeight(assignment, enrollment.getRequest()) + enrollment.getRequest().getWeight(); 249 // sections have limits -> desired size is section limit x (total enrollment / total limit) 250 // unlimited sections -> desired size is total enrollment / number of sections 251 double desired = (subpart.getLimit() > 0 252 ? section.getLimit() * (configUsed / subpart.getLimit()) 253 : configUsed / subpart.getSections().size()); 254 if (used > desired) 255 disbalanced += Math.min(enrollment.getRequest().getWeight(), used - desired) / enrollment.getRequest().getWeight(); 256 else 257 disbalanced -= Math.min(enrollment.getRequest().getWeight(), desired - used) / enrollment.getRequest().getWeight(); 258 total ++; 259 } 260 if (disbalanced > 0) 261 weight *= (1.0 - disbalanced / total * iBalancingFactor); 262 } 263 if (iMPP) { 264 double difference = getDifference(enrollment); 265 if (difference > 0.0) 266 weight *= (1.0 - difference * iPerturbationFactor); 267 } 268 if (iSelectionFactor != 0.0) { 269 double selection = getSelection(enrollment); 270 if (selection > 0.0) 271 weight *= (1.0 - selection * iSelectionFactor); 272 } 273 if (enrollment.isCourseRequest() && iGroupFactor != 0.0) { 274 double sameGroup = 0.0; int groupCount = 0; 275 for (RequestGroup g: ((CourseRequest)enrollment.getRequest()).getRequestGroups()) { 276 if (g.getCourse().equals(enrollment.getCourse())) { 277 sameGroup += g.getEnrollmentSpread(assignment, enrollment, iGroupBestRatio, iGroupFillRatio); 278 groupCount ++; 279 } 280 } 281 if (groupCount > 0) { 282 double difference = 1.0 - sameGroup / groupCount; 283 weight *= (1.0 - difference * iGroupFactor); 284 } 285 } 286 return round(weight); 287 } 288 289 @Override 290 public double getDistanceConflictWeight(Assignment<Request, Enrollment> assignment, DistanceConflict.Conflict c) { 291 if (c.getR1().getPriority() < c.getR2().getPriority()) { 292 return round(getWeight(assignment, c.getE2()) * iDistanceConflict); 293 } else { 294 return round(getWeight(assignment, c.getE1()) * iDistanceConflict); 295 } 296 } 297 298 @Override 299 public double getTimeOverlapConflictWeight(Assignment<Request, Enrollment> assignment, Enrollment e, TimeOverlapsCounter.Conflict c) { 300 if (e == null || e.getRequest() == null) return 0.0; 301 double toc = Math.min(iTimeOverlapMaxLimit * c.getShare() / e.getNrSlots(), iTimeOverlapMaxLimit); 302 return round(getWeight(assignment, e) * toc); 303 } 304 305 @Override 306 public double getWeight(Assignment<Request, Enrollment> assignment, Enrollment enrollment, Set<DistanceConflict.Conflict> distanceConflicts, Set<TimeOverlapsCounter.Conflict> timeOverlappingConflicts) { 307 double base = getWeight(assignment, enrollment); 308 double dc = 0.0; 309 if (distanceConflicts != null) { 310 for (DistanceConflict.Conflict c: distanceConflicts) { 311 Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1()); 312 if (other.getRequest().getPriority() <= enrollment.getRequest().getPriority()) 313 dc += base * iDistanceConflict; 314 else 315 dc += getWeight(assignment, other) * iDistanceConflict; 316 } 317 } 318 double toc = 0.0; 319 if (timeOverlappingConflicts != null) { 320 for (TimeOverlapsCounter.Conflict c: timeOverlappingConflicts) { 321 toc += base * Math.min(iTimeOverlapFactor * c.getShare() / enrollment.getNrSlots(), iTimeOverlapMaxLimit); 322 Enrollment other = (c.getE1().equals(enrollment) ? c.getE2() : c.getE1()); 323 if (other.getRequest() != null) 324 toc += getWeight(assignment, other) * Math.min(iTimeOverlapFactor * c.getShare() / other.getNrSlots(), iTimeOverlapMaxLimit); 325 } 326 } 327 return round(base - dc - toc); 328 } 329 330 331 @Override 332 public boolean isBetterThanBestSolution(Solution<Request, Enrollment> currentSolution) { 333 return currentSolution.getBestInfo() == null || currentSolution.getModel().getTotalValue(currentSolution.getAssignment()) < currentSolution.getBestValue(); 334 } 335 336 @Override 337 public boolean isFreeTimeAllowOverlaps() { 338 return false; 339 } 340 341 /** 342 * Test case -- run to see the weights for a few courses 343 * @param args program arguments 344 */ 345 public static void main(String[] args) { 346 PriorityStudentWeights pw = new PriorityStudentWeights(new DataProperties()); 347 DecimalFormat df = new DecimalFormat("0.0000"); 348 Student s = new Student(0l); 349 new CourseRequest(1l, 0, false, s, ToolBox.toList( 350 new Course(1, "A", "1", new Offering(0, "A")), 351 new Course(1, "A", "2", new Offering(0, "A")), 352 new Course(1, "A", "3", new Offering(0, "A"))), false, null); 353 new CourseRequest(2l, 1, false, s, ToolBox.toList( 354 new Course(1, "B", "1", new Offering(0, "B")), 355 new Course(1, "B", "2", new Offering(0, "B")), 356 new Course(1, "B", "3", new Offering(0, "B"))), false, null); 357 new CourseRequest(3l, 2, false, s, ToolBox.toList( 358 new Course(1, "C", "1", new Offering(0, "C")), 359 new Course(1, "C", "2", new Offering(0, "C")), 360 new Course(1, "C", "3", new Offering(0, "C"))), false, null); 361 new CourseRequest(4l, 3, false, s, ToolBox.toList( 362 new Course(1, "D", "1", new Offering(0, "D")), 363 new Course(1, "D", "2", new Offering(0, "D")), 364 new Course(1, "D", "3", new Offering(0, "D"))), false, null); 365 new CourseRequest(5l, 4, false, s, ToolBox.toList( 366 new Course(1, "E", "1", new Offering(0, "E")), 367 new Course(1, "E", "2", new Offering(0, "E")), 368 new Course(1, "E", "3", new Offering(0, "E"))), false, null); 369 new CourseRequest(6l, 5, true, s, ToolBox.toList( 370 new Course(1, "F", "1", new Offering(0, "F")), 371 new Course(1, "F", "2", new Offering(0, "F")), 372 new Course(1, "F", "3", new Offering(0, "F"))), false, null); 373 new CourseRequest(7l, 6, true, s, ToolBox.toList( 374 new Course(1, "G", "1", new Offering(0, "G")), 375 new Course(1, "G", "2", new Offering(0, "G")), 376 new Course(1, "G", "3", new Offering(0, "G"))), false, null); 377 378 Assignment<Request, Enrollment> assignment = new DefaultSingleAssignment<Request, Enrollment>(); 379 Placement p = new Placement(null, new TimeLocation(1, 90, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 380 for (Request r: s.getRequests()) { 381 CourseRequest cr = (CourseRequest)r; 382 double[] w = new double[] {0.0, 0.0, 0.0}; 383 for (int i = 0; i < cr.getCourses().size(); i++) { 384 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 385 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 386 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 387 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 388 w[i] = pw.getWeight(assignment, e, null, null); 389 } 390 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 391 } 392 393 System.out.println("With one distance conflict:"); 394 for (Request r: s.getRequests()) { 395 CourseRequest cr = (CourseRequest)r; 396 double[] w = new double[] {0.0, 0.0, 0.0}; 397 for (int i = 0; i < cr.getCourses().size(); i++) { 398 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 399 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 400 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 401 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 402 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 403 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 404 w[i] = pw.getWeight(assignment, e, dc, null); 405 } 406 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 407 } 408 409 System.out.println("With two distance conflicts:"); 410 for (Request r: s.getRequests()) { 411 CourseRequest cr = (CourseRequest)r; 412 double[] w = new double[] {0.0, 0.0, 0.0}; 413 for (int i = 0; i < cr.getCourses().size(); i++) { 414 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 415 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 416 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 417 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 418 Set<DistanceConflict.Conflict> dc = new HashSet<DistanceConflict.Conflict>(); 419 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, (Section)sections.iterator().next())); 420 dc.add(new DistanceConflict.Conflict(s, e, (Section)sections.iterator().next(), e, 421 new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null))); 422 w[i] = pw.getWeight(assignment, e, dc, null); 423 } 424 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 425 } 426 427 System.out.println("With 25% time overlapping conflict:"); 428 for (Request r: s.getRequests()) { 429 CourseRequest cr = (CourseRequest)r; 430 double[] w = new double[] {0.0, 0.0, 0.0}; 431 for (int i = 0; i < cr.getCourses().size(); i++) { 432 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 433 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 434 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 435 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 436 Set<TimeOverlapsCounter.Conflict> toc = new HashSet<TimeOverlapsCounter.Conflict>(); 437 toc.add(new TimeOverlapsCounter.Conflict(s, 3, e, sections.iterator().next(), e, sections.iterator().next())); 438 w[i] = pw.getWeight(assignment, e, null, toc); 439 } 440 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 441 } 442 443 System.out.println("Disbalanced sections (by 2 / 10 students):"); 444 for (Request r: s.getRequests()) { 445 CourseRequest cr = (CourseRequest)r; 446 double[] w = new double[] {0.0, 0.0, 0.0}; 447 for (int i = 0; i < cr.getCourses().size(); i++) { 448 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 449 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 450 Subpart x = new Subpart(0, "Lec", "Lec", cfg, null); 451 Section a = new Section(0, 10, "x", x, p, null); 452 new Section(1, 10, "y", x, p, null); 453 sections.add(a); 454 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 455 a.assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 456 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 457 cfg.getContext(assignment).assigned(assignment, new Enrollment(s.getRequests().get(0), i, cfg, sections, assignment)); 458 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 459 w[i] = pw.getWeight(assignment, e, null, null); 460 } 461 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 462 } 463 464 System.out.println("Same choice sections:"); 465 pw.iMPP = true; 466 for (Request r: s.getRequests()) { 467 CourseRequest cr = (CourseRequest)r; 468 double[] w = new double[] {0.0, 0.0, 0.0}; 469 for (int i = 0; i < cr.getCourses().size(); i++) { 470 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 471 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 472 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 473 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 474 Set<SctAssignment> other = new HashSet<SctAssignment>(); 475 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 476 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 477 w[i] = pw.getWeight(assignment, e, null, null); 478 } 479 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 480 } 481 482 System.out.println("Same time sections:"); 483 for (Request r: s.getRequests()) { 484 CourseRequest cr = (CourseRequest)r; 485 double[] w = new double[] {0.0, 0.0, 0.0}; 486 for (int i = 0; i < cr.getCourses().size(); i++) { 487 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 488 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 489 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 490 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 491 Set<SctAssignment> other = new HashSet<SctAssignment>(); 492 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null))); 493 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 494 w[i] = pw.getWeight(assignment, e, null, null); 495 } 496 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 497 } 498 499 System.out.println("Different time sections:"); 500 Placement q = new Placement(null, new TimeLocation(1, 102, 12, 0, 0, null, null, new BitSet(), 10), new ArrayList<RoomLocation>()); 501 for (Request r: s.getRequests()) { 502 CourseRequest cr = (CourseRequest)r; 503 double[] w = new double[] {0.0, 0.0, 0.0}; 504 for (int i = 0; i < cr.getCourses().size(); i++) { 505 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 506 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 507 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 508 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 509 Set<SctAssignment> other = new HashSet<SctAssignment>(); 510 other.add(new Section(1, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), q, null)); 511 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 512 w[i] = pw.getWeight(assignment, e, null, null); 513 } 514 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 515 } 516 517 System.out.println("Two sections, one same choice, one same time:"); 518 for (Request r: s.getRequests()) { 519 CourseRequest cr = (CourseRequest)r; 520 double[] w = new double[] {0.0, 0.0, 0.0}; 521 for (int i = 0; i < cr.getCourses().size(); i++) { 522 Config cfg = new Config(0l, -1, "", cr.getCourses().get(i).getOffering()); 523 Set<SctAssignment> sections = new HashSet<SctAssignment>(); 524 sections.add(new Section(0, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 525 sections.add(new Section(1, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null)); 526 Enrollment e = new Enrollment(cr, i, cfg, sections, assignment); 527 Set<SctAssignment> other = new HashSet<SctAssignment>(); 528 other.add(new Section(2, 1, "x", new Subpart(0, "Lec", "Lec", cfg, null), p, null)); 529 other.add(new Section(3, 1, "y", new Subpart(1, "Rec", "Rec", cfg, null), p, null, new Instructor(1l, null, "Josef Novak", null))); 530 cr.setInitialAssignment(new Enrollment(cr, i, cfg, other, assignment)); 531 w[i] = pw.getWeight(assignment, e, null, null); 532 } 533 System.out.println(cr + ": " + df.format(w[0]) + " " + df.format(w[1]) + " " + df.format(w[2])); 534 } 535 536 } 537}