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}