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 }