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