001 package net.sf.cpsolver.coursett.heuristics; 002 003 004 import java.util.*; 005 006 import net.sf.cpsolver.coursett.constraint.*; 007 import net.sf.cpsolver.coursett.model.*; 008 import net.sf.cpsolver.ifs.extension.*; 009 import net.sf.cpsolver.ifs.heuristics.*; 010 import net.sf.cpsolver.ifs.model.*; 011 import net.sf.cpsolver.ifs.perturbations.*; 012 import net.sf.cpsolver.ifs.solution.*; 013 import net.sf.cpsolver.ifs.solver.*; 014 import net.sf.cpsolver.ifs.util.*; 015 016 /** 017 * Placement (value) selection. 018 * <br><br> 019 * We have implemented a hierarchical handling of the value selection criteria (see {@link HeuristicSelector}). 020 * <br><br> 021 * The value selection heuristics also allow for random selection of a value with a given probability 022 * (random walk, e.g., 2%) and, in the case of MPP, to select the initial value (if it exists) with a given probability (e.g., 70%). 023 * <br><br> 024 * Parameters (general): 025 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr> 026 * <tr><td>Placement.RandomWalkProb</td><td>{@link Double}</td><td>Random walk probability</td></tr> 027 * <tr><td>Placement.GoodSelectionProb</td><td>{@link Double}</td><td>Good value (not removed from domain) selection probability (MAC related)</td></tr> 028 * <tr><td>Placement.TabuLength</td><td>{@link Integer}</td><td>Tabu-list length (-1 means do not use tabu-list)</td></tr> 029 * <tr><td>Placement.MPP_InitialProb</td><td>{@link Double}</td><td>MPP initial selection probability </td></tr> 030 * <tr><td>Placement.MPP_Limit</td><td>{@link Integer}</td><td>MPP: limit on the number of perturbations (-1 for no limit)</td></tr> 031 * <tr><td>Placement.MPP_PenaltyLimit</td><td>{@link Double}</td><td>MPP: limit on the perturbations penalty (-1 for no limit)</td></tr> 032 * </table> 033 * <br> 034 * Parameters (for each level of selection): 035 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr> 036 * <tr><td>Placement.NrAssignmentsWeight1<br>Placement.NrAssignmentsWeight2<br>Placement.NrAssignmentsWeight3</td><td>{@link Double}</td><td>Number of previous assignments of the value weight</td></tr> 037 * <tr><td>Placement.NrConflictsWeight1,2,3</td><td>{@link Double}</td><td>Number of conflicts weight</td></tr> 038 * <tr><td>Placement.WeightedConflictsWeight1,2,3</td><td>{@link Double}</td><td>Weighted conflicts weight (Conflict-based Statistics related)</td></tr> 039 * <tr><td>Placement.NrPotentialConflictsWeight1,2,3</td><td>{@link Double}</td><td>Number of potential conflicts weight (Conflict-based Statistics related)</td></tr> 040 * <tr><td>Placement.MPP_DeltaInitialAssignmentWeight1,2,3</td><td>{@link Double}</td><td>Delta initial assigments weight (MPP, violated initials related)</td></tr> 041 * <tr><td>Placement.NrHardStudConfsWeight1,2,3</td><td>{@link Double}</td><td>Hard student conflicts weight (student conflicts between single-section classes)</td></tr> 042 * <tr><td>Placement.NrStudConfsWeight1,2,3</td><td>{@link Double}</td><td>Student conflicts weight</td></tr> 043 * <tr><td>Placement.TimePreferenceWeight1,2,3</td><td>{@link Double}</td><td>Time preference weight</td></tr> 044 * <tr><td>Placement.DeltaTimePreferenceWeight1,2,3</td><td>{@link Double}</td><td>Time preference delta weight (difference between before and after assignemnt of the value)</td></tr> 045 * <tr><td>Placement.ConstrPreferenceWeight1,2,3</td><td>{@link Double}</td><td>Constraint preference weight</td></tr> 046 * <tr><td>Placement.RoomPreferenceWeight1,2,3</td><td>{@link Double}</td><td>Room preference weight</td></tr> 047 * <tr><td>Placement.UselessSlotsWeight1,2,3</td><td>{@link Double}</td><td>Useless slot weight</td></tr> 048 * <tr><td>Placement.TooBigRoomWeight1,2,3</td><td>{@link Double}</td><td>Too big room weight</td></tr> 049 * <tr><td>Placement.DistanceInstructorPreferenceWeight1,2,3</td><td>{@link Double}</td><td>Distance (of the rooms of the back-to-back classes) based instructor preferences weight</td></tr> 050 * <tr><td>Placement.DeptSpreadPenaltyWeight1,2,3</td><td>{@link Double}</td><td>Department spreading: penalty of when a slot over initial allowance is used</td></tr> 051 * <tr><td>Placement.ThresholdKoef1,2</td><td>{@link Double}</td><td>Threshold koeficient of the level</td></tr> 052 * </table> 053 * 054 * @see PlacementSelection 055 * @version 056 * CourseTT 1.1 (University Course Timetabling)<br> 057 * Copyright (C) 2006 Tomáš Müller<br> 058 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 059 * Lazenska 391, 76314 Zlin, Czech Republic<br> 060 * <br> 061 * This library is free software; you can redistribute it and/or 062 * modify it under the terms of the GNU Lesser General Public 063 * License as published by the Free Software Foundation; either 064 * version 2.1 of the License, or (at your option) any later version. 065 * <br><br> 066 * This library is distributed in the hope that it will be useful, 067 * but WITHOUT ANY WARRANTY; without even the implied warranty of 068 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 069 * Lesser General Public License for more details. 070 * <br><br> 071 * You should have received a copy of the GNU Lesser General Public 072 * License along with this library; if not, write to the Free Software 073 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 074 */ 075 076 public class PlacementSelection implements ValueSelection { 077 static final int NR_LEVELS = 3; 078 private static final double PRECISION = 1.0; 079 private static final boolean USE_THRESHOLD = true; 080 private boolean iUseThreshold = USE_THRESHOLD; 081 082 private double iGoodSelectionProb; 083 public static final String GOOD_SELECTION_PROB = "Placement.GoodSelectionProb"; 084 private double iRandomWalkProb; 085 public static final String RW_SELECTION_PROB = "Placement.RandomWalkProb"; 086 private double iInitialSelectionProb; 087 public static final String INITIAL_SELECTION_PROB = "Placement.MPP_InitialProb"; 088 private int iMPPLimit; 089 public static final String NR_MPP_LIMIT = "Placement.MPP_Limit"; 090 private double iMPPPenaltyLimit; 091 public static final String NR_MPP_PENALTY_LIMIT = "Placement.MPP_PenaltyLimit"; 092 093 private double[] iNrConflictsWeight = new double[NR_LEVELS]; 094 public static final String NR_CONFLICTS_WEIGHT = "Placement.NrConflictsWeight"; 095 private double[] iNrPotentialConflictsWeight = new double[NR_LEVELS]; 096 public static final String NR_POTENTIAL_CONFLICTS_WEIGHT = "Placement.NrPotentialConflictsWeight"; 097 private double[] iNrWeightedConflictsWeight = new double[NR_LEVELS]; 098 public static final String WEIGHTED_CONFLICTS_WEIGHT = "Placement.WeightedConflictsWeight"; 099 private double[] iDeltaTimePreferenceWeight = new double[NR_LEVELS]; 100 public static final String DELTA_TIME_PREFERENCE_WEIGHT = "Placement.DeltaTimePreferenceWeight"; 101 private double[] iPerturbationPenaltyWeight = new double[NR_LEVELS]; 102 public static final String DELTA_INITIAL_ASSIGNMENT_WEIGHT = "Placement.MPP_DeltaInitialAssignmentWeight"; 103 private double[] iNrStudentConflictsWeight = new double[NR_LEVELS]; 104 public static final String NR_STUDENT_CONF_WEIGHT = "Placement.NrStudConfsWeight"; 105 private double[] iNrHardStudentConflictsWeight = new double[NR_LEVELS]; 106 public static final String NR_HARD_STUDENT_CONF_WEIGHT = "Placement.NrHardStudConfsWeight"; 107 private double[] iNrCommitedStudentConflictsWeight = new double[NR_LEVELS]; 108 public static final String NR_COMMITED_STUDENT_CONF_WEIGHT = "Placement.NrCommitedStudConfsWeight"; 109 private double[] iUselessSlotsWeight = new double[NR_LEVELS]; 110 public static final String USELESS_SLOTS_WEIGHT = "Placement.UselessSlotsWeight"; 111 private double[] iSumConstrPreferencesWeight = new double[NR_LEVELS]; 112 public static final String SUM_CONSTR_PREFERENCE_WEIGHT = "Placement.ConstrPreferenceWeight"; 113 private double[] iSumRoomPreferencesWeight = new double[NR_LEVELS]; 114 public static final String SUM_ROOM_PREFERENCE_WEIGHT = "Placement.RoomPreferenceWeight"; 115 private double[] iSumTimePreferencesWeight = new double[NR_LEVELS]; 116 public static final String SUM_TIME_PREFERENCE_WEIGHT = "Placement.TimePreferenceWeight"; 117 private double[] iNrAssignmentsWeight = new double[NR_LEVELS]; 118 public static final String NR_ASSIGNMENTS_WEIGHT = "Placement.NrAssignmentsWeight"; 119 private double[] iThresholdKoef = new double[NR_LEVELS]; 120 public static final String NR_THRESHOLD_KOEF = "Placement.ThresholdKoef"; 121 private double[] iTooBigRoomWeight = new double[NR_LEVELS]; 122 public static final String TOO_BIG_ROOM_WEIGHT = "Placement.TooBigRoomWeight"; 123 private double[] iDeptSpreadWeight = new double[NR_LEVELS]; 124 public static final String DEPT_SPREAD_WEIGHT = "Placement.DeptSpreadPenaltyWeight"; 125 private double[] iDistanceInstructorPreferenceWeight = new double[NR_LEVELS]; 126 public static final String DISTANCE_INSTRUCTOR_PREFERENCE_WEIGHT = "Placement.DistanceInstructorPreferenceWeight"; 127 private double[] iSpreadWeight = new double[NR_LEVELS]; 128 public static final String SPREAD_WEIGHT = "Placement.SpreadPenaltyWeight"; 129 130 private int iTabuSize = 0; 131 private ArrayList iTabu = null; 132 private int iTabuPos = 0; 133 public static final String TABU_LENGTH = "Placement.TabuLength"; 134 135 private ConflictStatistics iStat = null; 136 private MacPropagation iProp = null; 137 private ViolatedInitials iViolatedInitials = null; 138 private PerturbationsCounter iPerturbationsCounter = null; 139 140 private boolean iRW = false; 141 private boolean iMPP = false; 142 private boolean iSW = false; 143 144 private boolean iCanUnassingSingleton = false; 145 146 public void init(Solver solver) { 147 for (Enumeration i=solver.getExtensions().elements();i.hasMoreElements();) { 148 Extension extension = (Extension)i.nextElement(); 149 if (extension instanceof ConflictStatistics) 150 iStat = (ConflictStatistics) extension; 151 if (extension instanceof MacPropagation) 152 iProp = (MacPropagation)extension; 153 if (extension instanceof ViolatedInitials) 154 iViolatedInitials = (ViolatedInitials)extension; 155 } 156 iPerturbationsCounter = solver.getPerturbationsCounter(); 157 } 158 159 public PlacementSelection(DataProperties properties) { 160 iMPP = properties.getPropertyBoolean("General.MPP", false); 161 iRW = properties.getPropertyBoolean("General.RandomWalk", true); 162 iSW = properties.getPropertyBoolean("General.SwitchStudents",true); 163 iCanUnassingSingleton = properties.getPropertyBoolean("Placement.CanUnassingSingleton", iCanUnassingSingleton); 164 boolean autoconfigure = properties.getPropertyBoolean("Placement.AutoConfigure", false); 165 iRandomWalkProb = (iRW?properties.getPropertyDouble(RW_SELECTION_PROB,0.00):0.0); 166 iGoodSelectionProb = properties.getPropertyDouble(GOOD_SELECTION_PROB,1.00); 167 iInitialSelectionProb = (iMPP?properties.getPropertyDouble(INITIAL_SELECTION_PROB, 0.75):0.0); 168 iMPPLimit = (iMPP?properties.getPropertyInt(NR_MPP_LIMIT, -1):-1); 169 iMPPPenaltyLimit = (iMPP?properties.getPropertyDouble(NR_MPP_PENALTY_LIMIT, -1.0):-1.0); 170 iTabuSize = properties.getPropertyInt(TABU_LENGTH, -1); 171 if (iTabuSize>0) iTabu=new ArrayList(iTabuSize); 172 iUseThreshold = properties.getPropertyBoolean("Placement.UseThreshold", USE_THRESHOLD); 173 174 for (int level=0; level<NR_LEVELS; level++) { 175 iNrConflictsWeight[level] = properties.getPropertyDouble(NR_CONFLICTS_WEIGHT+(level+1),(level==0?1.0:0.0)); 176 iNrPotentialConflictsWeight[level] = properties.getPropertyDouble(NR_POTENTIAL_CONFLICTS_WEIGHT+(level+1),0.0); 177 iNrWeightedConflictsWeight[level] = properties.getPropertyDouble(WEIGHTED_CONFLICTS_WEIGHT+(level+1),(level==0?1.0:0.0)); 178 iDeltaTimePreferenceWeight[level] = properties.getPropertyDouble(DELTA_TIME_PREFERENCE_WEIGHT+(level+1), (level==0?0.5:0.0)); 179 iPerturbationPenaltyWeight[level] = (iMPP?properties.getPropertyDouble(DELTA_INITIAL_ASSIGNMENT_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0)):0.0); 180 iNrStudentConflictsWeight[level] = properties.getPropertyDouble(NR_STUDENT_CONF_WEIGHT+(level+1),(level==0?0.1:(level==1?0.2:0.0))); 181 iNrHardStudentConflictsWeight[level] = (iSW?properties.getPropertyDouble(NR_HARD_STUDENT_CONF_WEIGHT+(level+1),(level==0?0.5:level==1?1.0:0.0)):0.0); 182 iNrCommitedStudentConflictsWeight[level] = properties.getPropertyDouble(NR_COMMITED_STUDENT_CONF_WEIGHT+(level+1),(level==0?0.2:level==1?1.0:0.0)); 183 iUselessSlotsWeight[level] = properties.getPropertyDouble(USELESS_SLOTS_WEIGHT+(level+1), 0.0); 184 iSumConstrPreferencesWeight[level] = properties.getPropertyDouble(SUM_CONSTR_PREFERENCE_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0)); 185 iSumRoomPreferencesWeight[level] = properties.getPropertyDouble(SUM_ROOM_PREFERENCE_WEIGHT+(level+1), (level==1?0.1:0.0)); 186 iSumTimePreferencesWeight[level] = properties.getPropertyDouble(SUM_TIME_PREFERENCE_WEIGHT+(level+1), (level==1?1.0:0.0)); 187 iNrAssignmentsWeight[level] = properties.getPropertyDouble(NR_ASSIGNMENTS_WEIGHT+(level+1), 0.0); 188 iThresholdKoef[level] = (USE_THRESHOLD?properties.getPropertyDouble(NR_THRESHOLD_KOEF+(level+1), (level==0?0.1:0.0)):0.0); 189 iTooBigRoomWeight[level] = properties.getPropertyDouble(TOO_BIG_ROOM_WEIGHT+(level+1), 0.0); 190 iDeptSpreadWeight[level] = properties.getPropertyDouble(DEPT_SPREAD_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0)); 191 iSpreadWeight[level] = properties.getPropertyDouble(SPREAD_WEIGHT+(level+1), (level==0?0.5:level==1?1.0:0.0)); 192 iDistanceInstructorPreferenceWeight[level] = properties.getPropertyDouble(DISTANCE_INSTRUCTOR_PREFERENCE_WEIGHT+(level+1), (level==0?0.1:level==1?1.0:0.0)); 193 } 194 195 if (autoconfigure) { 196 iNrConflictsWeight[0] = 3.0; 197 iNrPotentialConflictsWeight[0] = 0.0; 198 iNrWeightedConflictsWeight[0] = 3.0; 199 iDeltaTimePreferenceWeight[0] = properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0)/2.0; 200 iNrAssignmentsWeight[0] = 0.0; 201 iThresholdKoef[0] = 0.1; 202 203 iNrStudentConflictsWeight[0] = properties.getPropertyDouble("Comparator.StudentConflictWeight",0.2); 204 iNrHardStudentConflictsWeight[0] = properties.getPropertyDouble("Comparator.HardStudentConflictWeight",1.0); 205 iNrCommitedStudentConflictsWeight[0] = properties.getPropertyDouble("Comparator.CommitedStudentConflictWeight",1.0); 206 iUselessSlotsWeight[0] = properties.getPropertyDouble("Comparator.UselessSlotWeight",0.0); 207 iSumConstrPreferencesWeight[0] = properties.getPropertyDouble("Comparator.ContrPreferenceWeight",1.0); 208 iSumRoomPreferencesWeight[0] = properties.getPropertyDouble("Comparator.RoomPreferenceWeight",0.1); 209 iSumTimePreferencesWeight[0] = properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0); 210 iTooBigRoomWeight[0] = properties.getPropertyDouble("Comparator.TooBigRoomWeight",0.0); 211 iDeptSpreadWeight[0] = properties.getPropertyDouble("Comparator.DeptSpreadPenaltyWeight",1.0); 212 iSpreadWeight[0] = properties.getPropertyDouble("Comparator.SpreadPenaltyWeight",1.0); 213 iDistanceInstructorPreferenceWeight[0] = properties.getPropertyDouble("Comparator.DistanceInstructorPreferenceWeight",1.0); 214 iPerturbationPenaltyWeight[0] = (iMPP?properties.getPropertyDouble("Comparator.PerturbationPenaltyWeight",1.0):0.0); 215 216 iNrConflictsWeight[1] = 0.0; 217 iNrPotentialConflictsWeight[1] = 0.0; 218 iNrWeightedConflictsWeight[1] = 0.0; 219 iDeltaTimePreferenceWeight[1] = 0.0; 220 iNrAssignmentsWeight[1] = 0.0; 221 iThresholdKoef[1] = 0.0; 222 223 iNrStudentConflictsWeight[1] = properties.getPropertyDouble("Comparator.StudentConflictWeight",0.2); 224 iNrHardStudentConflictsWeight[1] = properties.getPropertyDouble("Comparator.HardStudentConflictWeight",1.0); 225 iNrCommitedStudentConflictsWeight[1] = properties.getPropertyDouble("Comparator.CommitedStudentConflictWeight",1.0); 226 iUselessSlotsWeight[1] = properties.getPropertyDouble("Comparator.UselessSlotWeight",0.0); 227 iSumConstrPreferencesWeight[1] = properties.getPropertyDouble("Comparator.ContrPreferenceWeight",1.0); 228 iSumRoomPreferencesWeight[1] = properties.getPropertyDouble("Comparator.RoomPreferenceWeight",0.1); 229 iSumTimePreferencesWeight[1] = properties.getPropertyDouble("Comparator.TimePreferenceWeight",1.0); 230 iTooBigRoomWeight[1] = properties.getPropertyDouble("Comparator.TooBigRoomWeight",0.0); 231 iDeptSpreadWeight[1] = properties.getPropertyDouble("Comparator.DeptSpreadPenaltyWeight",1.0); 232 iSpreadWeight[1] = properties.getPropertyDouble("Comparator.SpreadPenaltyWeight",1.0); 233 iDistanceInstructorPreferenceWeight[1] = properties.getPropertyDouble("Comparator.DistanceInstructorPreferenceWeight",1.0); 234 iPerturbationPenaltyWeight[1] = (iMPP?properties.getPropertyDouble("Comparator.PerturbationPenaltyWeight",1.0):0.0); 235 236 iNrConflictsWeight[2] = 0.0; 237 iNrPotentialConflictsWeight[2] = 0.0; 238 iNrWeightedConflictsWeight[2] = 0.0; 239 iDeltaTimePreferenceWeight[2] = 0.0; 240 iPerturbationPenaltyWeight[2] = 0.0; 241 iNrStudentConflictsWeight[2] = 0.0; 242 iNrHardStudentConflictsWeight[2] = 0.0; 243 iNrCommitedStudentConflictsWeight[2] = 0.0; 244 iUselessSlotsWeight[2] = 0.0; 245 iSumConstrPreferencesWeight[2] = 0.0; 246 iSumRoomPreferencesWeight[2] = 0.0; 247 iSumTimePreferencesWeight[2] = 0.0; 248 iNrAssignmentsWeight[2] = 0.0; 249 iThresholdKoef[2] = 0.0; 250 iTooBigRoomWeight[2] = 0.0; 251 iDeptSpreadWeight[2] = 0.0; 252 iSpreadWeight[2] = 0.0; 253 iDistanceInstructorPreferenceWeight[2] = 0.0; 254 } 255 } 256 257 public Value selectValue(Solution solution, Variable selectedVariable) { 258 if (selectedVariable==null) return null; 259 TimetableModel model = (TimetableModel)solution.getModel(); 260 /*if (iMPPLimit>=0 && solution.getModel().unassignedVariables().isEmpty() && iMPPLimit>solution.getModel().perturbVariables().size()) { 261 ToolBox.print("A complete solution with "+solution.getModel().perturbVariables().size()+" perturbances found"); 262 iMPPLimit = solution.getModel().perturbVariables().size()-1; 263 ToolBox.print("MPP limit decreased to "+iMPPLimit); 264 }*/ 265 if (selectedVariable.getInitialAssignment()!=null) { 266 if (iMPPLimit>=0 && model.perturbVariables().size()>=iMPPLimit) { 267 if (!containsItselfSingletonOrCommited(model, model.conflictValues(selectedVariable.getInitialAssignment()),selectedVariable.getInitialAssignment())) 268 return checkValue(selectedVariable.getInitialAssignment()); 269 } else if (iMPPPenaltyLimit>=0.0 && solution.getPerturbationsCounter()!=null && solution.getPerturbationsCounter().getPerturbationPenalty(model)>iMPPPenaltyLimit) { 270 if (!containsItselfSingletonOrCommited(model, model.conflictValues(selectedVariable.getInitialAssignment()),selectedVariable.getInitialAssignment())) 271 return checkValue(selectedVariable.getInitialAssignment()); 272 } else if (selectedVariable.getInitialAssignment()!=null && ToolBox.random()<=iInitialSelectionProb) { 273 if (!containsItselfSingletonOrCommited(model, model.conflictValues(selectedVariable.getInitialAssignment()),selectedVariable.getInitialAssignment())) 274 return checkValue(selectedVariable.getInitialAssignment()); 275 } 276 } 277 278 Vector values = selectedVariable.values(); 279 if (iRW && ToolBox.random()<=iRandomWalkProb) { 280 for (int i=0;i<5;i++) { 281 Value ret = (Value)ToolBox.random(values); 282 if (!containsItselfSingletonOrCommited(model, model.conflictValues(ret), ret)) 283 return checkValue(ret); 284 } 285 } 286 if (iProp!=null && selectedVariable.getAssignment()==null && ToolBox.random()<=iGoodSelectionProb) { 287 Collection goodValues = iProp.goodValues(selectedVariable); 288 if (!goodValues.isEmpty()) values=new FastVector(goodValues); 289 } 290 if (values.size()==1) { 291 Value ret = (Value)values.firstElement(); 292 if (!containsItselfSingletonOrCommited(model, model.conflictValues(ret), ret)) 293 return checkValue(ret); 294 } 295 296 long[] bestCost = new long[NR_LEVELS]; 297 Vector selectionValues = null; 298 299 300 HeuristicSelector selector = (iUseThreshold?new HeuristicSelector(iThresholdKoef):null); 301 for (Enumeration i1=values.elements();i1.hasMoreElements();) { 302 Value value = (Value) i1.nextElement(); 303 if (iTabu!=null && iTabu.contains(value)) continue; 304 if (selectedVariable.getAssignment()!=null && selectedVariable.getAssignment().equals(value)) continue; 305 306 ParamRetriever paramRetriever = new ParamRetriever(solution, (Lecture)selectedVariable, (Placement)value); 307 if (containsItselfSingletonOrCommited(model, paramRetriever.conflicts(), value)) continue; 308 309 if (iUseThreshold) { 310 Double flt = selector.firstLevelThreshold(); 311 double[] costs = new double[NR_LEVELS]; 312 for (int level=0;level<NR_LEVELS;level++) { 313 costs[level] = getCost(paramRetriever, level, flt); 314 if (level==0 && flt!=null && costs[0]>flt.doubleValue()) { 315 break; 316 } 317 } 318 if (flt!=null && costs[0]>flt.doubleValue()) continue; 319 selector.add(costs, value); 320 } else { 321 Double flt = (selectionValues==null?null:new Double(0.5+bestCost[0])); 322 boolean fail = false; 323 boolean best = false; 324 for (int level=0;!fail && level<1;level++) { 325 long cost = Math.round( PRECISION * getCost(paramRetriever, level, flt)); 326 if (selectionValues!=null && !best) { 327 if (cost>bestCost[level]) { fail=true; } 328 if (cost<bestCost[level]) { bestCost[level]=cost; selectionValues.clear(); best=true; } 329 } else { 330 bestCost[level]=cost; 331 } 332 } 333 if (selectionValues==null) selectionValues = new FastVector(values.size()); 334 if (!fail) selectionValues.addElement(value); 335 } 336 } 337 //ToolBox.print("Best "+selectionValues.size()+" locations for variable "+selectedVariable.getId()+" have "+bestConflicts+" conflicts ("+bestRemovals+" weighted) and "+bestStudentConflicts+" ("+bestOriginalStudentConflicts+" * "+bestKoef+" + "+bestPenalty+") preference."); 338 Value selectedValue = null; 339 if (iUseThreshold) { 340 selectionValues = selector.selection(); 341 342 if (selectedVariable.getInitialAssignment()!=null) { 343 for (Enumeration e=selectionValues.elements();e.hasMoreElements();) { 344 Value value = (Value)((HeuristicSelector.Element) e.nextElement()).getObject(); 345 if (value.equals(selectedVariable.getInitialAssignment())) { 346 selectedValue = value; 347 break; 348 } 349 } 350 //&& selectionValues.contains(selectedVariable.getInitialAssignment())) return selectedVariable.getInitialAssignment(); 351 } 352 353 if (selectedValue==null) { 354 HeuristicSelector.Element selection = (HeuristicSelector.Element)ToolBox.random(selectionValues); 355 selectedValue = (Value)(selection==null?null:selection.getObject()); 356 } 357 } else { 358 if (selectedVariable.getInitialAssignment()!=null && selectionValues.contains(selectedVariable.getInitialAssignment())) return checkValue(selectedVariable.getInitialAssignment()); 359 selectedValue = (Value)ToolBox.random(selectionValues); 360 } 361 if (selectedValue!=null && iTabu!=null) { 362 if (iTabu.size()==iTabuPos) 363 iTabu.add(selectedValue); 364 else 365 iTabu.set(iTabuPos, selectedValue); 366 iTabuPos = (iTabuPos + 1) % iTabuSize; 367 } 368 return checkValue(selectedValue); 369 } 370 371 public boolean containsItselfSingletonOrCommited(TimetableModel model, Collection values, Value selectedValue) { 372 if (values.contains(selectedValue)) return true; 373 if (model.hasConstantVariables()) { 374 for (Iterator i=values.iterator();i.hasNext();) { 375 Placement placement = (Placement)i.next(); 376 Lecture lecture = (Lecture)placement.variable(); 377 if (lecture.isCommitted()) return true; 378 if (!iCanUnassingSingleton && lecture.isSingleton()) return true; 379 } 380 return false; 381 } else { 382 if (iCanUnassingSingleton) return false; 383 for (Iterator i=values.iterator();i.hasNext();) { 384 Placement placement = (Placement)i.next(); 385 Lecture lecture = (Lecture)placement.variable(); 386 if (lecture.isSingleton()) return true; 387 } 388 return false; 389 } 390 } 391 392 private Value checkValue(Value aValue) { 393 if (aValue==null) return null; 394 for (Iterator i=((Lecture)aValue.variable()).getWeakeningConstraints().iterator();i.hasNext();) { 395 Constraint c = (Constraint)i.next(); 396 if (c.inConflict(aValue)) ((WeakeningConstraint)c).weaken(); 397 } 398 return aValue; 399 } 400 401 public ParamRetriever getParameters(Solution solution, Lecture lecture, Placement placement) { 402 return new ParamRetriever(solution, lecture, placement); 403 } 404 405 public double getCost(ParamRetriever paramRetriever, int level, Double flt) { 406 if (level==0 && flt!=null) { 407 double cost = 408 (iNrConflictsWeight[level]==0.0?0.0:iNrConflictsWeight[level]*paramRetriever.nrContlicts())+ 409 (iNrWeightedConflictsWeight[level]==0.0?0.0:iNrWeightedConflictsWeight[level]*paramRetriever.weightedConflicts())+ 410 (iNrPotentialConflictsWeight[level]==0.0?0.0:iNrPotentialConflictsWeight[level]*paramRetriever.potentialConflicts(3))+ 411 (iDeltaTimePreferenceWeight[level]==0.0?0.0:iDeltaTimePreferenceWeight[level]*paramRetriever.deltaTimePreference())+ 412 (iSumConstrPreferencesWeight[level]==0.0?0.0:iSumConstrPreferencesWeight[level]*paramRetriever.constrPreference())+ 413 (iSumRoomPreferencesWeight[level]==0.0?0.0:iSumRoomPreferencesWeight[level]*paramRetriever.roomPreference())+ 414 (iSumTimePreferencesWeight[level]==0.0?0.0:iSumTimePreferencesWeight[level]*paramRetriever.timePreference())+ 415 (iNrAssignmentsWeight[level]==0.0?0.0:iNrAssignmentsWeight[level]*paramRetriever.nrAssignments()) 416 ; 417 if (cost>flt.doubleValue()) return cost; 418 cost += 419 (iUselessSlotsWeight[level]==0.0?0.0:iUselessSlotsWeight[level]*paramRetriever.emptySingleHalfHours())+ 420 (iTooBigRoomWeight[level]==0.0?0.0:iTooBigRoomWeight[level]*paramRetriever.tooBig()) 421 ; 422 if (cost>flt.doubleValue()) return cost; 423 cost += 424 (iPerturbationPenaltyWeight[level]==0.0?0.0:iPerturbationPenaltyWeight[level]*paramRetriever.perturbationsPenalty()) 425 ; 426 if (cost>flt.doubleValue()) return cost; 427 cost += 428 (iDistanceInstructorPreferenceWeight[level]==0.0?0.0:iDistanceInstructorPreferenceWeight[level]*paramRetriever.distanceInstructorPreference()) 429 ; 430 if (cost>flt.doubleValue()) return cost; 431 cost += 432 (iDeptSpreadWeight[level]==0.0?0.0:iDeptSpreadWeight[level]*paramRetriever.deptSpread())+ 433 (iSpreadWeight[level]==0.0?0.0:iSpreadWeight[level]*paramRetriever.spread()) 434 ; 435 if (cost>flt.doubleValue()) return cost; 436 cost += 437 (iNrStudentConflictsWeight[level]==0.0?0.0:iNrStudentConflictsWeight[level]*paramRetriever.sumStudentConflicts())+ 438 (iNrHardStudentConflictsWeight[level]==0.0?0.0:iNrHardStudentConflictsWeight[level]*paramRetriever.sumHardStudentConflicts())+ 439 (iNrCommitedStudentConflictsWeight[level]==0.0?0.0:iNrCommitedStudentConflictsWeight[level]*paramRetriever.sumCommitedStudentConflicts()) 440 ; 441 return cost; 442 } 443 double cost = 444 (iNrConflictsWeight[level]==0.0?0.0:iNrConflictsWeight[level]*paramRetriever.nrContlicts())+ 445 (iNrWeightedConflictsWeight[level]==0.0?0.0:iNrWeightedConflictsWeight[level]*paramRetriever.weightedConflicts())+ 446 (iNrPotentialConflictsWeight[level]==0.0?0.0:iNrPotentialConflictsWeight[level]*paramRetriever.potentialConflicts(3))+ 447 (iDeltaTimePreferenceWeight[level]==0.0?0.0:iDeltaTimePreferenceWeight[level]*paramRetriever.deltaTimePreference())+ 448 (iPerturbationPenaltyWeight[level]==0.0?0.0:iPerturbationPenaltyWeight[level]*paramRetriever.perturbationsPenalty())+ 449 (iNrStudentConflictsWeight[level]==0.0?0.0:iNrStudentConflictsWeight[level]*paramRetriever.sumStudentConflicts())+ 450 (iNrHardStudentConflictsWeight[level]==0.0?0.0:iNrHardStudentConflictsWeight[level]*paramRetriever.sumHardStudentConflicts())+ 451 (iUselessSlotsWeight[level]==0.0?0.0:iUselessSlotsWeight[level]*paramRetriever.emptySingleHalfHours())+ 452 (iSumConstrPreferencesWeight[level]==0.0?0.0:iSumConstrPreferencesWeight[level]*paramRetriever.constrPreference())+ 453 (iSumRoomPreferencesWeight[level]==0.0?0.0:iSumRoomPreferencesWeight[level]*paramRetriever.roomPreference())+ 454 (iSumTimePreferencesWeight[level]==0.0?0.0:iSumTimePreferencesWeight[level]*paramRetriever.timePreference())+ 455 (iNrAssignmentsWeight[level]==0.0?0.0:iNrAssignmentsWeight[level]*paramRetriever.nrAssignments())+ 456 (iTooBigRoomWeight[level]==0.0?0.0:iTooBigRoomWeight[level]*paramRetriever.tooBig())+ 457 (iDeptSpreadWeight[level]==0.0?0.0:iDeptSpreadWeight[level]*paramRetriever.deptSpread())+ 458 (iSpreadWeight[level]==0.0?0.0:iSpreadWeight[level]*paramRetriever.spread())+ 459 (iDistanceInstructorPreferenceWeight[level]==0.0?0.0:iDistanceInstructorPreferenceWeight[level]*paramRetriever.distanceInstructorPreference())+ 460 (iNrCommitedStudentConflictsWeight[level]==0.0?0.0:iNrCommitedStudentConflictsWeight[level]*paramRetriever.sumCommitedStudentConflicts()) 461 ; 462 return cost; 463 } 464 465 public class ParamRetriever { 466 private Lecture iLecture; 467 private Placement iPlacement; 468 private Solution iSolution; 469 private ParamRetriever(Solution solution, Lecture lecture, Placement placement) { 470 iSolution = solution; 471 iLecture = lecture; 472 iPlacement = placement; 473 } 474 475 Collection iConf = null; 476 public Collection conflicts() { 477 if (iConf == null) iConf = iSolution.getModel().conflictValues(iPlacement); 478 return iConf; 479 } 480 481 public long nrContlicts() { 482 return conflicts().size(); 483 } 484 485 private Double iWeightedConflicts = null; 486 public double weightedConflicts() { 487 if (iWeightedConflicts==null) 488 iWeightedConflicts = new Double(iStat==null?0.0:iStat.countRemovals(iSolution.getIteration(), conflicts(), iPlacement)); 489 return iWeightedConflicts.doubleValue(); 490 } 491 492 private Double iPotentialConflicts = null; 493 public double potentialConflicts(int limit) { 494 if (iPotentialConflicts==null) 495 iPotentialConflicts = new Double(iStat==null?0.0:iStat.countPotentialConflicts(iSolution.getIteration(),iPlacement, limit)); 496 return iPotentialConflicts.doubleValue(); 497 } 498 499 Double iDeltaTimePreference = null; 500 public double deltaTimePreference() { 501 if (iDeltaTimePreference==null) { 502 double deltaTimePreference = 0; 503 for (Iterator it1=conflicts().iterator(); it1.hasNext(); ) { 504 Placement placement = (Placement)it1.next(); 505 double timePref = placement.getTimeLocation().getNormalizedPreference(); 506 deltaTimePreference -= timePref - ((Lecture)placement.variable()).getBestTimePreference(); 507 } 508 deltaTimePreference += iPlacement.getTimeLocation().getNormalizedPreference() - iLecture.getBestTimePreference(); 509 iDeltaTimePreference = new Double(deltaTimePreference); 510 } 511 return iDeltaTimePreference.doubleValue(); 512 } 513 514 Double iPerturbationsPenalty = null; 515 public double perturbationsPenalty() { 516 if (iPerturbationsCounter==null) return 0.0; 517 if (iPerturbationsPenalty==null) { 518 iPerturbationsPenalty = new Double(iPerturbationsCounter.getPerturbationPenalty(iSolution.getModel(),iPlacement,conflicts())); 519 } 520 return iPerturbationsPenalty.doubleValue(); 521 } 522 523 public void countStudentConflicts() { 524 long all = 0; 525 int hard = 0; 526 if (!iLecture.isSingleSection()) { 527 for (Enumeration i=iLecture.jenrlConstraints();i.hasMoreElements();) { 528 JenrlConstraint jc = (JenrlConstraint)i.nextElement(); 529 all += jc.jenrl(iLecture,iPlacement); 530 } 531 } else { 532 for (Enumeration i=iLecture.jenrlConstraints();i.hasMoreElements();) { 533 JenrlConstraint jc = (JenrlConstraint)i.nextElement(); 534 long jenrl = jc.jenrl(iLecture,iPlacement); 535 if (((Lecture)jc.another(iLecture)).isSingleSection()) hard += jenrl; 536 all += jenrl; 537 } 538 } 539 iSumStudentConflicts = new Integer((int)all); 540 iSumHardStudentConflicts = new Integer(hard); 541 } 542 543 Integer iSumStudentConflicts = null; 544 public int sumStudentConflicts() { 545 if (iSumStudentConflicts==null) countStudentConflicts(); 546 return iSumStudentConflicts.intValue(); 547 } 548 549 Integer iConstrPreference = null; 550 public int constrPreference() { 551 if (iConstrPreference==null) { 552 int constrPreference = 0; 553 for (Iterator i2=iLecture.groupConstraints().iterator();i2.hasNext();) { 554 GroupConstraint gc = (GroupConstraint)i2.next(); 555 constrPreference += gc.getCurrentPreference(iPlacement); 556 } 557 iConstrPreference = new Integer(constrPreference); 558 } 559 return iConstrPreference.intValue(); 560 } 561 562 Integer iEmptySingleHalfHours = null; 563 public int emptySingleHalfHours() { 564 if (iEmptySingleHalfHours==null) { 565 iEmptySingleHalfHours = new Integer(iPlacement.nrUselessHalfHours()); 566 } 567 return iEmptySingleHalfHours.intValue(); 568 } 569 570 Integer iSumHardStudentConflicts = null; 571 public int sumHardStudentConflicts() { 572 if (iSumHardStudentConflicts==null) countStudentConflicts(); 573 return iSumHardStudentConflicts.intValue(); 574 } 575 576 public int sumCommitedStudentConflicts() { 577 return iLecture.getCommitedConflicts(iPlacement); 578 } 579 580 public int roomPreference() { 581 return iPlacement.sumRoomPreference(); 582 } 583 584 public long nrAssignments() { 585 return iPlacement.countAssignments(); 586 } 587 588 public double timePreference() { 589 return iPlacement.getTimeLocation().getNormalizedPreference(); 590 } 591 592 public int tooBig() { 593 return iPlacement.getTooBigRoomPreference(); 594 } 595 596 Integer iDeptSpreadCache = null; 597 public int deptSpread() { 598 if (iLecture.getDeptSpreadConstraint()==null) return 0; 599 if (iDeptSpreadCache==null) 600 iDeptSpreadCache = new Integer(iLecture.getDeptSpreadConstraint().getPenalty(iPlacement)); 601 return iDeptSpreadCache.intValue(); 602 } 603 604 Integer iSpreadCache = null; 605 public int spread() { 606 if (iLecture.getSpreadConstraints().isEmpty()) return 0; 607 if (iSpreadCache==null) { 608 iSpreadCache = new Integer(iPlacement.getSpreadPenalty()); 609 } 610 return iSpreadCache.intValue(); 611 } 612 613 Integer iDistanceInstructorPreferenceCache = null; 614 public int distanceInstructorPreference() { 615 if (iDistanceInstructorPreferenceCache==null) { 616 int pref = 0; 617 for (Enumeration i2=iLecture.constraints().elements();i2.hasMoreElements();) { 618 Constraint constraint = (Constraint)i2.nextElement(); 619 if (constraint instanceof InstructorConstraint) { 620 pref += ((InstructorConstraint)constraint).getPreference(iPlacement); 621 } 622 } 623 iDistanceInstructorPreferenceCache = new Integer(pref); 624 } 625 return iDistanceInstructorPreferenceCache.intValue(); 626 } 627 } 628 629 public PerturbationsCounter getPerturbationsCounter() { 630 return iPerturbationsCounter; 631 } 632 }