001package net.sf.cpsolver.coursett.constraint;
002
003import java.util.Set;
004
005import net.sf.cpsolver.coursett.model.Lecture;
006import net.sf.cpsolver.coursett.model.Placement;
007import net.sf.cpsolver.coursett.model.RoomSharingModel;
008import net.sf.cpsolver.ifs.model.WeakeningConstraint;
009import net.sf.cpsolver.ifs.util.DataProperties;
010
011/**
012 * Discouraged room constraint. This constraint is based on
013 * {@link RoomConstraint}, however, it tries to minimize the usage of the room
014 * as much as possible.
015 * 
016 * @version CourseTT 1.2 (University Course Timetabling)<br>
017 *          Copyright (C) 2006 - 2010 Tomáš Müller<br>
018 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
019 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
020 * <br>
021 *          This library is free software; you can redistribute it and/or modify
022 *          it under the terms of the GNU Lesser General Public License as
023 *          published by the Free Software Foundation; either version 3 of the
024 *          License, or (at your option) any later version. <br>
025 * <br>
026 *          This library is distributed in the hope that it will be useful, but
027 *          WITHOUT ANY WARRANTY; without even the implied warranty of
028 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
029 *          Lesser General Public License for more details. <br>
030 * <br>
031 *          You should have received a copy of the GNU Lesser General Public
032 *          License along with this library; if not see
033 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
034 */
035public class DiscouragedRoomConstraint extends RoomConstraint implements WeakeningConstraint<Lecture, Placement> {
036    int iUsage = 0;
037    int iLimit = 0;
038    boolean iEnabled = false;
039
040    private int iUnassignmentsToWeaken = 1000;
041    private long iUnassignment = 0;
042
043    public DiscouragedRoomConstraint(DataProperties config, Long id, String name, Long buildingId, int capacity,
044            RoomSharingModel roomSharingModel, Double x, Double y, boolean ignoreTooFar, boolean constraint) {
045        super(id, name, buildingId, capacity, roomSharingModel, x, y, ignoreTooFar, constraint);
046        iUnassignmentsToWeaken = config.getPropertyInt("DiscouragedRoom.Unassignments2Weaken", iUnassignmentsToWeaken);
047    }
048
049    public int getLimit() {
050        return iLimit;
051    }
052
053    public int getUsage() {
054        return iUsage;
055    }
056
057    public boolean isOverLimit(Placement value) {
058        if (!iEnabled)
059            return false; // not enabled
060        if (iUnassignmentsToWeaken == 0)
061            return false; // not working
062        Placement placement = value;
063        if (!placement.hasRoomLocation(getResourceId()))
064            return false; // different room
065        Lecture lecture = placement.variable();
066        if (lecture.roomLocations().size() == lecture.getNrRooms())
067            return false; // required room
068        if (lecture.isCommitted())
069            return false; // commited class
070        if (lecture.getAssignment() != null && (lecture.getAssignment()).hasRoomLocation(getResourceId()))
071            return false; // already assigned in this room
072        if (iUsage + 1 <= iLimit)
073            return false; // under the limit
074        return true;
075    }
076
077    @Override
078    public void computeConflicts(Placement value, Set<Placement> conflicts) {
079        if (!getConstraint())
080            return;
081        super.computeConflicts(value, conflicts);
082        if (isOverLimit(value))
083            conflicts.add(value);
084    }
085
086    @Override
087    public boolean inConflict(Placement value) {
088        if (!getConstraint())
089            return false;
090        if (isOverLimit(value))
091            return true;
092        return super.inConflict(value);
093    }
094
095    @Override
096    public boolean isConsistent(Placement value1, Placement value2) {
097        if (!getConstraint())
098            return true;
099        if (isOverLimit(value1) || isOverLimit(value2))
100            return false;
101        return super.isConsistent(value1, value2);
102    }
103
104    @Override
105    public void assigned(long iteration, Placement value) {
106        super.assigned(iteration, value);
107        Placement placement = value;
108        if (!placement.hasRoomLocation(getResourceId()))
109            return;
110        Lecture lecture = placement.variable();
111        if (lecture.isCommitted())
112            return;
113        iUsage++;
114    }
115
116    @Override
117    public void unassigned(long iteration, Placement value) {
118        super.unassigned(iteration, value);
119        Placement placement = value;
120        if (!placement.hasRoomLocation(getResourceId())) {
121            iUnassignment++;
122            if (iUnassignmentsToWeaken > 0 && iUnassignment % iUnassignmentsToWeaken == 0)
123                iLimit++;
124        } else {
125            iUsage--;
126        }
127    }
128
129    @Override
130    public String getName() {
131        return "discouraged " + super.getName();
132    }
133
134    @Override
135    public String toString() {
136        return "Discouraged " + super.toString();
137    }
138
139    public void setEnabled(boolean enabled) {
140        iEnabled = enabled;
141        iLimit = Math.max(iUsage, iLimit);
142    }
143
144    public boolean isEnabled() {
145        return iEnabled;
146    }
147
148    @Override
149    public void weaken() {
150        iLimit ++;
151    }
152
153    @Override
154    public void weaken(Placement value) {
155        while (isOverLimit(value)) iLimit ++;
156    }
157}