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