001package org.cpsolver.studentsct.extension; 002 003import java.util.HashSet; 004import java.util.Set; 005 006import org.apache.log4j.Logger; 007import org.cpsolver.ifs.assignment.Assignment; 008import org.cpsolver.ifs.assignment.context.AssignmentConstraintContext; 009import org.cpsolver.ifs.assignment.context.ExtensionWithContext; 010import org.cpsolver.ifs.solver.Solver; 011import org.cpsolver.ifs.util.DataProperties; 012import org.cpsolver.studentsct.StudentSectioningModel; 013import org.cpsolver.studentsct.StudentSectioningModel.StudentSectioningModelContext; 014import org.cpsolver.studentsct.model.Enrollment; 015import org.cpsolver.studentsct.model.FreeTimeRequest; 016import org.cpsolver.studentsct.model.Request; 017import org.cpsolver.studentsct.model.SctAssignment; 018import org.cpsolver.studentsct.model.Section; 019import org.cpsolver.studentsct.model.Student; 020import org.cpsolver.studentsct.model.Unavailability; 021 022 023/** 024 * This extension computes time overlaps. Only sections that allow overlaps 025 * (see {@link SctAssignment#isAllowOverlap()}) can overlap. This class counts 026 * how many overlapping slots there are so that this number can be minimized. 027 * 028 * <br> 029 * <br> 030 * 031 * @version StudentSct 1.3 (Student Sectioning)<br> 032 * Copyright (C) 2007 - 2014 Tomas Muller<br> 033 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 034 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 035 * <br> 036 * This library is free software; you can redistribute it and/or modify 037 * it under the terms of the GNU Lesser General Public License as 038 * published by the Free Software Foundation; either version 3 of the 039 * License, or (at your option) any later version. <br> 040 * <br> 041 * This library is distributed in the hope that it will be useful, but 042 * WITHOUT ANY WARRANTY; without even the implied warranty of 043 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 044 * Lesser General Public License for more details. <br> 045 * <br> 046 * You should have received a copy of the GNU Lesser General Public 047 * License along with this library; if not see 048 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 049 */ 050 051public class TimeOverlapsCounter extends ExtensionWithContext<Request, Enrollment, TimeOverlapsCounter.TimeOverlapsCounterContext> { 052 private static Logger sLog = Logger.getLogger(TimeOverlapsCounter.class); 053 /** Debug flag */ 054 public static boolean sDebug = false; 055 056 /** 057 * Constructor. Beside of other things, this constructor also uses 058 * {@link StudentSectioningModel#setTimeOverlaps(TimeOverlapsCounter)} to 059 * set the this instance to the model. 060 * 061 * @param solver 062 * constraint solver 063 * @param properties 064 * configuration 065 */ 066 public TimeOverlapsCounter(Solver<Request, Enrollment> solver, DataProperties properties) { 067 super(solver, properties); 068 if (solver != null) 069 ((StudentSectioningModel) solver.currentSolution().getModel()).setTimeOverlaps(this); 070 } 071 072 @Override 073 public String toString() { 074 return "TimeOverlaps"; 075 } 076 077 /** 078 * Return true if the given two assignments are overlapping. 079 * 080 * @param a1 081 * an assignment 082 * @param a2 083 * an assignment 084 * @return true, if the given sections are in an overlapping conflict 085 */ 086 public boolean inConflict(SctAssignment a1, SctAssignment a2) { 087 if (a1.getTime() == null || a2.getTime() == null) return false; 088 if (a1 instanceof Section && a2 instanceof Section && ((Section)a1).isToIgnoreStudentConflictsWith(a2.getId())) return false; 089 return a1.getTime().hasIntersection(a2.getTime()); 090 } 091 092 /** 093 * If the two sections are overlapping, return the number of slots of the overlap. 094 * 095 * @param a1 096 * an assignment 097 * @param a2 098 * an assignment 099 * @return the number of overlapping slots against the number of slots of the smallest section 100 */ 101 public int share(SctAssignment a1, SctAssignment a2) { 102 if (!inConflict(a1, a2)) return 0; 103 return a1.getTime().nrSharedDays(a2.getTime()) * a1.getTime().nrSharedHours(a2.getTime()); 104 } 105 106 107 /** 108 * Return number of time overlapping conflicts that are between two enrollments. It 109 * is the total share between pairs of assignments of these enrollments that are in a 110 * time overlap. 111 * 112 * @param e1 113 * an enrollment 114 * @param e2 115 * an enrollment 116 * @return number of time overlapping conflict between given enrollments 117 */ 118 public int nrConflicts(Enrollment e1, Enrollment e2) { 119 if (!e1.getStudent().equals(e2.getStudent())) return 0; 120 if (e1.getRequest() instanceof FreeTimeRequest && e2.getRequest() instanceof FreeTimeRequest) return 0; 121 int cnt = 0; 122 for (SctAssignment s1 : e1.getAssignments()) { 123 for (SctAssignment s2 : e2.getAssignments()) { 124 if (inConflict(s1, s2)) 125 cnt += share(s1, s2); 126 } 127 } 128 return cnt; 129 } 130 131 /** 132 * Return a set of time overlapping conflicts ({@link Conflict} objects) between 133 * given (course) enrollments. 134 * 135 * @param e1 136 * an enrollment 137 * @param e2 138 * an enrollment 139 * @return list of time overlapping conflicts that are between assignment of the 140 * given enrollments 141 */ 142 public Set<Conflict> conflicts(Enrollment e1, Enrollment e2) { 143 Set<Conflict> ret = new HashSet<Conflict>(); 144 if (!e1.getStudent().equals(e2.getStudent())) return ret; 145 if (e1.getRequest() instanceof FreeTimeRequest && e2.getRequest() instanceof FreeTimeRequest) return ret; 146 for (SctAssignment s1 : e1.getAssignments()) { 147 for (SctAssignment s2 : e2.getAssignments()) { 148 if (inConflict(s1, s2)) 149 ret.add(new Conflict(e1.getStudent(), share(s1, s2), e1, s1, e2, s2)); 150 } 151 } 152 return ret; 153 } 154 155 /** 156 * Total sum of all free time conflict of the given enrollment. 157 * @param enrollment given enrollment 158 * @return number of all free time conflicts of the given enrollment 159 */ 160 public int nrFreeTimeConflicts(Enrollment enrollment) { 161 if (enrollment.getRequest() instanceof FreeTimeRequest) return 0; 162 int cnt = 0; 163 for (Request request : enrollment.getStudent().getRequests()) { 164 if (request instanceof FreeTimeRequest) { 165 FreeTimeRequest ft = (FreeTimeRequest)request; 166 for (SctAssignment section: enrollment.getAssignments()) 167 cnt += share(section, ft); 168 } 169 } 170 return cnt; 171 } 172 173 /** 174 * Return a set of free time conflict of the given enrollment. 175 * @param enrollment given enrollment 176 * @return set of all free time conflicts of the given enrollment 177 */ 178 public Set<Conflict> freeTimeConflicts(Enrollment enrollment) { 179 Set<Conflict> ret = new HashSet<Conflict>(); 180 if (enrollment.getRequest() instanceof FreeTimeRequest) return ret; 181 for (Request request : enrollment.getStudent().getRequests()) { 182 if (request instanceof FreeTimeRequest) { 183 FreeTimeRequest ft = (FreeTimeRequest)request; 184 for (SctAssignment section: enrollment.getAssignments()) { 185 if (inConflict(section, ft)) 186 ret.add(new Conflict(enrollment.getStudent(), share(section, ft), enrollment, section, ft.createEnrollment(), ft)); 187 } 188 } 189 } 190 return ret; 191 } 192 193 /** 194 * Total sum of all unavailability time conflict of the given enrollment. 195 * @param enrollment given enrollment 196 * @return number of all unavailability time conflicts of the given enrollment 197 */ 198 public int nrNotAvailableTimeConflicts(Enrollment enrollment) { 199 if (enrollment.getRequest() instanceof FreeTimeRequest) return 0; 200 int cnt = 0; 201 for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities()) 202 for (SctAssignment section: enrollment.getAssignments()) 203 cnt += share(section, unavailability); 204 return cnt; 205 } 206 207 /** 208 * Return a set of unavailability time conflict of the given enrollment. 209 * @param enrollment given enrollment 210 * @return set of all unavailability time conflicts of the given enrollment 211 */ 212 public Set<Conflict> notAvailableTimeConflicts(Enrollment enrollment) { 213 Set<Conflict> ret = new HashSet<Conflict>(); 214 if (enrollment.getRequest() instanceof FreeTimeRequest) return ret; 215 for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities()) 216 for (SctAssignment section: enrollment.getAssignments()) 217 if (inConflict(section, unavailability)) 218 ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, null, unavailability)); 219 return ret; 220 } 221 222 /** 223 * Return a set of free and unavailability time conflict of the given enrollment. 224 * @param enrollment given enrollment 225 * @return set of all free time conflicts of the given enrollment 226 */ 227 public Set<Conflict> conflicts(Enrollment enrollment) { 228 Set<Conflict> ret = new HashSet<Conflict>(); 229 if (enrollment.getRequest() instanceof FreeTimeRequest) return ret; 230 for (Request request : enrollment.getStudent().getRequests()) { 231 if (request instanceof FreeTimeRequest) { 232 FreeTimeRequest ft = (FreeTimeRequest)request; 233 for (SctAssignment section: enrollment.getAssignments()) { 234 if (inConflict(section, ft)) 235 ret.add(new Conflict(enrollment.getStudent(), share(section, ft), enrollment, section, ft.createEnrollment(), ft)); 236 } 237 } 238 } 239 for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities()) 240 for (SctAssignment section: enrollment.getAssignments()) 241 if (inConflict(section, unavailability)) 242 ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, unavailability.createEnrollment(), unavailability)); 243 return ret; 244 } 245 246 /** Actual number of all time overlapping conflicts 247 * @param assignment current assignment 248 * @return total number of time overlapping conflicts 249 **/ 250 public int getTotalNrConflicts(Assignment<Request, Enrollment> assignment) { 251 return getContext(assignment).getTotalNrConflicts(); 252 } 253 254 public void checkTotalNrConflicts(Assignment<Request, Enrollment> assignment) { 255 getContext(assignment).checkTotalNrConflicts(assignment); 256 } 257 258 /** 259 * Return a set of all time overlapping conflicts ({@link Conflict} objects). 260 * @param assignment current assignment 261 * @return set of all time overlapping conflicts in the assignment 262 */ 263 public Set<Conflict> getAllConflicts(Assignment<Request, Enrollment> assignment) { 264 return getContext(assignment).getAllConflicts(); 265 } 266 267 /** 268 * Called before a value is assigned to a variable. 269 */ 270 @Override 271 public void beforeAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) { 272 getContext(assignment).beforeAssigned(assignment, iteration, value); 273 } 274 275 /** 276 * Called after a value is assigned to a variable. 277 */ 278 @Override 279 public void afterAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) { 280 getContext(assignment).afterAssigned(assignment, iteration, value); 281 } 282 283 /** 284 * Called after a value is unassigned from a variable. 285 */ 286 @Override 287 public void afterUnassigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) { 288 getContext(assignment).afterUnassigned(assignment, iteration, value); 289 } 290 291 /** A representation of a time overlapping conflict */ 292 public static class Conflict { 293 private int iShare; 294 private Student iStudent; 295 private SctAssignment iA1, iA2; 296 private Enrollment iE1, iE2; 297 private int iHashCode; 298 299 /** 300 * Constructor 301 * 302 * @param student 303 * related student 304 * @param share number of slots in common between the two conflicting sections 305 * @param e1 first enrollment 306 * @param a1 307 * first conflicting section 308 * @param e2 second enrollment 309 * @param a2 310 * second conflicting section 311 */ 312 public Conflict(Student student, int share, Enrollment e1, SctAssignment a1, Enrollment e2, SctAssignment a2) { 313 iStudent = student; 314 if (a1.compareById(a2) < 0 ) { 315 iA1 = a1; 316 iA2 = a2; 317 iE1 = e1; 318 iE2 = e2; 319 } else { 320 iA1 = a2; 321 iA2 = a1; 322 iE1 = e2; 323 iE2 = e1; 324 } 325 iHashCode = (iStudent.getId() + ":" + iA1.getId() + ":" + iA2.getId()).hashCode(); 326 iShare = share; 327 } 328 329 /** Related student 330 * @return student 331 **/ 332 public Student getStudent() { 333 return iStudent; 334 } 335 336 /** First section 337 * @return first section 338 **/ 339 public SctAssignment getS1() { 340 return iA1; 341 } 342 343 /** Second section 344 * @return second section 345 **/ 346 public SctAssignment getS2() { 347 return iA2; 348 } 349 350 /** First request 351 * @return first request 352 **/ 353 public Request getR1() { 354 return iE1.getRequest(); 355 } 356 357 /** First request weight 358 * @return first request weight 359 **/ 360 public double getR1Weight() { 361 return (iE1.getRequest() == null ? 0.0 : iE1.getRequest().getWeight()); 362 } 363 364 /** Second request weight 365 * @return second request weight 366 **/ 367 public double getR2Weight() { 368 return (iE2.getRequest() == null ? 0.0 : iE2.getRequest().getWeight()); 369 } 370 371 /** Second request 372 * @return second request 373 **/ 374 public Request getR2() { 375 return iE2.getRequest(); 376 } 377 378 /** First enrollment 379 * @return first enrollment 380 **/ 381 public Enrollment getE1() { 382 return iE1; 383 } 384 385 /** Second enrollment 386 * @return second enrollment 387 **/ 388 public Enrollment getE2() { 389 return iE2; 390 } 391 392 @Override 393 public int hashCode() { 394 return iHashCode; 395 } 396 397 /** The number of overlapping slots against the number of slots of the smallest section 398 * @return number of overlapping slots between the two sections 399 **/ 400 public int getShare() { 401 return iShare; 402 } 403 404 @Override 405 public boolean equals(Object o) { 406 if (o == null || !(o instanceof Conflict)) return false; 407 Conflict c = (Conflict) o; 408 return getStudent().equals(c.getStudent()) && getS1().equals(c.getS1()) && getS2().equals(c.getS2()); 409 } 410 411 @Override 412 public String toString() { 413 return getStudent() + ": (s:" + getShare() + ") " + getS1() + " -- " + getS2(); 414 } 415 } 416 417 /** 418 * The set of all conflicts ({@link Conflict} objects) of the given 419 * enrollment and other enrollments that are assigned to the same student. 420 * @param assignment current assignment 421 * @param enrollment given enrollment 422 * @return all conflicts of the given enrollment 423 */ 424 public Set<Conflict> allConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 425 Set<Conflict> ret = new HashSet<Conflict>(); 426 if (enrollment.getRequest() instanceof FreeTimeRequest) return ret; 427 for (Request request : enrollment.getStudent().getRequests()) { 428 if (request.equals(enrollment.getRequest())) continue; 429 Enrollment other = assignment.getValue(request); 430 if (request instanceof FreeTimeRequest) { 431 FreeTimeRequest ft = (FreeTimeRequest)request; 432 ret.addAll(conflicts(enrollment, ft.createEnrollment())); 433 continue; 434 } else if (other != null) { 435 ret.addAll(conflicts(enrollment, other)); 436 } 437 } 438 for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities()) 439 for (SctAssignment section: enrollment.getAssignments()) 440 if (inConflict(section, unavailability)) 441 ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, unavailability.createEnrollment(), unavailability)); 442 return ret; 443 } 444 445 public class TimeOverlapsCounterContext implements AssignmentConstraintContext<Request, Enrollment> { 446 private int iTotalNrConflicts = 0; 447 private Set<Conflict> iAllConflicts = new HashSet<Conflict>(); 448 private Request iOldVariable = null; 449 private Enrollment iUnassignedValue = null; 450 451 public TimeOverlapsCounterContext(Assignment<Request, Enrollment> assignment) { 452 iTotalNrConflicts = countTotalNrConflicts(assignment); 453 if (sDebug) 454 iAllConflicts = computeAllConflicts(assignment); 455 StudentSectioningModelContext cx = ((StudentSectioningModel)getModel()).getContext(assignment); 456 for (Conflict c: computeAllConflicts(assignment)) 457 cx.add(assignment, c); 458 } 459 460 /** 461 * Called when a value is assigned to a variable. Internal number of 462 * time overlapping conflicts is updated, see 463 * {@link TimeOverlapsCounter#getTotalNrConflicts(Assignment)}. 464 */ 465 @Override 466 public void assigned(Assignment<Request, Enrollment> assignment, Enrollment value) { 467 StudentSectioningModelContext cx = ((StudentSectioningModel)getModel()).getContext(assignment); 468 for (Conflict c: allConflicts(assignment, value)) { 469 iTotalNrConflicts += c.getShare(); 470 cx.add(assignment, c); 471 } 472 if (sDebug) { 473 sLog.debug("A:" + value.variable() + " := " + value); 474 int inc = nrAllConflicts(assignment, value); 475 if (inc != 0) { 476 sLog.debug("-- TOC+" + inc + " A: " + value.variable() + " := " + value); 477 for (Conflict c: allConflicts(assignment, value)) { 478 sLog.debug(" -- " + c); 479 iAllConflicts.add(c); 480 inc -= c.getShare(); 481 } 482 if (inc != 0) { 483 sLog.error("Different number of conflicts for the assigned value (difference: " + inc + ")!"); 484 } 485 } 486 } 487 } 488 489 /** 490 * Called when a value is unassigned from a variable. Internal number of 491 * time overlapping conflicts is updated, see 492 * {@link TimeOverlapsCounter#getTotalNrConflicts(Assignment)}. 493 */ 494 @Override 495 public void unassigned(Assignment<Request, Enrollment> assignment, Enrollment value) { 496 StudentSectioningModelContext cx = ((StudentSectioningModel)getModel()).getContext(assignment); 497 for (Conflict c: allConflicts(assignment, value)) { 498 iTotalNrConflicts -= c.getShare(); 499 cx.remove(assignment, c); 500 } 501 if (sDebug) { 502 sLog.debug("U:" + value.variable() + " := " + value); 503 int dec = nrAllConflicts(assignment, value); 504 if (dec != 0) { 505 sLog.debug("-- TOC-" + dec + " U: " + value.variable() + " := " + value); 506 for (Conflict c: allConflicts(assignment, value)) { 507 sLog.debug(" -- " + c); 508 iAllConflicts.remove(c); 509 dec -= c.getShare(); 510 } 511 if (dec != 0) { 512 sLog.error("Different number of conflicts for the unassigned value (difference: " + dec + ")!"); 513 } 514 } 515 } 516 } 517 518 /** 519 * Called before a value is assigned to a variable. 520 * @param assignment current assignment 521 * @param iteration current iteration 522 * @param value value to be assigned 523 */ 524 public void beforeAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) { 525 if (value != null) { 526 Enrollment old = assignment.getValue(value.variable()); 527 if (old != null) { 528 iUnassignedValue = old; 529 unassigned(assignment, old); 530 } 531 iOldVariable = value.variable(); 532 } 533 } 534 535 /** 536 * Called after a value is assigned to a variable. 537 * @param assignment current assignment 538 * @param iteration current iteration 539 * @param value value that was assigned 540 */ 541 public void afterAssigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) { 542 iOldVariable = null; 543 iUnassignedValue = null; 544 if (value != null) { 545 assigned(assignment, value); 546 } 547 } 548 549 /** 550 * Called after a value is unassigned from a variable. 551 * @param assignment current assignment 552 * @param iteration current iteration 553 * @param value value that was unassigned 554 */ 555 public void afterUnassigned(Assignment<Request, Enrollment> assignment, long iteration, Enrollment value) { 556 if (value != null && !value.equals(iUnassignedValue)) { 557 unassigned(assignment, value); 558 } 559 } 560 561 /** 562 * Return a set of all time overlapping conflicts ({@link Conflict} objects). 563 * @return all conflicts 564 */ 565 public Set<Conflict> getAllConflicts() { 566 return iAllConflicts; 567 } 568 569 /** Actual number of all time overlapping conflicts 570 * @return total number of all conflicts 571 **/ 572 public int getTotalNrConflicts() { 573 return iTotalNrConflicts; 574 } 575 576 public void checkTotalNrConflicts(Assignment<Request, Enrollment> assignment) { 577 int total = countTotalNrConflicts(assignment); 578 if (total != iTotalNrConflicts) { 579 sLog.error("Number of conflicts does not match (actual: " + total + ", count: " + iTotalNrConflicts + ")!"); 580 iTotalNrConflicts = total; 581 if (sDebug) { 582 Set<Conflict> conflicts = computeAllConflicts(assignment); 583 for (Conflict c: conflicts) { 584 if (!iAllConflicts.contains(c)) 585 sLog.debug(" +add+ " + c); 586 } 587 for (Conflict c: iAllConflicts) { 588 if (!conflicts.contains(c)) 589 sLog.debug(" -rem- " + c); 590 } 591 for (Conflict c: conflicts) { 592 for (Conflict d: iAllConflicts) { 593 if (c.equals(d) && c.getShare() != d.getShare()) { 594 sLog.debug(" -dif- " + c + " (other: " + d.getShare() + ")"); 595 } 596 } 597 } 598 iAllConflicts = conflicts; 599 // getSolver().stopSolver(false); 600 } 601 } 602 } 603 604 /** 605 * Compute the actual number of all time overlapping conflicts. Should be equal to 606 * {@link TimeOverlapsCounter#getTotalNrConflicts(Assignment)}. 607 * @param assignment current assignment 608 * @return counted number of all time conflicts in the assignment 609 */ 610 public int countTotalNrConflicts(Assignment<Request, Enrollment> assignment) { 611 int total = 0; 612 for (Request r1 : getModel().variables()) { 613 Enrollment e1 = assignment.getValue(r1); 614 if (e1 == null || r1 instanceof FreeTimeRequest || r1.equals(iOldVariable)) 615 continue; 616 for (Request r2 : r1.getStudent().getRequests()) { 617 Enrollment e2 = assignment.getValue(r2); 618 if (r2 instanceof FreeTimeRequest) { 619 FreeTimeRequest ft = (FreeTimeRequest)r2; 620 total += nrConflicts(e1, ft.createEnrollment()); 621 } else if (e2 != null && r1.getId() < r2.getId() && !r2.equals(iOldVariable)) { 622 total += nrConflicts(e1, e2); 623 } 624 } 625 total += nrNotAvailableTimeConflicts(e1); 626 } 627 return total; 628 } 629 630 /** 631 * Compute a set of all time overlapping conflicts ({@link Conflict} objects). 632 * @param assignment current assignment 633 * @return set of all time conflicts in the assignment 634 */ 635 public Set<Conflict> computeAllConflicts(Assignment<Request, Enrollment> assignment) { 636 Set<Conflict> ret = new HashSet<Conflict>(); 637 for (Request r1 : getModel().variables()) { 638 Enrollment e1 = assignment.getValue(r1); 639 if (e1 == null || r1 instanceof FreeTimeRequest || r1.equals(iOldVariable)) 640 continue; 641 for (Request r2 : r1.getStudent().getRequests()) { 642 Enrollment e2 = assignment.getValue(r2); 643 if (r2 instanceof FreeTimeRequest) { 644 FreeTimeRequest ft = (FreeTimeRequest)r2; 645 ret.addAll(conflicts(e1, ft.createEnrollment())); 646 } else if (e2 != null && r1.getId() < r2.getId() && !r2.equals(iOldVariable)) { 647 ret.addAll(conflicts(e1, e2)); 648 } 649 } 650 for (Unavailability unavailability: e1.getStudent().getUnavailabilities()) 651 for (SctAssignment section: e1.getAssignments()) 652 if (inConflict(section, unavailability)) 653 ret.add(new Conflict(e1.getStudent(), share(section, unavailability), e1, section, unavailability.createEnrollment(), unavailability)); 654 } 655 return ret; 656 } 657 658 /** 659 * The set of all conflicts ({@link Conflict} objects) of the given 660 * enrollment and other enrollments that are assigned to the same student. 661 * @param assignment current assignment 662 * @param enrollment given enrollment 663 * @return set of all conflict of the given enrollment 664 */ 665 public Set<Conflict> allConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 666 Set<Conflict> ret = new HashSet<Conflict>(); 667 if (enrollment.getRequest() instanceof FreeTimeRequest) return ret; 668 for (Request request : enrollment.getStudent().getRequests()) { 669 if (request.equals(enrollment.getRequest())) continue; 670 if (request instanceof FreeTimeRequest) { 671 FreeTimeRequest ft = (FreeTimeRequest)request; 672 ret.addAll(conflicts(enrollment, ft.createEnrollment())); 673 continue; 674 } else if (assignment.getValue(request) != null && !request.equals(iOldVariable)) { 675 ret.addAll(conflicts(enrollment, assignment.getValue(request))); 676 } 677 } 678 for (Unavailability unavailability: enrollment.getStudent().getUnavailabilities()) 679 for (SctAssignment section: enrollment.getAssignments()) 680 if (inConflict(section, unavailability)) 681 ret.add(new Conflict(enrollment.getStudent(), share(section, unavailability), enrollment, section, unavailability.createEnrollment(), unavailability)); 682 return ret; 683 } 684 685 /** 686 * Total sum of all conflict of the given enrollment and other enrollments 687 * that are assigned to the same student. 688 * @param assignment current assignment 689 * @param enrollment given enrollment 690 * @return number of all conflict of the given enrollment 691 */ 692 public int nrAllConflicts(Assignment<Request, Enrollment> assignment, Enrollment enrollment) { 693 if (enrollment.getRequest() instanceof FreeTimeRequest) return 0; 694 int cnt = 0; 695 for (Request request : enrollment.getStudent().getRequests()) { 696 if (request.equals(enrollment.getRequest())) continue; 697 if (request instanceof FreeTimeRequest) { 698 FreeTimeRequest ft = (FreeTimeRequest)request; 699 cnt += nrConflicts(enrollment, ft.createEnrollment()); 700 } else if (assignment.getValue(request) != null && !request.equals(iOldVariable)) { 701 cnt += nrConflicts(enrollment, assignment.getValue(request)); 702 } 703 } 704 cnt += nrNotAvailableTimeConflicts(enrollment); 705 return cnt; 706 } 707 } 708 709 @Override 710 public TimeOverlapsCounterContext createAssignmentContext(Assignment<Request, Enrollment> assignment) { 711 return new TimeOverlapsCounterContext(assignment); 712 } 713}