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