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