001package net.sf.cpsolver.coursett.model; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.Comparator; 006import java.util.HashSet; 007import java.util.HashMap; 008import java.util.Iterator; 009import java.util.List; 010import java.util.Map; 011import java.util.Set; 012 013import net.sf.cpsolver.coursett.Constants; 014import net.sf.cpsolver.coursett.constraint.ClassLimitConstraint; 015import net.sf.cpsolver.coursett.constraint.DepartmentSpreadConstraint; 016import net.sf.cpsolver.coursett.constraint.FlexibleConstraint; 017import net.sf.cpsolver.coursett.constraint.GroupConstraint; 018import net.sf.cpsolver.coursett.constraint.IgnoreStudentConflictsConstraint; 019import net.sf.cpsolver.coursett.constraint.InstructorConstraint; 020import net.sf.cpsolver.coursett.constraint.JenrlConstraint; 021import net.sf.cpsolver.coursett.constraint.RoomConstraint; 022import net.sf.cpsolver.coursett.constraint.SpreadConstraint; 023import net.sf.cpsolver.coursett.criteria.StudentCommittedConflict; 024import net.sf.cpsolver.coursett.criteria.StudentConflict; 025import net.sf.cpsolver.ifs.constant.ConstantVariable; 026import net.sf.cpsolver.ifs.model.Constraint; 027import net.sf.cpsolver.ifs.model.GlobalConstraint; 028import net.sf.cpsolver.ifs.model.Variable; 029import net.sf.cpsolver.ifs.model.WeakeningConstraint; 030import net.sf.cpsolver.ifs.util.DistanceMetric; 031 032/** 033 * Lecture (variable). 034 * 035 * @version CourseTT 1.2 (University Course Timetabling)<br> 036 * Copyright (C) 2006 - 2010 Tomáš Müller<br> 037 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 038 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 039 * <br> 040 * This library is free software; you can redistribute it and/or modify 041 * it under the terms of the GNU Lesser General Public License as 042 * published by the Free Software Foundation; either version 3 of the 043 * License, or (at your option) any later version. <br> 044 * <br> 045 * This library is distributed in the hope that it will be useful, but 046 * WITHOUT ANY WARRANTY; without even the implied warranty of 047 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 048 * Lesser General Public License for more details. <br> 049 * <br> 050 * You should have received a copy of the GNU Lesser General Public 051 * License along with this library; if not see 052 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 053 */ 054 055public class Lecture extends Variable<Lecture, Placement> implements ConstantVariable { 056 private Long iClassId; 057 private Long iSolverGroupId; 058 private Long iSchedulingSubpartId; 059 private String iName; 060 private Long iDept; 061 private Long iScheduler; 062 private List<TimeLocation> iTimeLocations; 063 private List<RoomLocation> iRoomLocations; 064 private String iNote = null; 065 066 private int iMinClassLimit; 067 private int iMaxClassLimit; 068 private float iRoomToLimitRatio; 069 private int iNrRooms; 070 private int iOrd; 071 private double iWeight = 1.0; 072 073 private Set<Student> iStudents = new HashSet<Student>(); 074 private DepartmentSpreadConstraint iDeptSpreadConstraint = null; 075 private Set<SpreadConstraint> iSpreadConstraints = new HashSet<SpreadConstraint>(); 076 private Set<Constraint<Lecture, Placement>> iWeakeningConstraints = new HashSet<Constraint<Lecture, Placement>>(); 077 private List<InstructorConstraint> iInstructorConstraints = new ArrayList<InstructorConstraint>(); 078 private Set<Long> iIgnoreStudentConflictsWith = null; 079 private ClassLimitConstraint iClassLimitConstraint = null; 080 081 private Lecture iParent = null; 082 private HashMap<Long, List<Lecture>> iChildren = null; 083 private java.util.List<Lecture> iSameSubpartLectures = null; 084 private Configuration iParentConfiguration = null; 085 086 private Set<JenrlConstraint> iActiveJenrls = new HashSet<JenrlConstraint>(); 087 private List<JenrlConstraint> iJenrlConstraints = new ArrayList<JenrlConstraint>(); 088 private HashMap<Lecture, JenrlConstraint> iJenrlConstraintsHash = new HashMap<Lecture, JenrlConstraint>(); 089 private HashMap<Placement, Integer> iCommitedConflicts = new HashMap<Placement, Integer>(); 090 private Set<GroupConstraint> iGroupConstraints = new HashSet<GroupConstraint>(); 091 private Set<GroupConstraint> iHardGroupSoftConstraints = new HashSet<GroupConstraint>(); 092 private Set<GroupConstraint> iCanShareRoomGroupConstraints = new HashSet<GroupConstraint>(); 093 private Set<FlexibleConstraint> iFlexibleGroupConstraints = new HashSet<FlexibleConstraint>(); 094 095 public boolean iCommitted = false; 096 097 public static boolean sSaveMemory = false; 098 public static boolean sAllowBreakHard = false; 099 100 private Integer iCacheMinRoomSize = null; 101 private Integer iCacheMaxRoomSize = null; 102 private Integer iCacheMaxAchievableClassLimit = null; 103 104 /** 105 * Constructor 106 * 107 * @param id 108 * unique identification 109 * @param name 110 * class name 111 * @param timeLocations 112 * set of time locations 113 * @param roomLocations 114 * set of room location 115 * @param initialPlacement 116 * initial placement 117 */ 118 public Lecture(Long id, Long solverGroupId, Long schedulingSubpartId, String name, 119 java.util.List<TimeLocation> timeLocations, java.util.List<RoomLocation> roomLocations, int nrRooms, 120 Placement initialPlacement, int minClassLimit, int maxClassLimit, double room2limitRatio) { 121 super(initialPlacement); 122 iClassId = id; 123 iSchedulingSubpartId = schedulingSubpartId; 124 iTimeLocations = new ArrayList<TimeLocation>(timeLocations); 125 iRoomLocations = new ArrayList<RoomLocation>(roomLocations); 126 iName = name; 127 iMinClassLimit = minClassLimit; 128 iMaxClassLimit = maxClassLimit; 129 iRoomToLimitRatio = (float)room2limitRatio; 130 iNrRooms = nrRooms; 131 iSolverGroupId = solverGroupId; 132 } 133 134 public Lecture(Long id, Long solverGroupId, String name) { 135 super(null); 136 iClassId = id; 137 iSolverGroupId = solverGroupId; 138 iName = name; 139 } 140 141 public Long getSolverGroupId() { 142 return iSolverGroupId; 143 } 144 145 /** 146 * Add active jenrl constraint (active mean that there is at least one 147 * student between its classes) 148 */ 149 public void addActiveJenrl(JenrlConstraint constr) { 150 iActiveJenrls.add(constr); 151 } 152 153 /** 154 * Active jenrl constraints (active mean that there is at least one student 155 * between its classes) 156 */ 157 public Set<JenrlConstraint> activeJenrls() { 158 return iActiveJenrls; 159 } 160 161 /** 162 * Remove active jenrl constraint (active mean that there is at least one 163 * student between its classes) 164 */ 165 public void removeActiveJenrl(JenrlConstraint constr) { 166 iActiveJenrls.remove(constr); 167 } 168 169 /** Class id */ 170 public Long getClassId() { 171 return iClassId; 172 } 173 174 public Long getSchedulingSubpartId() { 175 return iSchedulingSubpartId; 176 } 177 178 /** Class name */ 179 @Override 180 public String getName() { 181 return iName; 182 } 183 184 /** Class id */ 185 @Override 186 public long getId() { 187 return iClassId.longValue(); 188 } 189 190 /** Instructor name */ 191 public List<String> getInstructorNames() { 192 List<String> ret = new ArrayList<String>(); 193 for (InstructorConstraint ic : iInstructorConstraints) { 194 ret.add(ic.getName()); 195 } 196 return ret; 197 } 198 199 public String getInstructorName() { 200 StringBuffer sb = new StringBuffer(); 201 for (InstructorConstraint ic : iInstructorConstraints) { 202 if (sb.length() > 0) 203 sb.append(", "); 204 sb.append(ic.getName()); 205 } 206 return sb.toString(); 207 } 208 209 /** List of enrolled students */ 210 public Set<Student> students() { 211 return iStudents; 212 } 213 214 public double nrWeightedStudents() { 215 double w = 0.0; 216 for (Student s : iStudents) { 217 w += s.getOfferingWeight(getConfiguration()); 218 } 219 return w; 220 } 221 222 /** Add an enrolled student */ 223 public void addStudent(Student student) { 224 if (!iStudents.add(student)) 225 return; 226 if (getAssignment() != null && getModel() != null) 227 getModel().getCriterion(StudentCommittedConflict.class).inc(student.countConflictPlacements(getAssignment())); 228 iCommitedConflicts.clear(); 229 } 230 231 public void removeStudent(Student student) { 232 if (!iStudents.remove(student)) 233 return; 234 if (getAssignment() != null && getModel() != null) 235 if (getAssignment() != null && getModel() != null) 236 getModel().getCriterion(StudentCommittedConflict.class).inc(-student.countConflictPlacements(getAssignment())); 237 iCommitedConflicts.clear(); 238 } 239 240 /** Returns true if the given student is enrolled */ 241 public boolean hasStudent(Student student) { 242 return iStudents.contains(student); 243 } 244 245 /** Set of lectures of the same class (only section is different) */ 246 public void setSameSubpartLectures(java.util.List<Lecture> sameSubpartLectures) { 247 iSameSubpartLectures = sameSubpartLectures; 248 } 249 250 /** Set of lectures of the same class (only section is different) */ 251 public java.util.List<Lecture> sameSubpartLectures() { 252 return iSameSubpartLectures; 253 } 254 255 /** List of students enrolled in this class as well as in the given class */ 256 public Set<Student> sameStudents(Lecture lecture) { 257 JenrlConstraint jenrl = jenrlConstraint(lecture); 258 return (jenrl == null ? new HashSet<Student>() : jenrl.getStudents()); 259 } 260 261 /** List of students of this class in conflict with the given assignment */ 262 public Set<Student> conflictStudents(Placement value) { 263 if (value == null) 264 return new HashSet<Student>(); 265 if (value.equals(getAssignment())) 266 return conflictStudents(); 267 Set<Student> ret = new HashSet<Student>(); 268 for (JenrlConstraint jenrl : jenrlConstraints()) { 269 if (jenrl.jenrl(this, value) > 0) 270 ret.addAll(sameStudents(jenrl.another(this))); 271 } 272 return ret; 273 } 274 275 /** 276 * List of students of this class which are in conflict with any other 277 * assignment 278 */ 279 public Set<Student> conflictStudents() { 280 Set<Student> ret = new HashSet<Student>(); 281 if (getAssignment() == null) 282 return ret; 283 for (JenrlConstraint jenrl : activeJenrls()) { 284 ret.addAll(sameStudents(jenrl.another(this))); 285 } 286 Placement placement = getAssignment(); 287 for (Student student : students()) { 288 if (student.countConflictPlacements(placement) > 0) 289 ret.add(student); 290 } 291 return ret; 292 } 293 294 /** 295 * Lectures different from this one, where it is student conflict of the 296 * given student between this and the lecture 297 */ 298 public List<Lecture> conflictLectures(Student student) { 299 List<Lecture> ret = new ArrayList<Lecture>(); 300 if (getAssignment() == null) 301 return ret; 302 for (JenrlConstraint jenrl : activeJenrls()) { 303 Lecture lect = jenrl.another(this); 304 if (lect.students().contains(student)) 305 ret.add(lect); 306 } 307 return ret; 308 } 309 310 /** True if this lecture is in a student conflict with the given student */ 311 public int isInConflict(Student student) { 312 if (getAssignment() == null) 313 return 0; 314 int ret = 0; 315 for (JenrlConstraint jenrl : activeJenrls()) { 316 Lecture lect = jenrl.another(this); 317 if (lect.students().contains(student)) 318 ret++; 319 } 320 return ret; 321 } 322 323 private void computeValues(List<Placement> values, boolean allowBreakHard, TimeLocation timeLocation, 324 List<RoomLocation> roomLocations, int idx) { 325 if (roomLocations.size() == iNrRooms) { 326 Placement p = new Placement(this, timeLocation, roomLocations); 327 p.setVariable(this); 328 if (sSaveMemory && !isValid(p)) 329 return; 330 if (getInitialAssignment() != null && p.equals(getInitialAssignment())) 331 setInitialAssignment(p); 332 if (getAssignment() != null && getAssignment().equals(p)) 333 iValue = getAssignment(); 334 if (getBestAssignment() != null && getBestAssignment().equals(p)) 335 setBestAssignment(p); 336 values.add(p); 337 return; 338 } 339 for (int i = idx; i < iRoomLocations.size(); i++) { 340 RoomLocation roomLocation = iRoomLocations.get(i); 341 if (!allowBreakHard 342 && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(roomLocation 343 .getPreference()))) 344 continue; 345 346 if (roomLocation.getRoomConstraint() != null 347 && !roomLocation.getRoomConstraint().isAvailable(this, timeLocation, getScheduler())) 348 continue; 349 roomLocations.add(roomLocation); 350 computeValues(values, allowBreakHard, timeLocation, roomLocations, i + 1); 351 roomLocations.remove(roomLocations.size() - 1); 352 } 353 } 354 355 /** Domain -- all combinations of room and time locations */ 356 public List<Placement> computeValues(boolean allowBreakHard) { 357 List<Placement> values = new ArrayList<Placement>(iRoomLocations.size() * iTimeLocations.size()); 358 for (TimeLocation timeLocation : iTimeLocations) { 359 if (!allowBreakHard 360 && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(timeLocation 361 .getPreference()))) 362 continue; 363 if (timeLocation.getPreference() > 500) 364 continue; 365 boolean notAvailable = false; 366 for (InstructorConstraint ic : getInstructorConstraints()) { 367 if (!ic.isAvailable(this, timeLocation)) { 368 notAvailable = true; 369 break; 370 } 371 } 372 if (notAvailable) 373 continue; 374 if (iNrRooms == 0) { 375 Placement p = new Placement(this, timeLocation, (RoomLocation) null); 376 for (InstructorConstraint ic : getInstructorConstraints()) { 377 if (!ic.isAvailable(this, p)) { 378 notAvailable = true; 379 break; 380 } 381 } 382 if (notAvailable) 383 continue; 384 p.setVariable(this); 385 if (sSaveMemory && !isValid(p)) 386 continue; 387 if (getInitialAssignment() != null && p.equals(getInitialAssignment())) 388 setInitialAssignment(p); 389 if (getAssignment() != null && getAssignment().equals(p)) 390 iValue = getAssignment(); 391 if (getBestAssignment() != null && getBestAssignment().equals(p)) 392 setBestAssignment(p); 393 values.add(p); 394 } else if (iNrRooms == 1) { 395 for (RoomLocation roomLocation : iRoomLocations) { 396 if (!allowBreakHard 397 && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(roomLocation 398 .getPreference()))) 399 continue; 400 if (roomLocation.getPreference() > 500) 401 continue; 402 if (roomLocation.getRoomConstraint() != null 403 && !roomLocation.getRoomConstraint().isAvailable(this, timeLocation, getScheduler())) 404 continue; 405 Placement p = new Placement(this, timeLocation, roomLocation); 406 p.setVariable(this); 407 if (sSaveMemory && !isValid(p)) 408 continue; 409 if (getInitialAssignment() != null && p.equals(getInitialAssignment())) 410 setInitialAssignment(p); 411 if (getAssignment() != null && getAssignment().equals(p)) 412 iValue = getAssignment(); 413 if (getBestAssignment() != null && getBestAssignment().equals(p)) 414 setBestAssignment(p); 415 values.add(p); 416 } 417 } else { 418 computeValues(values, allowBreakHard, timeLocation, new ArrayList<RoomLocation>(iNrRooms), 0); 419 } 420 } 421 return values; 422 } 423 424 public void clearValueCache() { 425 super.setValues(null); 426 } 427 428 /** All values */ 429 @Override 430 public List<Placement> values() { 431 if (super.values() == null) { 432 if (getInitialAssignment() != null && iTimeLocations.size() == 1 && iRoomLocations.size() == getNrRooms()) { 433 List<Placement> values = new ArrayList<Placement>(1); 434 values.add(getInitialAssignment()); 435 setValues(values); 436 } else { 437 if (isCommitted() || !sSaveMemory) 438 setValues(computeValues(sAllowBreakHard)); 439 } 440 } 441 if (isCommitted()) 442 return super.values(); 443 if (sSaveMemory) { 444 return computeValues(sAllowBreakHard); 445 } else 446 return super.values(); 447 } 448 449 @Override 450 public boolean equals(Object o) { 451 if (o == null || !(o instanceof Lecture)) 452 return false; 453 return getClassId().equals(((Lecture) o).getClassId()); 454 } 455 456 /** Best time preference of this lecture */ 457 private Double iBestTimePreferenceCache = null; 458 459 public double getBestTimePreference() { 460 if (iBestTimePreferenceCache == null) { 461 double ret = Double.MAX_VALUE; 462 for (TimeLocation time : iTimeLocations) { 463 ret = Math.min(ret, time.getNormalizedPreference()); 464 } 465 iBestTimePreferenceCache = new Double(ret); 466 } 467 return iBestTimePreferenceCache.doubleValue(); 468 } 469 470 /** Best room preference of this lecture */ 471 public int getBestRoomPreference() { 472 int ret = Integer.MAX_VALUE; 473 for (RoomLocation room : iRoomLocations) { 474 ret = Math.min(ret, room.getPreference()); 475 } 476 return ret; 477 } 478 479 /** 480 * Number of student conflicts caused by the given assignment of this 481 * lecture 482 */ 483 public int countStudentConflicts(Placement value) { 484 int studentConflictsSum = 0; 485 for (JenrlConstraint jenrl : jenrlConstraints()) { 486 studentConflictsSum += jenrl.jenrl(this, value); 487 } 488 return studentConflictsSum; 489 } 490 491 public int countStudentConflictsOfTheSameProblem(Placement value) { 492 int studentConflictsSum = 0; 493 for (JenrlConstraint jenrl : jenrlConstraints()) { 494 if (!jenrl.isOfTheSameProblem()) 495 continue; 496 studentConflictsSum += jenrl.jenrl(this, value); 497 } 498 return studentConflictsSum; 499 } 500 501 public int countHardStudentConflicts(Placement value) { 502 int studentConflictsSum = 0; 503 if (!isSingleSection()) 504 return 0; 505 for (JenrlConstraint jenrl : jenrlConstraints()) { 506 if (!jenrl.areStudentConflictsHard()) 507 continue; 508 studentConflictsSum += jenrl.jenrl(this, value); 509 } 510 return studentConflictsSum; 511 } 512 513 public int countCommittedStudentConflictsOfTheSameProblem(Placement value) { 514 int studentConflictsSum = 0; 515 for (JenrlConstraint jenrl : jenrlConstraints()) { 516 if (!jenrl.isOfTheSameProblem()) 517 continue; 518 if (!jenrl.areStudentConflictsCommitted()) 519 continue; 520 studentConflictsSum += jenrl.jenrl(this, value); 521 } 522 return studentConflictsSum; 523 } 524 525 public int countCommittedStudentConflicts(Placement value) { 526 int studentConflictsSum = 0; 527 for (JenrlConstraint jenrl : jenrlConstraints()) { 528 if (!jenrl.areStudentConflictsCommitted()) 529 continue; 530 studentConflictsSum += jenrl.jenrl(this, value); 531 } 532 return studentConflictsSum; 533 } 534 535 public int countHardStudentConflictsOfTheSameProblem(Placement value) { 536 int studentConflictsSum = 0; 537 for (JenrlConstraint jenrl : jenrlConstraints()) { 538 if (!jenrl.isOfTheSameProblem()) 539 continue; 540 if (!jenrl.areStudentConflictsHard()) 541 continue; 542 studentConflictsSum += jenrl.jenrl(this, value); 543 } 544 return studentConflictsSum; 545 } 546 547 public int countDistanceStudentConflicts(Placement value) { 548 int studentConflictsSum = 0; 549 for (JenrlConstraint jenrl : jenrlConstraints()) { 550 if (!jenrl.areStudentConflictsDistance(value)) 551 continue; 552 studentConflictsSum += jenrl.jenrl(this, value); 553 } 554 return studentConflictsSum; 555 } 556 557 public int countDistanceStudentConflictsOfTheSameProblem(Placement value) { 558 int studentConflictsSum = 0; 559 for (JenrlConstraint jenrl : jenrlConstraints()) { 560 if (!jenrl.isOfTheSameProblem()) 561 continue; 562 if (!jenrl.areStudentConflictsDistance(value)) 563 continue; 564 studentConflictsSum += jenrl.jenrl(this, value); 565 } 566 return studentConflictsSum; 567 } 568 569 private DistanceMetric getDistanceMetric() { 570 return ((TimetableModel)getModel()).getDistanceMetric(); 571 } 572 573 /** 574 * Number of student conflicts caused by the initial assignment of this 575 * lecture 576 */ 577 public int countInitialStudentConflicts() { 578 Placement value = getInitialAssignment(); 579 if (value == null) 580 return 0; 581 int studentConflictsSum = 0; 582 for (JenrlConstraint jenrl : jenrlConstraints()) { 583 Lecture another = jenrl.another(this); 584 if (another.getInitialAssignment() != null) 585 if (JenrlConstraint.isInConflict(value, another.getInitialAssignment(), getDistanceMetric())) 586 studentConflictsSum += jenrl.getJenrl(); 587 } 588 return studentConflictsSum; 589 } 590 591 /** 592 * Table of student conflicts caused by the initial assignment of this 593 * lecture in format (another lecture, number) 594 */ 595 public Map<Lecture, Long> getInitialStudentConflicts() { 596 Placement value = getInitialAssignment(); 597 if (value == null) 598 return null; 599 Map<Lecture, Long> ret = new HashMap<Lecture, Long>(); 600 for (JenrlConstraint jenrl : jenrlConstraints()) { 601 Lecture another = jenrl.another(this); 602 if (another.getInitialAssignment() != null) 603 if (JenrlConstraint.isInConflict(value, another.getInitialAssignment(), getDistanceMetric())) 604 ret.put(another, jenrl.getJenrl()); 605 } 606 return ret; 607 } 608 609 /** 610 * List of student conflicts caused by the initial assignment of this 611 * lecture 612 */ 613 public Set<Student> initialStudentConflicts() { 614 Placement value = getInitialAssignment(); 615 if (value == null) 616 return null; 617 HashSet<Student> ret = new HashSet<Student>(); 618 for (JenrlConstraint jenrl : jenrlConstraints()) { 619 Lecture another = jenrl.another(this); 620 if (another.getInitialAssignment() != null) 621 if (JenrlConstraint.isInConflict(value, another.getInitialAssignment(), getDistanceMetric())) 622 ret.addAll(sameStudents(another)); 623 } 624 return ret; 625 } 626 627 @Override 628 public void addContstraint(Constraint<Lecture, Placement> constraint) { 629 super.addContstraint(constraint); 630 631 if (constraint instanceof WeakeningConstraint) 632 iWeakeningConstraints.add(constraint); 633 634 if (constraint instanceof FlexibleConstraint) 635 iFlexibleGroupConstraints.add((FlexibleConstraint) constraint); 636 637 if (constraint instanceof JenrlConstraint) { 638 JenrlConstraint jenrl = (JenrlConstraint) constraint; 639 Lecture another = jenrl.another(this); 640 if (another != null) { 641 iJenrlConstraints.add(jenrl); 642 another.iJenrlConstraints.add(jenrl); 643 iJenrlConstraintsHash.put(another, (JenrlConstraint) constraint); 644 another.iJenrlConstraintsHash.put(this, (JenrlConstraint) constraint); 645 } 646 } else if (constraint instanceof DepartmentSpreadConstraint) 647 iDeptSpreadConstraint = (DepartmentSpreadConstraint) constraint; 648 else if (constraint instanceof SpreadConstraint) 649 iSpreadConstraints.add((SpreadConstraint) constraint); 650 else if (constraint instanceof InstructorConstraint) { 651 InstructorConstraint ic = (InstructorConstraint) constraint; 652 if (ic.getResourceId() != null && ic.getResourceId().longValue() > 0) 653 iInstructorConstraints.add(ic); 654 } else if (constraint instanceof ClassLimitConstraint) 655 iClassLimitConstraint = (ClassLimitConstraint) constraint; 656 else if (constraint instanceof GroupConstraint) { 657 GroupConstraint gc = (GroupConstraint) constraint; 658 if (gc.canShareRoom()) { 659 iCanShareRoomGroupConstraints.add((GroupConstraint) constraint); 660 } else { 661 iGroupConstraints.add((GroupConstraint) constraint); 662 if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(gc.getPreference())) 663 || Constants.sPreferenceRequired.equals(Constants 664 .preferenceLevel2preference(gc.getPreference()))) 665 iHardGroupSoftConstraints.add((GroupConstraint) constraint); 666 } 667 } 668 } 669 670 @Override 671 public void removeContstraint(Constraint<Lecture, Placement> constraint) { 672 super.removeContstraint(constraint); 673 674 if (constraint instanceof WeakeningConstraint) 675 iWeakeningConstraints.remove(constraint); 676 677 if (constraint instanceof FlexibleConstraint) 678 iFlexibleGroupConstraints.remove(constraint); 679 680 if (constraint instanceof JenrlConstraint) { 681 JenrlConstraint jenrl = (JenrlConstraint) constraint; 682 Lecture another = jenrl.another(this); 683 if (another != null) { 684 iJenrlConstraints.remove(jenrl); 685 another.iJenrlConstraints.remove(jenrl); 686 iJenrlConstraintsHash.remove(another); 687 another.iJenrlConstraintsHash.remove(this); 688 } 689 } else if (constraint instanceof GroupConstraint) { 690 iCanShareRoomGroupConstraints.remove(constraint); 691 iHardGroupSoftConstraints.remove(constraint); 692 iGroupConstraints.remove(constraint); 693 } else if (constraint instanceof DepartmentSpreadConstraint) 694 iDeptSpreadConstraint = null; 695 else if (constraint instanceof SpreadConstraint) 696 iSpreadConstraints.remove(constraint); 697 else if (constraint instanceof InstructorConstraint) 698 iInstructorConstraints.remove(constraint); 699 else if (constraint instanceof ClassLimitConstraint) 700 iClassLimitConstraint = null; 701 } 702 703 /** All JENRL constraints of this lecture */ 704 public JenrlConstraint jenrlConstraint(Lecture another) { 705 /* 706 * for (Enumeration e=iJenrlConstraints.elements();e.hasMoreElements();) 707 * { JenrlConstraint jenrl = (JenrlConstraint)e.nextElement(); if 708 * (jenrl.another(this).equals(another)) return jenrl; } return null; 709 */ 710 return iJenrlConstraintsHash.get(another); 711 } 712 713 public List<JenrlConstraint> jenrlConstraints() { 714 return iJenrlConstraints; 715 } 716 717 public int minClassLimit() { 718 return iMinClassLimit; 719 } 720 721 public int maxClassLimit() { 722 return iMaxClassLimit; 723 } 724 725 public int maxAchievableClassLimit() { 726 if (iCacheMaxAchievableClassLimit != null) 727 return iCacheMaxAchievableClassLimit.intValue(); 728 729 int maxAchievableClassLimit = Math.min(maxClassLimit(), (int) Math.floor(maxRoomSize() / roomToLimitRatio())); 730 731 if (hasAnyChildren()) { 732 733 for (Long subpartId: getChildrenSubpartIds()) { 734 int maxAchievableChildrenLimit = 0; 735 736 for (Lecture child : getChildren(subpartId)) { 737 maxAchievableChildrenLimit += child.maxAchievableClassLimit(); 738 } 739 740 maxAchievableClassLimit = Math.min(maxAchievableClassLimit, maxAchievableChildrenLimit); 741 } 742 } 743 744 maxAchievableClassLimit = Math.max(minClassLimit(), maxAchievableClassLimit); 745 iCacheMaxAchievableClassLimit = new Integer(maxAchievableClassLimit); 746 return maxAchievableClassLimit; 747 } 748 749 public int classLimit() { 750 if (minClassLimit() == maxClassLimit()) 751 return minClassLimit(); 752 return classLimit(null, null); 753 } 754 755 public int classLimit(Placement assignment, Set<Placement> conflicts) { 756 Placement a = getAssignment(); 757 if (assignment != null && assignment.variable().equals(this)) 758 a = assignment; 759 if (conflicts != null && a != null && conflicts.contains(a)) 760 a = null; 761 int classLimit = (a == null ? maxAchievableClassLimit() : Math.min(maxClassLimit(), (int) Math.floor(a.getRoomSize() / roomToLimitRatio()))); 762 763 if (!hasAnyChildren()) 764 return classLimit; 765 766 for (Long subpartId: getChildrenSubpartIds()) { 767 int childrenClassLimit = 0; 768 769 for (Lecture child : getChildren(subpartId)) { 770 childrenClassLimit += child.classLimit(assignment, conflicts); 771 } 772 773 classLimit = Math.min(classLimit, childrenClassLimit); 774 } 775 776 return Math.max(minClassLimit(), classLimit); 777 } 778 779 public double roomToLimitRatio() { 780 return iRoomToLimitRatio; 781 } 782 783 public int minRoomUse() { 784 return (int) Math.ceil(iMinClassLimit * iRoomToLimitRatio); 785 } 786 787 public int maxRoomUse() { 788 return (int) Math.ceil(iMaxClassLimit * iRoomToLimitRatio); 789 } 790 791 @Override 792 public String toString() { 793 return getName(); 794 } 795 796 public String getValuesString() { 797 StringBuffer sb = new StringBuffer(); 798 for (Placement p : values()) { 799 if (sb.length() > 0) 800 sb.append(", "); 801 sb.append(p.getName()); 802 } 803 return sb.toString(); 804 } 805 806 /** Controlling Course Offering Department */ 807 public Long getDepartment() { 808 return iDept; 809 } 810 811 /** Controlling Course Offering Department */ 812 public void setDepartment(Long dept) { 813 iDept = dept; 814 } 815 816 /** Scheduler (Managing Department) */ 817 public Long getScheduler() { 818 return iScheduler; 819 } 820 821 /** Scheduler (Managing Department) */ 822 public void setScheduler(Long scheduler) { 823 iScheduler = scheduler; 824 } 825 826 /** Departmental spreading constraint */ 827 public DepartmentSpreadConstraint getDeptSpreadConstraint() { 828 return iDeptSpreadConstraint; 829 } 830 831 /** Instructor constraint */ 832 public List<InstructorConstraint> getInstructorConstraints() { 833 return iInstructorConstraints; 834 } 835 836 public ClassLimitConstraint getClassLimitConstraint() { 837 return iClassLimitConstraint; 838 } 839 840 public Set<SpreadConstraint> getSpreadConstraints() { 841 return iSpreadConstraints; 842 } 843 844 public Set<FlexibleConstraint> getFlexibleGroupConstraints() { 845 return iFlexibleGroupConstraints; 846 } 847 848 public Set<Constraint<Lecture, Placement>> getWeakeningConstraints() { 849 return iWeakeningConstraints; 850 } 851 852 /** All room locations */ 853 public List<RoomLocation> roomLocations() { 854 return iRoomLocations; 855 } 856 857 /** All time locations */ 858 public List<TimeLocation> timeLocations() { 859 return iTimeLocations; 860 } 861 862 public int nrTimeLocations() { 863 int ret = 0; 864 for (TimeLocation time : iTimeLocations) { 865 if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(time.getPreference()))) 866 ret++; 867 } 868 return ret; 869 } 870 871 public int nrRoomLocations() { 872 int ret = 0; 873 for (RoomLocation room : iRoomLocations) { 874 if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(room.getPreference()))) 875 ret++; 876 } 877 return ret; 878 } 879 880 public int nrValues() { 881 int ret = 0; 882 for (Placement placement : values()) { 883 if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(placement 884 .getRoomPreference())) 885 && !Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(placement 886 .getTimeLocation().getPreference()))) 887 ret++; 888 } 889 return ret; 890 } 891 892 public int nrValues(TimeLocation time) { 893 int ret = 0; 894 for (RoomLocation room : iRoomLocations) { 895 if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(room.getPreference())) 896 && (room.getRoomConstraint() == null || room.getRoomConstraint().isAvailable(this, time, 897 getScheduler()))) 898 ret++; 899 } 900 return ret; 901 } 902 903 public int nrValues(RoomLocation room) { 904 int ret = 0; 905 for (TimeLocation time : iTimeLocations) { 906 if (!Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(time.getPreference())) 907 && (room.getRoomConstraint() == null || room.getRoomConstraint().isAvailable(this, time, 908 getScheduler()))) 909 ret++; 910 } 911 return ret; 912 } 913 914 public int nrValues(List<RoomLocation> rooms) { 915 int ret = 0; 916 for (TimeLocation time : iTimeLocations) { 917 boolean available = true; 918 for (RoomLocation room : rooms) { 919 if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(time.getPreference())) 920 || (room.getRoomConstraint() != null && !room.getRoomConstraint().isAvailable(this, time, 921 getScheduler()))) 922 available = false; 923 } 924 if (available) 925 ret++; 926 } 927 return ret; 928 } 929 930 public boolean allowBreakHard() { 931 return sAllowBreakHard; 932 } 933 934 public int getNrRooms() { 935 return iNrRooms; 936 } 937 938 public Lecture getParent() { 939 return iParent; 940 } 941 942 public void setParent(Lecture parent) { 943 iParent = parent; 944 iParent.addChild(this); 945 } 946 947 public boolean hasParent() { 948 return (iParent != null); 949 } 950 951 public boolean hasChildren(Long subpartId) { 952 return (iChildren != null && iChildren.get(subpartId) != null && !iChildren.get(subpartId).isEmpty()); 953 } 954 955 public boolean hasAnyChildren() { 956 return (iChildren != null && !iChildren.isEmpty()); 957 } 958 959 public List<Lecture> getChildren(Long subpartId) { 960 return iChildren.get(subpartId); 961 } 962 963 public Set<Long> getChildrenSubpartIds() { 964 return (iChildren == null ? null : iChildren.keySet()); 965 } 966 967 private void addChild(Lecture child) { 968 if (iChildren == null) 969 iChildren = new HashMap<Long, List<Lecture>>(); 970 List<Lecture> childrenThisSubpart = iChildren.get(child.getSchedulingSubpartId()); 971 if (childrenThisSubpart == null) { 972 childrenThisSubpart = new ArrayList<Lecture>(); 973 iChildren.put(child.getSchedulingSubpartId(), childrenThisSubpart); 974 } 975 childrenThisSubpart.add(child); 976 } 977 978 public boolean isSingleSection() { 979 return (iSameSubpartLectures == null || iSameSubpartLectures.size() <= 1); 980 /* 981 if (iParent == null) 982 return (iSameSubpartLectures == null || iSameSubpartLectures.size() <= 1); 983 return (iParent.getChildren(getSchedulingSubpartId()).size() <= 1); 984 */ 985 } 986 987 public java.util.List<Lecture> sameStudentsLectures() { 988 return (hasParent() ? getParent().getChildren(getSchedulingSubpartId()) : sameSubpartLectures()); 989 } 990 991 public Lecture getChild(Student student, Long subpartId) { 992 if (!hasAnyChildren()) 993 return null; 994 List<Lecture> children = getChildren(subpartId); 995 if (children == null) 996 return null; 997 for (Lecture child : children) { 998 if (child.students().contains(student)) 999 return child; 1000 } 1001 return null; 1002 } 1003 1004 public int getCommitedConflicts(Placement placement) { 1005 Integer ret = iCommitedConflicts.get(placement); 1006 if (ret == null) { 1007 ret = new Integer(placement.getCommitedConflicts()); 1008 iCommitedConflicts.put(placement, ret); 1009 } 1010 return ret.intValue(); 1011 } 1012 1013 public Set<GroupConstraint> hardGroupSoftConstraints() { 1014 return iHardGroupSoftConstraints; 1015 } 1016 1017 public Set<GroupConstraint> groupConstraints() { 1018 return iGroupConstraints; 1019 } 1020 1021 public int minRoomSize() { 1022 if (iCacheMinRoomSize != null) 1023 return iCacheMinRoomSize.intValue(); 1024 if (getNrRooms() <= 1) { 1025 int min = Integer.MAX_VALUE; 1026 for (RoomLocation r : roomLocations()) { 1027 if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2) 1028 min = Math.min(min, r.getRoomSize()); 1029 } 1030 iCacheMinRoomSize = new Integer(min); 1031 return min; 1032 } else { 1033 List<RoomLocation> rooms = new ArrayList<RoomLocation>(); 1034 for (RoomLocation r: roomLocations()) 1035 if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2) 1036 rooms.add(r); 1037 Collections.sort(rooms, new Comparator<RoomLocation>() { 1038 @Override 1039 public int compare(RoomLocation r1, RoomLocation r2) { 1040 if (r1.getRoomSize() < r2.getRoomSize()) return -1; 1041 if (r1.getRoomSize() > r2.getRoomSize()) return 1; 1042 return r1.compareTo(r2); 1043 } 1044 }); 1045 int min = rooms.isEmpty() ? 0 : rooms.get(Math.min(getNrRooms(), rooms.size()) - 1).getRoomSize(); 1046 iCacheMinRoomSize = new Integer(min); 1047 return min; 1048 } 1049 } 1050 1051 public int maxRoomSize() { 1052 if (iCacheMaxRoomSize != null) 1053 return iCacheMaxRoomSize.intValue(); 1054 if (getNrRooms() <= 1) { 1055 int max = Integer.MIN_VALUE; 1056 for (RoomLocation r : roomLocations()) { 1057 if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2) 1058 max = Math.max(max, r.getRoomSize()); 1059 } 1060 iCacheMaxRoomSize = new Integer(max); 1061 return max; 1062 } else { 1063 List<RoomLocation> rooms = new ArrayList<RoomLocation>(); 1064 for (RoomLocation r: roomLocations()) 1065 if (r.getPreference() <= Constants.sPreferenceLevelProhibited / 2) rooms.add(r); 1066 Collections.sort(rooms, new Comparator<RoomLocation>() { 1067 @Override 1068 public int compare(RoomLocation r1, RoomLocation r2) { 1069 if (r1.getRoomSize() > r2.getRoomSize()) return -1; 1070 if (r1.getRoomSize() < r2.getRoomSize()) return 1; 1071 return r1.compareTo(r2); 1072 } 1073 }); 1074 int max = rooms.isEmpty() ? 0 : rooms.get(Math.min(getNrRooms(), rooms.size()) - 1).getRoomSize(); 1075 iCacheMaxRoomSize = new Integer(max); 1076 return max; 1077 } 1078 } 1079 1080 public boolean canShareRoom() { 1081 return (!iCanShareRoomGroupConstraints.isEmpty()); 1082 } 1083 1084 public boolean canShareRoom(Lecture other) { 1085 if (other.equals(this)) 1086 return true; 1087 for (GroupConstraint gc : iCanShareRoomGroupConstraints) { 1088 if (gc.variables().contains(other)) 1089 return true; 1090 } 1091 return false; 1092 } 1093 1094 public Set<GroupConstraint> canShareRoomConstraints() { 1095 return iCanShareRoomGroupConstraints; 1096 } 1097 1098 public boolean isSingleton() { 1099 return values().size() == 1; 1100 } 1101 1102 public boolean isValid(Placement placement) { 1103 TimetableModel model = (TimetableModel) getModel(); 1104 if (model == null) 1105 return true; 1106 if (model.hasConstantVariables()) { 1107 for (Placement confPlacement : model.conflictValuesSkipWeakeningConstraints(placement)) { 1108 Lecture lecture = confPlacement.variable(); 1109 if (lecture.isCommitted()) 1110 return false; 1111 if (confPlacement.equals(placement)) 1112 return false; 1113 } 1114 } else { 1115 Set<Placement> conflicts = new HashSet<Placement>(); 1116 for (Constraint<Lecture, Placement> constraint : hardConstraints()) { 1117 if (constraint instanceof WeakeningConstraint) continue; 1118 constraint.computeConflicts(placement, conflicts); 1119 } 1120 for (GlobalConstraint<Lecture, Placement> constraint : model.globalConstraints()) { 1121 if (constraint instanceof WeakeningConstraint) continue; 1122 constraint.computeConflicts(placement, conflicts); 1123 } 1124 if (conflicts.contains(placement)) 1125 return false; 1126 } 1127 return true; 1128 } 1129 1130 public String getNotValidReason(Placement placement) { 1131 TimetableModel model = (TimetableModel) getModel(); 1132 if (model == null) 1133 return "no model for class " + getName(); 1134 Map<Constraint<Lecture, Placement>, Set<Placement>> conflictConstraints = model.conflictConstraints(placement); 1135 for (Map.Entry<Constraint<Lecture, Placement>, Set<Placement>> entry : conflictConstraints.entrySet()) { 1136 Constraint<Lecture, Placement> constraint = entry.getKey(); 1137 Set<Placement> conflicts = entry.getValue(); 1138 String cname = constraint.getName(); 1139 if (constraint instanceof RoomConstraint) { 1140 cname = "Room " + constraint.getName(); 1141 } else if (constraint instanceof InstructorConstraint) { 1142 cname = "Instructor " + constraint.getName(); 1143 } else if (constraint instanceof GroupConstraint) { 1144 cname = "Distribution " + constraint.getName(); 1145 } else if (constraint instanceof DepartmentSpreadConstraint) { 1146 cname = "Balancing of department " + constraint.getName(); 1147 } else if (constraint instanceof SpreadConstraint) { 1148 cname = "Same subpart spread " + constraint.getName(); 1149 } else if (constraint instanceof ClassLimitConstraint) { 1150 cname = "Class limit " + constraint.getName(); 1151 } 1152 for (Placement confPlacement : conflicts) { 1153 Lecture lecture = confPlacement.variable(); 1154 if (lecture.isCommitted()) { 1155 return placement.getLongName() + " conflicts with " + lecture.getName() + " " 1156 + confPlacement.getLongName() + " due to constraint " + cname; 1157 } 1158 if (confPlacement.equals(placement)) { 1159 return placement.getLongName() + " is not valid due to constraint " + cname; 1160 } 1161 } 1162 } 1163 return null; 1164 } 1165 1166 public void purgeInvalidValues(boolean interactiveMode) { 1167 if (isCommitted() || Lecture.sSaveMemory) 1168 return; 1169 TimetableModel model = (TimetableModel) getModel(); 1170 if (model == null) 1171 return; 1172 List<Placement> newValues = new ArrayList<Placement>(values().size()); 1173 for (Placement placement : values()) { 1174 if (placement.isValid()) 1175 newValues.add(placement); 1176 } 1177 if (!interactiveMode && newValues.size() != values().size()) { 1178 for (Iterator<TimeLocation> i = timeLocations().iterator(); i.hasNext();) { 1179 TimeLocation timeLocation = i.next(); 1180 boolean hasPlacement = false; 1181 for (Placement placement : newValues) { 1182 if (timeLocation.equals(placement.getTimeLocation())) { 1183 hasPlacement = true; 1184 break; 1185 } 1186 } 1187 if (!hasPlacement) 1188 i.remove(); 1189 } 1190 for (Iterator<RoomLocation> i = roomLocations().iterator(); i.hasNext();) { 1191 RoomLocation roomLocation = i.next(); 1192 boolean hasPlacement = false; 1193 for (Placement placement : newValues) { 1194 if (placement.isMultiRoom()) { 1195 if (placement.getRoomLocations().contains(roomLocation)) { 1196 hasPlacement = true; 1197 break; 1198 } 1199 } else { 1200 if (roomLocation.equals(placement.getRoomLocation())) { 1201 hasPlacement = true; 1202 break; 1203 } 1204 } 1205 } 1206 if (!hasPlacement) 1207 i.remove(); 1208 } 1209 } 1210 setValues(newValues); 1211 } 1212 1213 public void setCommitted(boolean committed) { 1214 iCommitted = committed; 1215 } 1216 1217 public boolean isCommitted() { 1218 return iCommitted; 1219 } 1220 1221 @Override 1222 public boolean isConstant() { 1223 return iCommitted; 1224 } 1225 1226 public int getSpreadPenalty() { 1227 int spread = 0; 1228 for (SpreadConstraint sc : getSpreadConstraints()) { 1229 spread += sc.getPenalty(); 1230 } 1231 return spread; 1232 } 1233 1234 @Override 1235 public int hashCode() { 1236 return getClassId().hashCode(); 1237 } 1238 1239 public Configuration getConfiguration() { 1240 Lecture lecture = this; 1241 while (lecture.getParent() != null) 1242 lecture = lecture.getParent(); 1243 return lecture.iParentConfiguration; 1244 } 1245 1246 public void setConfiguration(Configuration configuration) { 1247 Lecture lecture = this; 1248 while (lecture.getParent() != null) 1249 lecture = lecture.getParent(); 1250 lecture.iParentConfiguration = configuration; 1251 configuration.addTopLecture(lecture); 1252 } 1253 1254 private int[] iMinMaxRoomPreference = null; 1255 1256 public int[] getMinMaxRoomPreference() { 1257 if (iMinMaxRoomPreference == null) { 1258 if (getNrRooms() <= 0 || roomLocations().isEmpty()) { 1259 iMinMaxRoomPreference = new int[] { 0, 0 }; 1260 } else { 1261 Integer minRoomPref = null, maxRoomPref = null; 1262 for (RoomLocation r : roomLocations()) { 1263 int pref = r.getPreference(); 1264 if (pref >= Constants.sPreferenceLevelRequired / 2 && pref <= Constants.sPreferenceLevelProhibited / 2) { 1265 minRoomPref = (minRoomPref == null ? pref : Math.min(minRoomPref, pref)); 1266 maxRoomPref = (maxRoomPref == null ? pref : Math.max(maxRoomPref, pref)); 1267 } 1268 } 1269 iMinMaxRoomPreference = new int[] { minRoomPref == null ? 0 : minRoomPref, maxRoomPref == null ? 0 : maxRoomPref }; 1270 } 1271 } 1272 return iMinMaxRoomPreference; 1273 } 1274 1275 private double[] iMinMaxTimePreference = null; 1276 1277 public double[] getMinMaxTimePreference() { 1278 if (iMinMaxTimePreference == null) { 1279 Double minTimePref = null, maxTimePref = null; 1280 for (TimeLocation t : timeLocations()) { 1281 double npref = t.getNormalizedPreference(); 1282 int pref = t.getPreference(); 1283 if (pref >= Constants.sPreferenceLevelRequired / 2 && pref <= Constants.sPreferenceLevelProhibited / 2) { 1284 minTimePref = (minTimePref == null ? npref : Math.min(minTimePref, npref)); 1285 maxTimePref = (maxTimePref == null ? npref : Math.max(maxTimePref, npref)); 1286 } 1287 } 1288 iMinMaxTimePreference = new double[] { minTimePref == null ? 0.0 : minTimePref, maxTimePref == null ? 0.0 : maxTimePref }; 1289 } 1290 return iMinMaxTimePreference; 1291 } 1292 1293 public void setOrd(int ord) { 1294 iOrd = ord; 1295 } 1296 1297 public int getOrd() { 1298 return iOrd; 1299 } 1300 1301 @Override 1302 public int compareTo(Lecture o) { 1303 int cmp = Double.compare(getOrd(), o.getOrd()); 1304 if (cmp != 0) 1305 return cmp; 1306 return super.compareTo(o); 1307 } 1308 1309 public String getNote() { 1310 return iNote; 1311 } 1312 1313 public void setNote(String note) { 1314 iNote = note; 1315 } 1316 1317 public boolean areStudentConflictsHard(Lecture other) { 1318 return StudentConflict.hard(this, other); 1319 } 1320 1321 public void clearIgnoreStudentConflictsWithCache() { 1322 iIgnoreStudentConflictsWith = null; 1323 } 1324 1325 /** 1326 * Returns true if there is {@link IgnoreStudentConflictsConstraint} between the two lectures. 1327 */ 1328 public boolean isToIgnoreStudentConflictsWith(Lecture other) { 1329 if (iIgnoreStudentConflictsWith == null) { 1330 iIgnoreStudentConflictsWith = new HashSet<Long>(); 1331 for (Constraint<Lecture, Placement> constraint: constraints()) { 1332 if (constraint instanceof IgnoreStudentConflictsConstraint) 1333 for (Lecture x: constraint.variables()) { 1334 if (!x.equals(this)) iIgnoreStudentConflictsWith.add(x.getClassId()); 1335 } 1336 } 1337 } 1338 return iIgnoreStudentConflictsWith.contains(other.getClassId()); 1339 } 1340 1341 /** 1342 * Get class weight. This weight is used with the criteria. E.g., class that is not meeting all the 1343 * semester can have a lower weight. Defaults to 1.0 1344 */ 1345 public double getWeight() { return iWeight; } 1346 /** 1347 * Set class weight. This weight is used with the criteria. E.g., class that is not meeting all the 1348 * semester can have a lower weight. 1349 */ 1350 public void setWeight(double weight) { iWeight = weight; } 1351}