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 return getRoomLocations().contains(placement.getRoomLocation()); 305 } 306 } else { 307 if (getRoomLocation().getRoomConstraint() == null || !getRoomLocation().getRoomConstraint().getConstraint()) 308 return false; 309 if (placement.isMultiRoom()) { 310 return placement.getRoomLocations().contains(getRoomLocation()); 311 } else { 312 return getRoomLocation().equals(placement.getRoomLocation()); 313 } 314 } 315 } 316 317 public int nrDifferentRooms(Placement placement) { 318 if (isMultiRoom()) { 319 int ret = 0; 320 for (RoomLocation r : getRoomLocations()) { 321 if (!placement.getRoomLocations().contains(r)) 322 ret++; 323 } 324 return ret; 325 } else { 326 return (placement.getRoomLocation().equals(getRoomLocation()) ? 0 : 1); 327 } 328 } 329 330 public int nrDifferentBuildings(Placement placement) { 331 if (isMultiRoom()) { 332 int ret = 0; 333 for (RoomLocation r : getRoomLocations()) { 334 boolean contains = false; 335 for (RoomLocation q : placement.getRoomLocations()) { 336 if (ToolBox.equals(r.getBuildingId(), q.getBuildingId())) 337 contains = true; 338 } 339 if (!contains) 340 ret++; 341 } 342 return ret; 343 } else { 344 return (ToolBox.equals(placement.getRoomLocation().getBuildingId(), getRoomLocation().getBuildingId()) ? 0 345 : 1); 346 } 347 } 348 349 public int sumRoomPreference() { 350 if (isMultiRoom()) { 351 int ret = 0; 352 int roomIndex = 0; 353 for (RoomLocation r : getRoomLocations()) { 354 ret += r.getPreference(roomIndex ++); 355 } 356 return ret; 357 } else { 358 return getRoomLocation().getPreference(); 359 } 360 } 361 362 public int getRoomPreference() { 363 if (isMultiRoom()) { 364 PreferenceCombination p = PreferenceCombination.getDefault(); 365 int roomIndex = 0; 366 for (RoomLocation r : getRoomLocations()) { 367 p.addPreferenceInt(r.getPreference(roomIndex++)); 368 } 369 return p.getPreferenceInt(); 370 } else { 371 return getRoomLocation().getPreference(); 372 } 373 } 374 375 public int getRoomSize() { 376 if (isMultiRoom()) { 377 if (getRoomLocations().isEmpty()) return 0; 378 if (variable() != null && variable().isSplitAttendance()) { 379 int roomSize = 0; 380 for (RoomLocation r : getRoomLocations()) 381 roomSize += r.getRoomSize(); 382 return roomSize; 383 } else { 384 int roomSize = Integer.MAX_VALUE; 385 for (RoomLocation r : getRoomLocations()) { 386 roomSize = Math.min(roomSize, r.getRoomSize()); 387 } 388 return roomSize; 389 } 390 } else { 391 return getRoomLocation().getRoomSize(); 392 } 393 } 394 395 public boolean isHard(Assignment<Lecture, Placement> assignment) { 396 if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(getTimeLocation().getPreference()))) 397 return true; 398 if (isRoomProhibited()) return true; 399 Lecture lecture = variable(); 400 for (GroupConstraint gc : lecture.hardGroupSoftConstraints()) { 401 if (gc.isSatisfied(assignment)) 402 continue; 403 if (Constants.sPreferenceProhibited.equals(gc.getPrologPreference())) 404 return true; 405 if (Constants.sPreferenceRequired.equals(gc.getPrologPreference())) 406 return true; 407 } 408 return false; 409 } 410 411 public boolean isRoomProhibited() { 412 if (isMultiRoom()) { 413 int roomIndex = 0; 414 for (RoomLocation r : getRoomLocations()) { 415 if (Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(r.getPreference(roomIndex++)))) 416 return true; 417 } 418 } else { 419 if (getRoomLocation() != null && Constants.sPreferenceProhibited.equals(Constants.preferenceLevel2preference(getRoomLocation().getPreference()))) 420 return true; 421 } 422 return false; 423 } 424 425 public boolean sameTime(Placement placement) { 426 return placement.getTimeLocation().equals(getTimeLocation()); 427 } 428 429 @Override 430 public boolean equals(Object object) { 431 if (object == null || !(object instanceof Placement)) 432 return false; 433 Placement placement = (Placement) object; 434 if (placement.getId() == getId()) 435 return true; // quick check 436 Lecture lecture = placement.variable(); 437 Lecture thisLecture = variable(); 438 if (lecture != null && thisLecture != null && !lecture.getClassId().equals(thisLecture.getClassId())) 439 return false; 440 if (!sameRooms(placement)) 441 return false; 442 if (!sameTime(placement)) 443 return false; 444 return true; 445 } 446 447 @Override 448 public int hashCode() { 449 return iHashCode; 450 } 451 452 @Override 453 public String toString() { 454 return variable().getName() + " " + getName(); 455 } 456 457 /** Distance between two placements 458 * @param m distance matrix 459 * @param p1 first placement 460 * @param p2 second placement 461 * @return maximal distance in meters between the two placement 462 **/ 463 public static double getDistanceInMeters(DistanceMetric m, Placement p1, Placement p2) { 464 if (p1.isMultiRoom()) { 465 if (p2.isMultiRoom()) { 466 double dist = 0.0; 467 for (RoomLocation r1 : p1.getRoomLocations()) { 468 for (RoomLocation r2 : p2.getRoomLocations()) { 469 dist = Math.max(dist, r1.getDistanceInMeters(m, r2)); 470 } 471 } 472 return dist; 473 } else { 474 if (p2.getRoomLocation() == null) 475 return 0.0; 476 double dist = 0.0; 477 for (RoomLocation r1 : p1.getRoomLocations()) { 478 dist = Math.max(dist, r1.getDistanceInMeters(m, p2.getRoomLocation())); 479 } 480 return dist; 481 } 482 } else if (p2.isMultiRoom()) { 483 if (p1.getRoomLocation() == null) 484 return 0.0; 485 double dist = 0.0; 486 for (RoomLocation r2 : p2.getRoomLocations()) { 487 dist = Math.max(dist, p1.getRoomLocation().getDistanceInMeters(m, r2)); 488 } 489 return dist; 490 } else { 491 if (p1.getRoomLocation() == null || p2.getRoomLocation() == null) 492 return 0.0; 493 return p1.getRoomLocation().getDistanceInMeters(m, p2.getRoomLocation()); 494 } 495 } 496 497 /** Distance between two placements 498 * @param m distance matrix 499 * @param p1 first placement 500 * @param p2 second placement 501 * @return maximal distance in minutes between the two placement 502 **/ 503 public static int getDistanceInMinutes(DistanceMetric m, Placement p1, Placement p2) { 504 if (p1.isMultiRoom()) { 505 if (p2.isMultiRoom()) { 506 int dist = 0; 507 for (RoomLocation r1 : p1.getRoomLocations()) { 508 for (RoomLocation r2 : p2.getRoomLocations()) { 509 dist = Math.max(dist, r1.getDistanceInMinutes(m, r2)); 510 } 511 } 512 return dist; 513 } else { 514 if (p2.getRoomLocation() == null) 515 return 0; 516 int dist = 0; 517 for (RoomLocation r1 : p1.getRoomLocations()) { 518 dist = Math.max(dist, r1.getDistanceInMinutes(m, p2.getRoomLocation())); 519 } 520 return dist; 521 } 522 } else if (p2.isMultiRoom()) { 523 if (p1.getRoomLocation() == null) 524 return 0; 525 int dist = 0; 526 for (RoomLocation r2 : p2.getRoomLocations()) { 527 dist = Math.max(dist, p1.getRoomLocation().getDistanceInMinutes(m, r2)); 528 } 529 return dist; 530 } else { 531 if (p1.getRoomLocation() == null || p2.getRoomLocation() == null) 532 return 0; 533 return p1.getRoomLocation().getDistanceInMinutes(m, p2.getRoomLocation()); 534 } 535 } 536 537 public int getCommitedConflicts() { 538 int ret = 0; 539 Lecture lecture = variable(); 540 for (Student student : lecture.students()) { 541 ret += student.countConflictPlacements(this); 542 } 543 return ret; 544 } 545 546 public Long getAssignmentId() { 547 return iAssignmentId; 548 } 549 550 public void setAssignmentId(Long assignmentId) { 551 iAssignmentId = assignmentId; 552 } 553 554 public boolean canShareRooms(Placement other) { 555 return (variable()).canShareRoom(other.variable()); 556 } 557 558 public boolean isValid() { 559 Lecture lecture = variable(); 560 if (!lecture.isValid(this)) 561 return false; 562 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 563 if (!ic.isAvailable(lecture, this) && ic.isHard()) 564 return false; 565 } 566 if (lecture.getNrRooms() > 0) { 567 if (isMultiRoom()) { 568 for (RoomLocation roomLocation : getRoomLocations()) { 569 if (roomLocation.getRoomConstraint() != null 570 && !roomLocation.getRoomConstraint().isAvailable(lecture, getTimeLocation(), 571 lecture.getScheduler())) 572 return false; 573 } 574 } else { 575 if (getRoomLocation().getRoomConstraint() != null 576 && !getRoomLocation().getRoomConstraint().isAvailable(lecture, getTimeLocation(), 577 lecture.getScheduler())) 578 return false; 579 } 580 } 581 return true; 582 } 583 584 public String getNotValidReason(Assignment<Lecture, Placement> assignment, boolean useAmPm) { 585 Lecture lecture = variable(); 586 String reason = lecture.getNotValidReason(assignment, this, useAmPm); 587 if (reason != null) 588 return reason; 589 for (InstructorConstraint ic : lecture.getInstructorConstraints()) { 590 if (!ic.isAvailable(lecture, this) && ic.isHard()) { 591 if (!ic.isAvailable(lecture, getTimeLocation())) { 592 for (Placement c: ic.getUnavailabilities()) { 593 if (c.getTimeLocation().hasIntersection(getTimeLocation()) && !lecture.canShareRoom(c.variable())) 594 return "instructor " + ic.getName() + " not available at " + getTimeLocation().getLongName(useAmPm) + " due to " + c.variable().getName(); 595 } 596 return "instructor " + ic.getName() + " not available at " + getTimeLocation().getLongName(useAmPm); 597 } else 598 return "placement " + getTimeLocation().getLongName(useAmPm) + " " + getRoomName(", ") + " is too far for instructor " + ic.getName(); 599 } 600 } 601 if (lecture.getNrRooms() > 0) { 602 if (isMultiRoom()) { 603 for (RoomLocation roomLocation : getRoomLocations()) { 604 if (roomLocation.getRoomConstraint() != null && !roomLocation.getRoomConstraint().isAvailable(lecture, getTimeLocation(), lecture.getScheduler())) { 605 if (roomLocation.getRoomConstraint().getAvailableArray() != null) { 606 for (Enumeration<Integer> e = getTimeLocation().getSlots(); e.hasMoreElements();) { 607 int slot = e.nextElement(); 608 if (roomLocation.getRoomConstraint().getAvailableArray()[slot] != null) { 609 for (Placement c : roomLocation.getRoomConstraint().getAvailableArray()[slot]) { 610 if (c.getTimeLocation().hasIntersection(getTimeLocation()) && !lecture.canShareRoom(c.variable())) { 611 return "room " + roomLocation.getName() + " not available at " + getTimeLocation().getLongName(useAmPm) + " due to " + c.variable().getName(); 612 } 613 } 614 } 615 } 616 } 617 return "room " + roomLocation.getName() + " not available at " + getTimeLocation().getLongName(useAmPm); 618 } 619 } 620 } else { 621 if (getRoomLocation().getRoomConstraint() != null && !getRoomLocation().getRoomConstraint().isAvailable(lecture, getTimeLocation(), lecture.getScheduler())) 622 if (getRoomLocation().getRoomConstraint().getAvailableArray() != null) { 623 for (Enumeration<Integer> e = getTimeLocation().getSlots(); e.hasMoreElements();) { 624 int slot = e.nextElement(); 625 if (getRoomLocation().getRoomConstraint().getAvailableArray()[slot] != null) { 626 for (Placement c : getRoomLocation().getRoomConstraint().getAvailableArray()[slot]) { 627 if (c.getTimeLocation().hasIntersection(getTimeLocation()) && !lecture.canShareRoom(c.variable())) { 628 return "room " + getRoomLocation().getName() + " not available at " + getTimeLocation().getLongName(useAmPm) + " due to " + c.variable().getName(); 629 } 630 } 631 } 632 } 633 } 634 return "room " + getRoomLocation().getName() + " not available at " + getTimeLocation().getLongName(useAmPm); 635 } 636 } 637 return reason; 638 } 639 640 @Deprecated 641 public String getNotValidReason(Assignment<Lecture, Placement> assignment) { 642 return getNotValidReason(assignment, true); 643 } 644 645 public int getNrRooms() { 646 if (iRoomLocations != null) 647 return iRoomLocations.size(); 648 return (iRoomLocation == null ? 0 : 1); 649 } 650 651 public int getSpreadPenalty(Assignment<Lecture, Placement> assignment) { 652 int spread = 0; 653 for (SpreadConstraint sc : variable().getSpreadConstraints()) { 654 spread += sc.getPenalty(assignment, this); 655 } 656 return spread; 657 } 658 659 public int getMaxSpreadPenalty(Assignment<Lecture, Placement> assignment) { 660 int spread = 0; 661 for (SpreadConstraint sc : variable().getSpreadConstraints()) { 662 spread += sc.getMaxPenalty(assignment, this); 663 } 664 return spread; 665 } 666 667 @Override 668 public double toDouble(Assignment<Lecture, Placement> assignment) { 669 double ret = 0.0; 670 for (Criterion<Lecture, Placement> criterion: variable().getModel().getCriteria()) 671 ret += criterion.getWeightedValue(assignment, this, null); 672 return ret; 673 } 674 675 private transient Object iAssignment = null; 676 677 public Object getAssignment() { 678 return iAssignment; 679 } 680 681 public void setAssignment(Object assignment) { 682 iAssignment = assignment; 683 } 684 685 public double getTimePenalty() { 686 if (iTimeLocation == null) return 0.0; 687 if (iTimePenalty == null) { 688 double[] bounds = variable().getMinMaxTimePreference(); 689 double npref = iTimeLocation.getNormalizedPreference(); 690 if (iTimeLocation.getPreference() < Constants.sPreferenceLevelRequired / 2) npref = bounds[0]; 691 else if (iTimeLocation.getPreference() > Constants.sPreferenceLevelProhibited / 2) npref = bounds[1]; 692 iTimePenalty = npref - bounds[0]; 693 } 694 return iTimePenalty; 695 } 696 697 public int getRoomPenalty() { 698 if (getNrRooms() == 0) return 0; 699 if (iRoomPenalty == null) { 700 int pref = getRoomPreference(); 701 int[] bounds = variable().getMinMaxRoomPreference(); 702 if (pref < Constants.sPreferenceLevelRequired / 2) pref = bounds[0]; 703 if (pref > Constants.sPreferenceLevelProhibited / 2) pref = bounds[1]; 704 iRoomPenalty = pref - bounds[0]; 705 } 706 return iRoomPenalty; 707 } 708}