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 Tomáš Müller<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    @Override
086    public void unassigned(Assignment<Lecture, Placement> assignment, long iteration, Placement placement) {
087        super.unassigned(assignment, iteration, placement);
088        if (!placement.hasRoomLocation(getResourceId()))
089            ((DiscouragedRoomConstraintContext)getContext(assignment)).weaken();
090    }
091
092    public class DiscouragedRoomConstraintContext extends RoomConstraintContext {
093        int iUsage = 0;
094        int iLimit = 0;
095        private long iUnassignment = 0;
096
097        public DiscouragedRoomConstraintContext(Assignment<Lecture, Placement> assignment) {
098            super(assignment);
099        }
100
101        @Override
102        public void assigned(Assignment<Lecture, Placement> assignment, Placement placement) {
103            super.assigned(assignment, placement);
104            if (placement.hasRoomLocation(getResourceId()) && !placement.variable().isCommitted())
105                iUsage ++;
106        }
107        
108        @Override
109        public void unassigned(Assignment<Lecture, Placement> assignment, Placement placement) {
110            super.unassigned(assignment, placement);
111            if (placement.hasRoomLocation(getResourceId()) && !placement.variable().isCommitted())
112                iUsage --;
113        }
114
115        public int getLimit() {
116            return iLimit;
117        }
118
119        public int getUsage() {
120            return iUsage;
121        }
122
123        public boolean isOverLimit(Assignment<Lecture, Placement> assignment, Placement value) {
124            if (iUnassignmentsToWeaken == 0)
125                return false; // not working
126            if (!value.hasRoomLocation(getResourceId()))
127                return false; // different room
128            Lecture lecture = value.variable();
129            if (lecture.roomLocations().size() == lecture.getNrRooms())
130                return false; // required room
131            if (lecture.isCommitted())
132                return false; // committed class
133            Placement current = assignment.getValue(lecture);
134            if (current != null && current.hasRoomLocation(getResourceId()))
135                return false; // already assigned in this room
136            if (iUsage + 1 <= iLimit)
137                return false; // under the limit
138            return true;
139        }
140        
141        public void weaken() {
142            if (iUnassignmentsToWeaken == 0) return;
143            iUnassignment++;
144            if (iUnassignment % iUnassignmentsToWeaken == 0)
145                iLimit ++;
146        }
147        
148        public void weaken(Assignment<Lecture, Placement> assignment, Placement value) {
149            while (isOverLimit(assignment, value))
150                iLimit ++;
151        }
152    }
153}