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