    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}