001package org.cpsolver.coursett.model; 002 003import java.util.ArrayList; 004import java.util.Enumeration; 005import java.util.List; 006 007import org.cpsolver.coursett.Constants; 008import org.cpsolver.coursett.constraint.GroupConstraint; 009import org.cpsolver.coursett.constraint.InstructorConstraint; 010import org.cpsolver.coursett.constraint.SpreadConstraint; 011import org.cpsolver.coursett.preference.PreferenceCombination; 012import org.cpsolver.ifs.assignment.Assignment; 013import org.cpsolver.ifs.criteria.Criterion; 014import org.cpsolver.ifs.model.Value; 015import org.cpsolver.ifs.util.DistanceMetric; 016import org.cpsolver.ifs.util.ToolBox; 017 018 019/** 020 * Placement (value). <br> 021 * <br> 022 * It combines room and time location 023 * 024 * @version CourseTT 1.3 (University Course Timetabling)<br> 025 * Copyright (C) 2006 - 2014 Tomáš Müller<br> 026 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 027 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 028 * <br> 029 * This library is free software; you can redistribute it and/or modify 030 * it under the terms of the GNU Lesser General Public License as 031 * published by the Free Software Foundation; either version 3 of the 032 * License, or (at your option) any later version. <br> 033 * <br> 034 * This library is distributed in the hope that it will be useful, but 035 * WITHOUT ANY WARRANTY; without even the implied warranty of 036 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 037 * Lesser General Public License for more details. <br> 038 * <br> 039 * You should have received a copy of the GNU Lesser General Public 040 * License along with this library; if not see 041 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 042 */ 043 044public class Placement extends Value<Lecture, Placement> { 045 private TimeLocation iTimeLocation; 046 private RoomLocation iRoomLocation; 047 private List<RoomLocation> iRoomLocations = null; 048 private Long iAssignmentId = null; 049 private int iHashCode = 0; 050 private Double iTimePenalty = null; 051 private Integer iRoomPenalty = null; 052 053 /** 054 * Constructor 055 * 056 * @param lecture 057 * lecture 058 * @param timeLocation 059 * time location 060 * @param roomLocation 061 * room location 062 */ 063 public Placement(Lecture lecture, TimeLocation timeLocation, RoomLocation roomLocation) { 064 super(lecture); 065 iTimeLocation = timeLocation; 066 iRoomLocation = roomLocation; 067 if (iRoomLocation == null) { 068 iRoomLocations = new ArrayList<RoomLocation>(0); 069 } 070 iHashCode = getName().hashCode(); 071 } 072 073 public Placement(Lecture lecture, TimeLocation timeLocation, java.util.List<RoomLocation> roomLocations) { 074 super(lecture); 075 iTimeLocation = timeLocation; 076 iRoomLocation = (roomLocations.isEmpty() ? null : (RoomLocation) roomLocations.get(0)); 077 if (roomLocations.size() != 1) { 078 iRoomLocations = new ArrayList<RoomLocation>(roomLocations); 079 } 080 if (iRoomLocations != null && iRoomLocations.size() > 1) { 081 boolean hasPreferenceByIndex = false; 082 for (RoomLocation r: iRoomLocations) 083 if (r.hasPreferenceByIndex()) { hasPreferenceByIndex = true; break; } 084 if (hasPreferenceByIndex) 085 fixRoomOrder(0, roomLocations, new RoomLocation[iRoomLocations.size()], PreferenceCombination.getDefault(), null); 086 } 087 iHashCode = getName().hashCode(); 088 } 089 090 private Integer fixRoomOrder(int idx, List<RoomLocation> rooms, RoomLocation[] current, PreferenceCombination preference, Integer bestSoFar) { 091 if (idx == current.length) { 092 if (bestSoFar == null || preference.getPreferenceInt() < bestSoFar) { 093 iRoomLocations.clear(); 094 for (RoomLocation r: current) 095 iRoomLocations.add(r); 096 return preference.getPreferenceInt(); 097 } 098 } else { 099 r: for (RoomLocation r: rooms) { 100 for (int i = 0; i < idx; i++) 101 if (r.equals(current[i])) continue r; 102 PreferenceCombination pc = preference.clonePreferenceCombination(); 103 pc.addPreferenceInt(r.getPreference(idx)); 104 if (!pc.isProhibited()) { 105 current[idx] = r; 106 bestSoFar = fixRoomOrder(idx + 1, rooms, current, pc, bestSoFar); 107 } 108 } 109 } 110 return bestSoFar; 111 } 112 113 /** Time location 114 * @return time of this placement 115 **/ 116 public TimeLocation getTimeLocation() { 117 return iTimeLocation; 118 } 119 120 /** Room location 121 * @return room of this placement 122 **/ 123 public RoomLocation getRoomLocation() { 124 return iRoomLocation; 125 } 126 127 /** Room locations (multi-room placement) 128 * @return rooms of this placement (if there are more than one) 129 **/ 130 public List<RoomLocation> getRoomLocations() { 131 return iRoomLocations; 132 } 133 134 public List<Long> getBuildingIds() { 135 if (isMultiRoom()) { 136 List<Long> ret = new ArrayList<Long>(iRoomLocations.size()); 137 for (RoomLocation r : iRoomLocations) { 138 ret.add(r.getBuildingId()); 139 } 140 return ret; 141 } else { 142 List<Long> ret = new ArrayList<Long>(1); 143 ret.add(iRoomLocation.getBuildingId()); 144 return ret; 145 } 146 } 147 148 public List<Long> getRoomIds() { 149 if (isMultiRoom()) { 150 List<Long> ret = new ArrayList<Long>(iRoomLocations.size()); 151 for (RoomLocation r : iRoomLocations) { 152 ret.add(r.getId()); 153 } 154 return ret; 155 } else { 156 List<Long> ret = new ArrayList<Long>(1); 157 ret.add(iRoomLocation.getId()); 158 return ret; 159 } 160 } 161 162 public List<String> getRoomNames() { 163 if (isMultiRoom()) { 164 List<String> ret = new ArrayList<String>(iRoomLocations.size()); 165 for (RoomLocation r : iRoomLocations) { 166 ret.add(r.getName()); 167 } 168 return ret; 169 } else { 170 List<String> ret = new ArrayList<String>(1); 171 if (iRoomLocation != null) 172 ret.add(iRoomLocation.getName()); 173 return ret; 174 } 175 } 176 177 public List<Integer> getRoomPrefs() { 178 if (isMultiRoom()) { 179 List<Integer> ret = new ArrayList<Integer>(iRoomLocations.size()); 180 int roomIndex = 0; 181 for (RoomLocation r : iRoomLocations) { 182 ret.add(r.getPreference(roomIndex++)); 183 } 184 return ret; 185 } else { 186 List<Integer> ret = new ArrayList<Integer>(1); 187 if (iRoomLocation != null) 188 ret.add(iRoomLocation.getPreference()); 189 return ret; 190 } 191 } 192 193 public boolean isMultiRoom() { 194 return (iRoomLocations != null && iRoomLocations.size() != 1); 195 } 196 197 public RoomLocation getRoomLocation(Long roomId) { 198 if (isMultiRoom()) { 199 for (RoomLocation r : iRoomLocations) { 200 if (r.getId().equals(roomId)) 201 return r; 202 } 203 } else if (iRoomLocation != null && iRoomLocation.getId().equals(roomId)) 204 return iRoomLocation; 205 return null; 206 } 207 208 public int getRoomLocationIndex(Long roomId) { 209 if (isMultiRoom()) { 210 int idx = 0; 211 for (RoomLocation r : iRoomLocations) { 212 if (r.getId().equals(roomId)) 213 return idx; 214 idx ++; 215 } 216 } else if (iRoomLocation != null && iRoomLocation.getId().equals(roomId)) 217 return 0; 218 return -1; 219 } 220 221 public boolean hasRoomLocation(Long roomId) { 222 if (isMultiRoom()) { 223 for (RoomLocation r : iRoomLocations) { 224 if (r.getId().equals(roomId)) 225 return true; 226 } 227 return false; 228 } else 229 return iRoomLocation != null && iRoomLocation.getId().equals(roomId); 230 } 231 232 public String getRoomName(String delim) { 233 if (isMultiRoom()) { 234 StringBuffer sb = new StringBuffer(); 235 for (RoomLocation r : iRoomLocations) { 236 if (sb.length() > 0) 237 sb.append(delim); 238 sb.append(r.getName()); 239 } 240 return sb.toString(); 241 } else { 242 return (getRoomLocation() == null ? "" : getRoomLocation().getName()); 243 } 244 } 245 246 @Override 247 public String getName() { 248 return getName(true); 249 } 250 251 public String getName(boolean useAmPm) { 252 Lecture lecture = variable(); 253 return getTimeLocation().getName(useAmPm) + " " + getRoomName(", ") 254 + (lecture != null && lecture.getInstructorName() != null ? " " + lecture.getInstructorName() : ""); 255 } 256 257 public String getLongName(boolean useAmPm) { 258 Lecture lecture = variable(); 259 if (isMultiRoom()) { 260 StringBuffer sb = new StringBuffer(); 261 for (RoomLocation r : iRoomLocations) { 262 if (sb.length() > 0) 263 sb.append(", "); 264 sb.append(r.getName()); 265 } 266 return getTimeLocation().getLongName(useAmPm) + " " + sb 267 + (lecture != null && lecture.getInstructorName() != null ? " " + lecture.getInstructorName() : ""); 268 } else 269 return getTimeLocation().getLongName(useAmPm) 270 + (getRoomLocation() == null ? "" : " " + getRoomLocation().getName()) 271 + (lecture != null && lecture.getInstructorName() != null ? " " + lecture.getInstructorName() : ""); 272 } 273 274 @Deprecated 275 public String getLongName() { 276 return getLongName(true); 277 } 278 279 public boolean sameRooms(Placement placement) { 280 if (placement.isMultiRoom() != isMultiRoom()) 281 return false; 282 if (isMultiRoom()) { 283 if (placement.getRoomLocations().size() != getRoomLocations().size()) 284 return false; 285 return placement.getRoomLocations().containsAll(getRoomLocations()); 286 } else { 287 if (placement.getRoomLocation() == null) 288 return getRoomLocation() == null; 289 return placement.getRoomLocation().equals(getRoomLocation()); 290 } 291 } 292 293 public boolean shareRooms(Placement placement) { 294 if (isMultiRoom()) { 295 if (placement.isMultiRoom()) { 296 for (RoomLocation rl : getRoomLocations()) { 297 if (rl.getRoomConstraint() == null || !rl.getRoomConstraint().getConstraint()) 298 continue; 299 if (placement.getRoomLocations().contains(rl)) 300 return true; 301 } 302 return false; 303 } else { 304 if (placement.getRoomLocation().getRoomConstraint() == null || !placement.getRoomLocation().getRoomConstraint().getConstraint()) 305 return false; 306 return getRoomLocations().contains(placement.getRoomLocation()); 307 } 308 } else { 309 if (getRoomLocation().getRoomConstraint() == null || !getRoomLocation().getRoomConstraint().getConstraint()) 310 return false; 311 if (placement.isMultiRoom()) { 312 return placement.getRoomLocations().contains(getRoomLocation()); 313 } else { 314 return getRoomLocation().equals(placement.getRoomLocation()); 315 } 316 } 317 } 318 319 public int nrDifferentRooms(Placement placement) { 320 if (isMultiRoom()) { 321 int ret = 0; 322 for (RoomLocation r : getRoomLocations()) { 323 if (!placement.getRoomLocations().contains(r)) 324 ret++; 325 } 326 return ret; 327 } else { 328 return (placement.getRoomLocation().equals(getRoomLocation()) ? 0 : 1); 329 } 330 } 331 332 public int nrDifferentBuildings(Placement placement) { 333 if (isMultiRoom()) { 334 int ret = 0; 335 for (RoomLocation r : getRoomLocations()) { 336 boolean contains = false; 337 for (RoomLocation q : placement.getRoomLocations()) { 338 if (ToolBox.equals(r.getBuildingId(), q.getBuildingId())) 339 contains = true; 340 } 341 if (!contains) 342 ret++; 343 } 344 return ret; 345 } else { 346 return (ToolBox.equals(placement.getRoomLocation().getBuildingId(), getRoomLocation().getBuildingId()) ? 0 347 : 1); 348 } 349 } 350 351 public int sumRoomPreference() { 352 if (isMultiRoom()) { 353 int ret = 0; 354 int roomIndex = 0; 355 for (RoomLocation r : getRoomLocations()) { 356 ret += r.getPreference(roomIndex ++); 357 } 358 return ret; 359 } else { 360 return getRoomLocation().getPreference(); 361 } 362 } 363 364 public int getRoomPreference() { 365 if (isMultiRoom()) { 366 PreferenceCombination p = PreferenceCombination.getDefault(); 367 int roomIndex = 0; 368 for (RoomLocation r : getRoomLocations()) { 369 p.addPreferenceInt(r.getPreference(roomIndex++)); 370 } 371 return p.getPreferenceInt(); 372 } else { 373 return getRoomLocation().getPreference(); 374 } 375 } 376 377 public int getRoomSize() { 378 if (isMultiRoom()) { 379 if (getRoomLocations().isEmpty()) return 0; 380 if (variable() != null && variable().isSplitAttendance()) { 381 int roomSize = 0; 382 for (RoomLocation r : getRoomLocations()) 383 roomSize += r.getRoomSize(); 384 return roomSize; 385 } else { 386 int roomSize = Integer.MAX_VALUE; 387 for (RoomLocation r : getRoomLocations()) { 388 roomSize = Math.min(roomSize, r.getRoomSize()); 389 } 390 return roomSize; 391 } 392 } else { 393 return getRoomLocation().getRoomSize(); 394 } 395 } 396 397 public boolean isHard(Assignment<Lecture, Placement> assignment) { 398 if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(getTimeLocation().getPreference()))) 399 return true; 400 if (isRoomProhibited()) return true; 401 Lecture lecture = variable(); 402 for (GroupConstraint gc : lecture.hardGroupSoftConstraints()) { 403 if (gc.isSatisfied(assignment)) 404 continue; 405 if (Constants.sPreferenceProhibited.equals(gc.getPrologPreference())) 406 return true; 407 if (Constants.sPreferenceRequired.equals(gc.getPrologPreference())) 408 return true; 409 } 410 return false; 411 } 412 413 public boolean isRoomProhibited() { 414 if (isMultiRoom()) { 415 int roomIndex = 0; 416 for (RoomLocation r : getRoomLocations()) { 417 if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(r.getPreference(roomIndex++)))) 418 return true; 419 } 420 } else { 421 if (getRoomLocation() != null && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(getRoomLocation().getPreference()))) 422 return true; 423 } 424 return false; 425 } 426 427 public boolean sameTime(Placement placement) { 428 return placement.getTimeLocation().equals(getTimeLocation()); 429 } 430 431 @Override 432 public boolean equals(Object object) { 433 if (object == null || !(object instanceof Placement)) 434 return false; 435 Placement placement = (Placement) object; 436 if (placement.getId() == getId()) 437 return true; // quick check 438 Lecture lecture = placement.variable(); 439 Lecture thisLecture = variable(); 440 if (lecture != null && thisLecture != null && !lecture.getClassId().equals(thisLecture.getClassId())) 441 return false; 442 if (!sameRooms(placement)) 443 return false; 444 if (!sameTime(placement)) 445 return false; 446 return true; 447 } 448 449 @Override 450 public int hashCode() { 451 return iHashCode; 452 } 453 454 @Override 455 public String toString() { 456 return variable().getName() + " " + getName(); 457 } 458 459 /** Distance between two placements 460 * @param m distance matrix 461 * @param p1 first placement 462 * @param p2 second placement 463 * @return maximal distance in meters between the two placement 464 **/ 465 public static double getDistanceInMeters(DistanceMetric m, Placement p1, Placement p2) { 466 if (p1.isMultiRoom()) { 467 if (p2.isMultiRoom()) { 468 double dist = 0.0; 469 for (RoomLocation r1 : p1.getRoomLocations()) { 470 for (RoomLocation r2 : p2.getRoomLocations()) { 471 dist = Math.max(dist, r1.getDistanceInMeters(m, r2)); 472 } 473 } 474 return dist; 475 } else { 476 if (p2.getRoomLocation() == null) 477 return 0.0; 478 double dist = 0.0; 479 for (RoomLocation r1 : p1.getRoomLocations()) { 480 dist = Math.max(dist, r1.getDistanceInMeters(m, p2.getRoomLocation())); 481 } 482 return dist; 483 } 484 } else if (p2.isMultiRoom()) { 485 if (p1.getRoomLocation() == null) 486 return 0.0; 487 double dist = 0.0; 488 for (RoomLocation r2 : p2.getRoomLocations()) { 489 dist = Math.max(dist, p1.getRoomLocation().getDistanceInMeters(m, r2)); 490 } 491 return dist; 492 } else { 493 if (p1.getRoomLocation() == null || p2.getRoomLocation() == null) 494 return 0.0; 495 return p1.getRoomLocation().getDistanceInMeters(m, p2.getRoomLocation()); 496 } 497 } 498 499 /** Distance between two placements 500 * @param m distance matrix 501 * @param p1 first placement 502 * @param p2 second placement 503 * @return maximal distance in minutes between the two placement 504 **/ 505 public static int getDistanceInMinutes(DistanceMetric m, Placement p1, Placement p2) { 506 if (p1.isMultiRoom()) { 507 if (p2.isMultiRoom()) { 508 int dist = 0; 509 for (RoomLocation r1 : p1.getRoomLocations()) { 510 for (RoomLocation r2 : p2.getRoomLocations()) { 511 dist = Math.max(dist, r1.getDistanceInMinutes(m, r2)); 512 } 513 } 514 return dist; 515 } else { 516 if (p2.getRoomLocation() == null) 517 return 0; 518 int dist = 0; 519 for (RoomLocation r1 : p1.getRoomLocations()) { 520 dist = Math.max(dist, r1.getDistanceInMinutes(m, p2.getRoomLocation())); 521 } 522 return dist; 523 } 524 } else if (p2.isMultiRoom()) { 525 if (p1.getRoomLocation() == null) 526 return 0; 527 int dist = 0; 528 for (RoomLocation r2 : p2.getRoomLocations()) { 529 dist = Math.max(dist, p1.getRoomLocation().getDistanceInMinutes(m, r2)); 530 } 531 return dist; 532 } else { 533 if (p1.getRoomLocation() == null || p2.getRoomLocation() == null) 534 return 0; 535 return p1.getRoomLocation().getDistanceInMinutes(m, p2.getRoomLocation()); 536 } 537 } 538 539 public int getCommitedConflicts() { 540 int ret = 0; 541 Lecture lecture = variable(); 542 for (Student student : lecture.students()) { 543 ret += student.countConflictPlacements(this); 544 } 545 return ret; 546 } 547 548 public Long getAssignmentId() { 549 return iAssignmentId; 550 } 551 552 public void setAssignmentId(Long assignmentId) { 553 iAssignmentId = assignmentId; 554 } 555 556 public boolean canShareRooms(Placement other) { 557 return (variable()).canShareRoom(other.variable()); 558 } 559 560 public boolean isValid() { 561 Lecture lecture = variable(); 562 if (!lecture.isValid(this)) 563 return false; 564 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 565 if (!ic.isAvailable(lecture, this) && ic.isHard()) 566 return false; 567 } 568 if (lecture.getNrRooms() > 0) { 569 if (isMultiRoom()) { 570 for (RoomLocation roomLocation : getRoomLocations()) { 571 if (roomLocation.getRoomConstraint() != null 572 && !roomLocation.getRoomConstraint().isAvailable(lecture, getTimeLocation(), 573 lecture.getScheduler())) 574 return false; 575 } 576 } else { 577 if (getRoomLocation().getRoomConstraint() != null 578 && !getRoomLocation().getRoomConstraint().isAvailable(lecture, getTimeLocation(), 579 lecture.getScheduler())) 580 return false; 581 } 582 } 583 return true; 584 } 585 586 public String getNotValidReason(Assignment<Lecture, Placement> assignment, boolean useAmPm) { 587 Lecture lecture = variable(); 588 String reason = lecture.getNotValidReason(assignment, this, useAmPm); 589 if (reason != null) 590 return reason; 591 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 592 if (!ic.isAvailable(lecture, this) && ic.isHard()) { 593 if (!ic.isAvailable(lecture, getTimeLocation())) { 594 for (Placement c: ic.getUnavailabilities()) { 595 if (c.getTimeLocation().hasIntersection(getTimeLocation()) && !lecture.canShareRoom(c.variable())) 596 return "instructor " + ic.getName() + " not available at " + getTimeLocation().getLongName(useAmPm) + " due to " + c.variable().getName(); 597 } 598 return "instructor " + ic.getName() + " not available at " + getTimeLocation().getLongName(useAmPm); 599 } else 600 return "placement " + getTimeLocation().getLongName(useAmPm) + " " + getRoomName(", ") + " is too far for instructor " + ic.getName(); 601 } 602 } 603 if (lecture.getNrRooms() > 0) { 604 if (isMultiRoom()) { 605 for (RoomLocation roomLocation : getRoomLocations()) { 606 if (roomLocation.getRoomConstraint() != null && !roomLocation.getRoomConstraint().isAvailable(lecture, getTimeLocation(), lecture.getScheduler())) { 607 if (roomLocation.getRoomConstraint().getAvailableArray() != null) { 608 for (Enumeration<Integer> e = getTimeLocation().getSlots(); e.hasMoreElements();) { 609 int slot = e.nextElement(); 610 if (roomLocation.getRoomConstraint().getAvailableArray()[slot] != null) { 611 for (Placement c : roomLocation.getRoomConstraint().getAvailableArray()[slot]) { 612 if (c.getTimeLocation().hasIntersection(getTimeLocation()) && !lecture.canShareRoom(c.variable())) { 613 return "room " + roomLocation.getName() + " not available at " + getTimeLocation().getLongName(useAmPm) + " due to " + c.variable().getName(); 614 } 615 } 616 } 617 } 618 } 619 return "room " + roomLocation.getName() + " not available at " + getTimeLocation().getLongName(useAmPm); 620 } 621 } 622 } else { 623 if (getRoomLocation().getRoomConstraint() != null && !getRoomLocation().getRoomConstraint().isAvailable(lecture, getTimeLocation(), lecture.getScheduler())) 624 if (getRoomLocation().getRoomConstraint().getAvailableArray() != null) { 625 for (Enumeration<Integer> e = getTimeLocation().getSlots(); e.hasMoreElements();) { 626 int slot = e.nextElement(); 627 if (getRoomLocation().getRoomConstraint().getAvailableArray()[slot] != null) { 628 for (Placement c : getRoomLocation().getRoomConstraint().getAvailableArray()[slot]) { 629 if (c.getTimeLocation().hasIntersection(getTimeLocation()) && !lecture.canShareRoom(c.variable())) { 630 return "room " + getRoomLocation().getName() + " not available at " + getTimeLocation().getLongName(useAmPm) + " due to " + c.variable().getName(); 631 } 632 } 633 } 634 } 635 } 636 return "room " + getRoomLocation().getName() + " not available at " + getTimeLocation().getLongName(useAmPm); 637 } 638 } 639 return reason; 640 } 641 642 @Deprecated 643 public String getNotValidReason(Assignment<Lecture, Placement> assignment) { 644 return getNotValidReason(assignment, true); 645 } 646 647 public int getNrRooms() { 648 if (iRoomLocations != null) 649 return iRoomLocations.size(); 650 return (iRoomLocation == null ? 0 : 1); 651 } 652 653 public int getSpreadPenalty(Assignment<Lecture, Placement> assignment) { 654 int spread = 0; 655 for (SpreadConstraint sc : variable().getSpreadConstraints()) { 656 spread += sc.getPenalty(assignment, this); 657 } 658 return spread; 659 } 660 661 public int getMaxSpreadPenalty(Assignment<Lecture, Placement> assignment) { 662 int spread = 0; 663 for (SpreadConstraint sc : variable().getSpreadConstraints()) { 664 spread += sc.getMaxPenalty(assignment, this); 665 } 666 return spread; 667 } 668 669 @Override 670 public double toDouble(Assignment<Lecture, Placement> assignment) { 671 double ret = 0.0; 672 for (Criterion<Lecture, Placement> criterion: variable().getModel().getCriteria()) 673 ret += criterion.getWeightedValue(assignment, this, null); 674 return ret; 675 } 676 677 private transient Object iAssignment = null; 678 679 public Object getAssignment() { 680 return iAssignment; 681 } 682 683 public void setAssignment(Object assignment) { 684 iAssignment = assignment; 685 } 686 687 public double getTimePenalty() { 688 if (iTimeLocation == null) return 0.0; 689 if (iTimePenalty == null) { 690 double[] bounds = variable().getMinMaxTimePreference(); 691 double npref = iTimeLocation.getNormalizedPreference(); 692 if (iTimeLocation.getPreference() < Constants.sPreferenceLevelRequired / 2) npref = bounds[0]; 693 else if (iTimeLocation.getPreference() > Constants.sPreferenceLevelProhibited / 2) npref = bounds[1]; 694 iTimePenalty = npref - bounds[0]; 695 } 696 return iTimePenalty; 697 } 698 699 public int getRoomPenalty() { 700 if (getNrRooms() == 0) return 0; 701 if (iRoomPenalty == null) { 702 int pref = getRoomPreference(); 703 int[] bounds = variable().getMinMaxRoomPreference(); 704 if (pref < Constants.sPreferenceLevelRequired / 2) pref = bounds[0]; 705 if (pref > Constants.sPreferenceLevelProhibited / 2) pref = bounds[1]; 706 iRoomPenalty = pref - bounds[0]; 707 } 708 return iRoomPenalty; 709 } 710}