001package org.cpsolver.coursett.criteria;
002
003import java.util.Collection;
004import java.util.Set;
005
006import org.cpsolver.coursett.Constants;
007import org.cpsolver.coursett.model.Lecture;
008import org.cpsolver.coursett.model.Placement;
009import org.cpsolver.coursett.model.RoomLocation;
010import org.cpsolver.coursett.preference.PreferenceCombination;
011import org.cpsolver.ifs.assignment.Assignment;
012import org.cpsolver.ifs.util.DataProperties;
013
014
015/**
016 * Too big rooms. This criterion counts cases where a class is placed in a room
017 * that is too big for the class. In general, a room is discouraged (in this
018 * criterion) if it has 25% more space than needed, strongly discouraged
019 * if it has more than 50% space than needed. Needed space is counted as the space
020 * of the smallest room in which a class can take place.
021 * <br>
022 * 
023 * @author  Tomáš Müller
024 * @version CourseTT 1.3 (University Course Timetabling)<br>
025 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
026 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
027 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
028 * <br>
029 *          This library is free software; you can redistribute it and/or modify
030 *          it under the terms of the GNU Lesser General Public License as
031 *          published by the Free Software Foundation; either version 3 of the
032 *          License, or (at your option) any later version. <br>
033 * <br>
034 *          This library is distributed in the hope that it will be useful, but
035 *          WITHOUT ANY WARRANTY; without even the implied warranty of
036 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
037 *          Lesser General Public License for more details. <br>
038 * <br>
039 *          You should have received a copy of the GNU Lesser General Public
040 *          License along with this library; if not see
041 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
042 */
043public class TooBigRooms extends TimetablingCriterion {
044    private double iDiscouragedRoomSize, iStronglyDiscouragedRoomSize;
045
046    @Override
047    public void configure(DataProperties properties) {
048        super.configure(properties);
049        iDiscouragedRoomSize = properties.getPropertyDouble("TooBigRooms.DiscouragedRoomSize", 1.25);
050        iStronglyDiscouragedRoomSize = properties.getPropertyDouble("TooBigRooms.StronglyDiscouragedRoomSize", 1.5);
051    }
052
053    @Override
054    public double getWeightDefault(DataProperties config) {
055        return config.getPropertyDouble("Comparator.TooBigRoomWeight", 0.1);
056    }
057    
058    @Override
059    public String getPlacementSelectionWeightName() {
060        return "Placement.TooBigRoomWeight";
061    }
062
063    @Override
064    public double getValue(Assignment<Lecture, Placement> assignment, Placement value, Set<Placement> conflicts) {
065        double ret = getPreference(value);
066        if (conflicts != null)
067            for (Placement conflict: conflicts)
068                ret -= getPreference(conflict);
069        return ret;
070    }
071    
072    @Override
073    public double[] getBounds(Assignment<Lecture, Placement> assignment, Collection<Lecture> variables) {
074        double[] bounds = new double[] { 0.0, 0.0 };
075        for (Lecture lect: variables) {
076            if (lect.getNrRooms() > 0)
077                bounds[0] += Constants.sPreferenceLevelStronglyDiscouraged;
078        }
079        return bounds;
080    }
081    
082    private long getDiscouragedRoomSize(Placement value) {
083        return Math.round(iDiscouragedRoomSize * value.variable().minRoomSize());
084    }
085
086    private long getStronglyDiscouragedRoomSize(Placement value) {
087        return Math.round(iStronglyDiscouragedRoomSize * value.variable().minRoomSize());
088    }
089    
090    public int getPreference(Placement value) {
091        if (value.isMultiRoom()) {
092            PreferenceCombination pref = PreferenceCombination.getDefault();
093            for (RoomLocation r : value.getRoomLocations()) {
094                if (r.getRoomSize() > getStronglyDiscouragedRoomSize(value))
095                    pref.addPreferenceInt(Constants.sPreferenceLevelStronglyDiscouraged);
096                else if (r.getRoomSize() > getDiscouragedRoomSize(value))
097                    pref.addPreferenceInt(Constants.sPreferenceLevelDiscouraged);
098            }
099            return pref.getPreferenceInt();
100        } else {
101            if (value.getRoomLocation().getRoomSize() > getStronglyDiscouragedRoomSize(value))
102                return Constants.sPreferenceLevelStronglyDiscouraged;
103            else if (value.getRoomLocation().getRoomSize() > getDiscouragedRoomSize(value))
104                return Constants.sPreferenceLevelDiscouraged;
105            else
106                return Constants.sPreferenceLevelNeutral;
107        }
108    }
109    
110    /** Use {@link TooBigRooms#getPreference(Placement)} instead. */
111    @Deprecated
112    public static int getTooBigRoomPreference(Placement value) {
113        if (value.isMultiRoom()) {
114            PreferenceCombination pref = PreferenceCombination.getDefault();
115            for (RoomLocation r : value.getRoomLocations()) {
116                if (r.getRoomSize() > Math.round(1.50 * value.variable().minRoomSize()))
117                    pref.addPreferenceInt(Constants.sPreferenceLevelStronglyDiscouraged);
118                else if (r.getRoomSize() > Math.round(1.25 * value.variable().minRoomSize()))
119                    pref.addPreferenceInt(Constants.sPreferenceLevelDiscouraged);
120            }
121            return pref.getPreferenceInt();
122        } else {
123            if (value.getRoomLocation().getRoomSize() > Math.round(1.50 * value.variable().minRoomSize()))
124                return Constants.sPreferenceLevelStronglyDiscouraged;
125            else if (value.getRoomLocation().getRoomSize() > Math.round(1.25 * value.variable().minRoomSize()))
126                return Constants.sPreferenceLevelDiscouraged;
127            else
128                return Constants.sPreferenceLevelNeutral;
129        }
130    }
131}