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