001 package net.sf.cpsolver.coursett.criteria;
002
003 import net.sf.cpsolver.coursett.Constants;
004 import net.sf.cpsolver.coursett.constraint.RoomConstraint;
005 import net.sf.cpsolver.coursett.model.TimeLocation;
006 import net.sf.cpsolver.ifs.util.DataProperties;
007
008 /**
009 * Useless half-hours. This criterion counts cases when there is an empty half hour in a room.
010 * Such half-hours should be generally avoided as usually any class takes more than half an hour.
011 * <br>
012 *
013 * @version CourseTT 1.2 (University Course Timetabling)<br>
014 * Copyright (C) 2006 - 2011 Tomas Muller<br>
015 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
016 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
017 * <br>
018 * This library is free software; you can redistribute it and/or modify
019 * it under the terms of the GNU Lesser General Public License as
020 * published by the Free Software Foundation; either version 3 of the
021 * License, or (at your option) any later version. <br>
022 * <br>
023 * This library is distributed in the hope that it will be useful, but
024 * WITHOUT ANY WARRANTY; without even the implied warranty of
025 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
026 * Lesser General Public License for more details. <br>
027 * <br>
028 * You should have received a copy of the GNU Lesser General Public
029 * License along with this library; if not see
030 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
031 */
032 public class UselessHalfHours extends BrokenTimePatterns {
033
034 @Override
035 public double getWeightDefault(DataProperties config) {
036 return Constants.sPreferenceLevelStronglyDiscouraged * config.getPropertyDouble("Comparator.UselessSlotWeight", 0.1);
037 }
038
039 @Override
040 public String getPlacementSelectionWeightName() {
041 return "Placement.UselessSlotsWeight";
042 }
043
044 @Override
045 protected int penalty(RoomConstraint rc) {
046 return countUselessSlotsHalfHours(rc);
047 }
048
049 @Override
050 protected int penalty(RoomConstraint rc, TimeLocation value) {
051 return countUselessSlotsHalfHours(rc, value);
052 }
053
054 private static boolean isUselessBefore(RoomConstraint rc, int slot) {
055 int s = slot % Constants.SLOTS_PER_DAY;
056 if (s - 1 < 0 || s + 6 >= Constants.SLOTS_PER_DAY)
057 return false;
058 return (!rc.getResource(slot - 1).isEmpty() &&
059 rc.getResource(slot + 0).isEmpty() &&
060 rc.getResource(slot + 1).isEmpty() &&
061 rc.getResource(slot + 2).isEmpty() &&
062 rc.getResource(slot + 3).isEmpty() &&
063 rc.getResource(slot + 4).isEmpty() &&
064 rc.getResource(slot + 5).isEmpty());
065 }
066
067 private static boolean isUselessAfter(RoomConstraint rc, int slot) {
068 int s = slot % Constants.SLOTS_PER_DAY;
069 if (s - 1 < 0 || s + 6 >= Constants.SLOTS_PER_DAY)
070 return false;
071 return (rc.getResource(slot + 0).isEmpty() &&
072 rc.getResource(slot + 1).isEmpty() &&
073 rc.getResource(slot + 2).isEmpty() &&
074 rc.getResource(slot + 3).isEmpty() &&
075 rc.getResource(slot + 4).isEmpty() &&
076 rc.getResource(slot + 5).isEmpty() &&
077 !rc.getResource(slot + 6).isEmpty());
078 }
079
080 /** Number of useless half hours for this room */
081 protected static int countUselessSlotsHalfHours(RoomConstraint rc, TimeLocation time) {
082 int ret = 0;
083 int slot = time.getStartSlot() % Constants.SLOTS_PER_DAY;
084 int days = time.getDayCode();
085 for (int d = 0; d < Constants.NR_DAYS; d++) {
086 if ((Constants.DAY_CODES[d] & days) == 0)
087 continue;
088 if (isUselessBefore(rc, d * Constants.SLOTS_PER_DAY + slot - 6))
089 ret ++;
090 if (isUselessAfter(rc, d * Constants.SLOTS_PER_DAY + slot + time.getNrSlotsPerMeeting()))
091 ret ++;
092 }
093 return ret;
094 }
095
096 private static boolean isUseless(RoomConstraint rc, int slot) {
097 int s = slot % Constants.SLOTS_PER_DAY;
098 if (s - 1 < 0 || s + 6 >= Constants.SLOTS_PER_DAY)
099 return false;
100 return (!rc.getResource(slot - 1).isEmpty() &&
101 rc.getResource(slot + 0).isEmpty() &&
102 rc.getResource(slot + 1).isEmpty() &&
103 rc.getResource(slot + 2).isEmpty() &&
104 rc.getResource(slot + 3).isEmpty() &&
105 rc.getResource(slot + 4).isEmpty() &&
106 rc.getResource(slot + 5).isEmpty() &&
107 !rc.getResource(slot + 6).isEmpty());
108 }
109
110 /** Number of useless slots for this room */
111 public static int countUselessSlotsHalfHours(RoomConstraint rc) {
112 int ret = 0;
113 for (int d = 0; d < Constants.NR_DAYS; d++) {
114 for (int s = 0; s < Constants.SLOTS_PER_DAY; s++) {
115 int slot = d * Constants.SLOTS_PER_DAY + s;
116 if (isUseless(rc, slot))
117 ret++;
118 }
119 }
120 return ret;
121 }
122 }