001 package net.sf.cpsolver.coursett.model; 002 003 004 import java.util.Enumeration; 005 import java.util.HashSet; 006 import java.util.Hashtable; 007 import java.util.Locale; 008 import java.util.Set; 009 import java.util.Vector; 010 011 import net.sf.cpsolver.coursett.Constants; 012 import net.sf.cpsolver.coursett.constraint.ClassLimitConstraint; 013 import net.sf.cpsolver.coursett.constraint.DepartmentSpreadConstraint; 014 import net.sf.cpsolver.coursett.constraint.GroupConstraint; 015 import net.sf.cpsolver.coursett.constraint.InstructorConstraint; 016 import net.sf.cpsolver.coursett.constraint.JenrlConstraint; 017 import net.sf.cpsolver.coursett.constraint.RoomConstraint; 018 import net.sf.cpsolver.coursett.constraint.SpreadConstraint; 019 import net.sf.cpsolver.coursett.heuristics.TimetableComparator; 020 import net.sf.cpsolver.coursett.heuristics.UniversalPerturbationsCounter; 021 import net.sf.cpsolver.ifs.constant.ConstantModel; 022 import net.sf.cpsolver.ifs.model.Constraint; 023 import net.sf.cpsolver.ifs.model.Value; 024 import net.sf.cpsolver.ifs.model.Variable; 025 import net.sf.cpsolver.ifs.perturbations.PerturbationsCounter; 026 import net.sf.cpsolver.ifs.solver.Solver; 027 import net.sf.cpsolver.ifs.util.Counter; 028 import net.sf.cpsolver.ifs.util.DataProperties; 029 import net.sf.cpsolver.ifs.util.FastVector; 030 031 032 /** 033 * Timetable model. 034 * 035 * @version 036 * CourseTT 1.1 (University Course Timetabling)<br> 037 * Copyright (C) 2006 Tomáš Müller<br> 038 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 039 * Lazenska 391, 76314 Zlin, Czech Republic<br> 040 * <br> 041 * This library is free software; you can redistribute it and/or 042 * modify it under the terms of the GNU Lesser General Public 043 * License as published by the Free Software Foundation; either 044 * version 2.1 of the License, or (at your option) any later version. 045 * <br><br> 046 * This library is distributed in the hope that it will be useful, 047 * but WITHOUT ANY WARRANTY; without even the implied warranty of 048 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 049 * Lesser General Public License for more details. 050 * <br><br> 051 * You should have received a copy of the GNU Lesser General Public 052 * License along with this library; if not, write to the Free Software 053 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 054 */ 055 056 public class TimetableModel extends ConstantModel { 057 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(TimetableModel.class); 058 private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.00",new java.text.DecimalFormatSymbols(Locale.US)); 059 private long iGlobalRoomPreference = 0; 060 private double iGlobalTimePreference = 0; 061 private long iMinRoomPreference = 0; 062 private long iMaxRoomPreference = 0; 063 private long iBestInstructorDistancePreference = 0; 064 private double iMinTimePreference = 0; 065 private double iMaxTimePreference = 0; 066 private int iBestDepartmentSpreadPenalty = 0; 067 private int iBestSpreadPenalty = 0; 068 private int iBestCommitedStudentConflicts = 0; 069 private int iMaxGroupConstraintPreference = 0; 070 private int iMinGroupConstraintPreference = 0; 071 private Counter iGlobalGroupConstraintPreference = new Counter(); 072 private Counter iViolatedStudentConflicts = new Counter(); 073 private Counter iViolatedHardStudentConflicts = new Counter(); 074 private Counter iViolatedDistanceStudentConflicts = new Counter(); 075 private Counter iCommittedStudentConflictsCounter = new Counter(); 076 private FastVector iInstructorConstraints = new FastVector(); 077 private FastVector iJenrlConstraints = new FastVector(); 078 private FastVector iRoomConstraints = new FastVector(); 079 private FastVector iDepartmentSpreadConstraints = new FastVector(); 080 private FastVector iSpreadConstraints = new FastVector(); 081 private FastVector iGroupConstraints = new FastVector(); 082 private FastVector iClassLimitConstraints = new FastVector(); 083 private DataProperties iProperties = null; 084 private TimetableComparator iCmp = null; 085 private UniversalPerturbationsCounter iPertCnt = null; 086 private int iYear = -1; 087 088 private HashSet iAllStudents = new HashSet(); 089 090 /** Back-to-back classes: maximal distance for no prefernce */ 091 private double iInstructorNoPreferenceLimit = 0.0; 092 /** Back-to-back classes: maximal distance for discouraged prefernce */ 093 private double iInstructorDiscouragedLimit = 5.0; 094 /** Back-to-back classes: maximal distance for strongly discouraged prefernce (everything above is prohibited) */ 095 private double iInstructorProhibitedLimit = 20.0; 096 097 private double iStudentDistanceLimit = 67.0; 098 private double iStudentDistanceLimit75min = 100.0; 099 100 public TimetableModel(DataProperties properties) { 101 super(); 102 iProperties = properties; 103 iInstructorNoPreferenceLimit = iProperties.getPropertyDouble("Instructor.NoPreferenceLimit", iInstructorNoPreferenceLimit); 104 iInstructorDiscouragedLimit = iProperties.getPropertyDouble("Instructor.DiscouragedLimit",iInstructorDiscouragedLimit); 105 iInstructorProhibitedLimit = iProperties.getPropertyDouble("Instructor.ProhibitedLimit",iInstructorProhibitedLimit); 106 iStudentDistanceLimit = iProperties.getPropertyDouble("Student.DistanceLimit",iStudentDistanceLimit); 107 iStudentDistanceLimit75min = iProperties.getPropertyDouble("Student.DistanceLimit75min",iStudentDistanceLimit75min); 108 iCmp = new TimetableComparator(properties); 109 iPertCnt = new UniversalPerturbationsCounter(properties); 110 if (properties.getPropertyBoolean("OnFlySectioning.Enabled", false)) addModelListener(new OnFlySectioning(this)); 111 } 112 113 public double getInstructorNoPreferenceLimit() { 114 return iInstructorNoPreferenceLimit; 115 } 116 117 public double getInstructorDiscouragedLimit() { 118 return iInstructorDiscouragedLimit; 119 } 120 121 public double getInstructorProhibitedLimit() { 122 return iInstructorProhibitedLimit; 123 } 124 125 public double getStudentDistanceLimit() { 126 return iStudentDistanceLimit; 127 } 128 129 public double getStudentDistanceLimit75min() { 130 return iStudentDistanceLimit75min; 131 } 132 133 public boolean init(Solver solver) { 134 iCmp = new TimetableComparator(solver.getProperties()); 135 iPertCnt = new UniversalPerturbationsCounter(solver.getProperties()); 136 return super.init(solver); 137 } 138 139 public void addVariable(Variable variable) { 140 super.addVariable(variable); 141 Lecture lecture = (Lecture)variable; 142 if (lecture.isCommitted()) return; 143 double[] minMaxTimePref = lecture.getMinMaxTimePreference(); 144 iMinTimePreference += minMaxTimePref[0]; 145 iMaxTimePreference += minMaxTimePref[1]; 146 int[] minMaxRoomPref = lecture.getMinMaxRoomPreference(); 147 iMinRoomPreference += minMaxRoomPref[0]; 148 iMaxRoomPreference += minMaxRoomPref[1]; 149 } 150 151 public void removeVariable(Variable variable) { 152 super.removeVariable(variable); 153 Lecture lecture = (Lecture)variable; 154 if (lecture.isCommitted()) return; 155 double[] minMaxTimePref = lecture.getMinMaxTimePreference(); 156 iMinTimePreference -= minMaxTimePref[0]; 157 iMaxTimePreference -= minMaxTimePref[1]; 158 int[] minMaxRoomPref = lecture.getMinMaxRoomPreference(); 159 iMinRoomPreference -= minMaxRoomPref[0]; 160 iMaxRoomPreference -= minMaxRoomPref[1]; 161 } 162 163 164 public DataProperties getProperties() { return iProperties; } 165 166 /** Overall room preference */ 167 public long getGlobalRoomPreference() { return iGlobalRoomPreference; } 168 /** Overall time preference */ 169 public double getGlobalTimePreference() { return iGlobalTimePreference; } 170 /** Number of student conflicts */ 171 public long getViolatedStudentConflicts() { return iViolatedStudentConflicts.get(); } 172 /** Number of student conflicts */ 173 public long countViolatedStudentConflicts() { 174 long studentConflicts = 0; 175 for (Enumeration it1=iJenrlConstraints.elements();it1.hasMoreElements();) { 176 JenrlConstraint jenrl = (JenrlConstraint)it1.nextElement(); 177 Lecture a = (Lecture)jenrl.first(); 178 Lecture b = (Lecture)jenrl.second(); 179 //if (a.getAssignment()!=null && b.getAssignment()!=null && JenrlConstraint.isInConflict((Placement)a.getAssignment(),(Placement)b.getAssignment())) 180 if (jenrl.isInConflict()) 181 studentConflicts+=jenrl.getJenrl(); 182 } 183 return studentConflicts; 184 } 185 /** Number of student conflicts */ 186 public Counter getViolatedStudentConflictsCounter() { return iViolatedStudentConflicts; } 187 public Counter getViolatedHardStudentConflictsCounter() { return iViolatedHardStudentConflicts; } 188 public Counter getViolatedDistanceStudentConflictsCounter() { return iViolatedDistanceStudentConflicts; } 189 190 /** Overall group constraint preference */ 191 public long getGlobalGroupConstraintPreference() { return iGlobalGroupConstraintPreference.get(); } 192 /** Overall group constraint preference */ 193 public Counter getGlobalGroupConstraintPreferenceCounter() { return iGlobalGroupConstraintPreference; } 194 /** Overall instructor distance (back-to-back) preference */ 195 public long getInstructorDistancePreference() { 196 long pref = 0; 197 for (Enumeration it1=iInstructorConstraints.elements();it1.hasMoreElements();) { 198 InstructorConstraint constraint = (InstructorConstraint)it1.nextElement(); 199 pref+=constraint.getPreference(); 200 } 201 return pref; 202 } 203 /** The worst instructor distance (back-to-back) preference */ 204 public long getInstructorWorstDistancePreference() { 205 long pref = 0; 206 for (Enumeration it1=iInstructorConstraints.elements();it1.hasMoreElements();) { 207 InstructorConstraint constraint = (InstructorConstraint)it1.nextElement(); 208 pref+=constraint.getWorstPreference(); 209 } 210 return pref; 211 } 212 /** Overall number of useless time slots */ 213 public long getUselessSlots() { 214 long uselessSlots = 0; 215 for (Enumeration it1=iRoomConstraints.elements();it1.hasMoreElements();) { 216 RoomConstraint constraint = (RoomConstraint)it1.nextElement(); 217 uselessSlots+=((RoomConstraint)constraint).countUselessSlots(); 218 } 219 return uselessSlots; 220 } 221 /** Overall number of useless time slots */ 222 public long getUselessHalfHours() { 223 long uselessSlots = 0; 224 for (Enumeration it1=iRoomConstraints.elements();it1.hasMoreElements();) { 225 RoomConstraint constraint = (RoomConstraint)it1.nextElement(); 226 uselessSlots+=((RoomConstraint)constraint).countUselessSlotsHalfHours(); 227 } 228 return uselessSlots; 229 } 230 /** Overall number of useless time slots */ 231 public long getBrokenTimePatterns() { 232 long uselessSlots = 0; 233 for (Enumeration it1=iRoomConstraints.elements();it1.hasMoreElements();) { 234 RoomConstraint constraint = (RoomConstraint)it1.nextElement(); 235 uselessSlots+=((RoomConstraint)constraint).countUselessSlotsBrokenTimePatterns(); 236 } 237 return uselessSlots; 238 } 239 /** Overall number of student conflicts caused by distancies (back-to-back classes are too far)*/ 240 public long getStudentDistanceConflicts() { 241 /* 242 if (iViolatedDistanceStudentConflicts.get()!=countStudentDistanceConflicts()) { 243 System.err.println("TimetableModel.getStudentDistanceConflicts() is not working properly"); 244 } 245 */ 246 return iViolatedDistanceStudentConflicts.get(); 247 } 248 public long countStudentDistanceConflicts() { 249 long nrConflicts = 0; 250 for (Enumeration it1=iJenrlConstraints.elements();it1.hasMoreElements();) { 251 JenrlConstraint jenrl = (JenrlConstraint)it1.nextElement(); 252 if (jenrl.isInConflict() && 253 !((Placement)jenrl.first().getAssignment()).getTimeLocation().hasIntersection(((Placement)jenrl.second().getAssignment()).getTimeLocation())) 254 nrConflicts += jenrl.getJenrl(); 255 } 256 return nrConflicts; 257 } 258 /** Overall hard student conflicts (student conflict between single section classes) */ 259 public long getHardStudentConflicts() { 260 /* 261 if (iViolatedHardStudentConflicts.get()!=countHardStudentConflicts()) { 262 System.err.println("TimetableModel.getHardStudentConflicts() is not working properly"); 263 } 264 */ 265 return iViolatedHardStudentConflicts.get(); 266 } 267 public long countHardStudentConflicts() { 268 long hardStudentConflicts = 0; 269 for (Enumeration it1=iJenrlConstraints.elements();it1.hasMoreElements();) { 270 JenrlConstraint jenrl = (JenrlConstraint)it1.nextElement(); 271 if (jenrl.isInConflict()) { 272 Lecture l1 = (Lecture)jenrl.first(); 273 Lecture l2 = (Lecture)jenrl.second(); 274 if (l1.areStudentConflictsHard(l2)) 275 hardStudentConflicts+=jenrl.getJenrl(); 276 } 277 } 278 return hardStudentConflicts; 279 } 280 public Counter getCommittedStudentConflictsCounter() { return iCommittedStudentConflictsCounter; } 281 public int getCommitedStudentConflicts() { 282 /* 283 if (iCommittedStudentConflictsCounter.get()!=countCommitedStudentConflicts()) { 284 System.err.println("TimetableModel.getCommitedStudentConflicts() is not working properly"); 285 } 286 */ 287 return (int)iCommittedStudentConflictsCounter.get(); 288 } 289 public int countCommitedStudentConflicts() { 290 int commitedStudentConflicts = 0; 291 for (Enumeration e=assignedVariables().elements();e.hasMoreElements();) { 292 Lecture lecture = (Lecture)e.nextElement(); 293 commitedStudentConflicts+=lecture.getCommitedConflicts((Placement)lecture.getAssignment()); 294 } 295 return commitedStudentConflicts; 296 } 297 298 /** When a value is assigned to a variable -- update gloval preferences */ 299 public void afterAssigned(long iteration, Value value) { 300 super.afterAssigned(iteration, value); 301 if (value==null) return; 302 Placement placement = (Placement)value; 303 iGlobalRoomPreference += placement.sumRoomPreference(); 304 iGlobalTimePreference += placement.getTimeLocation().getNormalizedPreference(); 305 } 306 /** When a value is unassigned from a variable -- update gloval preferences */ 307 public void afterUnassigned(long iteration, Value value) { 308 super.afterUnassigned(iteration, value); 309 if (value==null) return; 310 Placement placement = (Placement)value; 311 iGlobalRoomPreference -= placement.sumRoomPreference(); 312 iGlobalTimePreference -= placement.getTimeLocation().getNormalizedPreference(); 313 } 314 315 /** Student final sectioning (switching students between sections of the same class in order to minimize overall number of student conflicts) */ 316 public void switchStudents() { 317 FinalSectioning sect = new FinalSectioning(this); 318 sect.run(); 319 } 320 321 public String toString() { 322 return "TimetableModel{"+ 323 "\n super="+super.toString()+ 324 "\n studentConflicts="+iViolatedStudentConflicts.get()+ 325 // "\n studentConflicts(violated room distance)="+iViolatedRoomDistanceStudentConflicts.get()+ 326 // "\n studentPreferences="+iRoomDistanceStudentPreference.get()+ 327 "\n roomPreferences="+iGlobalRoomPreference+ 328 "\n timePreferences="+iGlobalTimePreference+ 329 "\n groupConstraintPreferences="+iGlobalGroupConstraintPreference.get()+ 330 "\n}"; 331 } 332 333 /** Overall number of too big rooms (rooms with more than 3/2 seats than needed) */ 334 public int countTooBigRooms() { 335 int tooBigRooms=0; 336 for (Enumeration it1=assignedVariables().elements();it1.hasMoreElements();) { 337 Lecture lecture = (Lecture)it1.nextElement(); 338 if (lecture.getAssignment()==null) continue; 339 Placement placement = (Placement)lecture.getAssignment(); 340 tooBigRooms += placement.getTooBigRoomPreference(); 341 } 342 return tooBigRooms; 343 } 344 345 /** Overall departmental spread penalty */ 346 public int getDepartmentSpreadPenalty() { 347 if (iDepartmentSpreadConstraints.isEmpty()) return 0; 348 int penalty = 0; 349 for (Enumeration e=iDepartmentSpreadConstraints.elements();e.hasMoreElements();) { 350 DepartmentSpreadConstraint c = (DepartmentSpreadConstraint)e.nextElement(); 351 penalty += ((DepartmentSpreadConstraint)c).getPenalty(); 352 } 353 return penalty; 354 } 355 356 /** Overall spread penalty */ 357 public int getSpreadPenalty() { 358 if (iSpreadConstraints.isEmpty()) return 0; 359 int penalty = 0; 360 for (Enumeration e=iSpreadConstraints.elements();e.hasMoreElements();) { 361 SpreadConstraint c = (SpreadConstraint)e.nextElement(); 362 penalty += ((SpreadConstraint)c).getPenalty(); 363 } 364 return penalty; 365 } 366 367 public java.util.Hashtable getBounds() { 368 Hashtable ret = new Hashtable(); 369 ret.put("Room preferences min", ""+iMinRoomPreference); 370 ret.put("Room preferences max", ""+iMaxRoomPreference); 371 ret.put("Time preferences min", ""+iMinTimePreference); 372 ret.put("Time preferences max", ""+iMaxTimePreference); 373 ret.put("Distribution preferences min", ""+iMinGroupConstraintPreference); 374 ret.put("Distribution preferences max", ""+iMaxGroupConstraintPreference); 375 if (getProperties().getPropertyBoolean("General.UseDistanceConstraints",false)) { 376 ret.put("Back-to-back instructor preferences max", ""+getInstructorWorstDistancePreference()); 377 } 378 ret.put("Too big rooms max", ""+(Constants.sPreferenceLevelStronglyDiscouraged*variables().size())); 379 ret.put("Useless half-hours", ""+(Constants.sPreferenceLevelStronglyDiscouraged*getRoomConstraints().size()*Constants.SLOTS_PER_DAY_NO_EVENINGS*Constants.NR_DAYS_WEEK)); 380 return ret; 381 } 382 383 /** Global info */ 384 public java.util.Hashtable getInfo() { 385 Hashtable ret = super.getInfo(); 386 ret.put("Memory usage", getMem()); 387 ret.put("Room preferences", getPerc(iGlobalRoomPreference,iMinRoomPreference,iMaxRoomPreference)+"% ("+iGlobalRoomPreference+")"); 388 ret.put("Time preferences", getPerc(iGlobalTimePreference,iMinTimePreference,iMaxTimePreference)+"% ("+sDoubleFormat.format(iGlobalTimePreference)+")"); 389 ret.put("Distribution preferences", getPerc(iGlobalGroupConstraintPreference.get(),iMinGroupConstraintPreference,iMaxGroupConstraintPreference)+"% ("+iGlobalGroupConstraintPreference.get()+")"); 390 int commitedStudentConflicts = getCommitedStudentConflicts(); 391 ret.put("Student conflicts", (commitedStudentConflicts+getViolatedStudentConflicts())+" [committed:"+commitedStudentConflicts+", hard:"+getHardStudentConflicts()+"]"); 392 if (getProperties().getPropertyBoolean("General.UseDistanceConstraints",false)) { 393 ret.put("Student conflicts", (commitedStudentConflicts+getViolatedStudentConflicts())+" [committed:"+commitedStudentConflicts+", distance:"+getStudentDistanceConflicts()+", hard:"+getHardStudentConflicts()+"]"); 394 ret.put("Back-to-back instructor preferences", getPerc(getInstructorDistancePreference(),0,getInstructorWorstDistancePreference())+"% ("+getInstructorDistancePreference()+")"); 395 } 396 if (getProperties().getPropertyBoolean("General.DeptBalancing", false)) { 397 ret.put("Department balancing penalty", sDoubleFormat.format(((double)getDepartmentSpreadPenalty())/12.0)); 398 } 399 ret.put("Same subpart balancing penalty", sDoubleFormat.format(((double)getSpreadPenalty())/12.0)); 400 ret.put("Too big rooms", getPercRev(countTooBigRooms(),0,Constants.sPreferenceLevelStronglyDiscouraged*variables().size())+"% ("+countTooBigRooms()+")"); 401 ret.put("Useless half-hours", getPercRev(getUselessSlots(),0,Constants.sPreferenceLevelStronglyDiscouraged*getRoomConstraints().size()*Constants.SLOTS_PER_DAY_NO_EVENINGS*Constants.NR_DAYS_WEEK)+"% ("+getUselessHalfHours()+" + "+getBrokenTimePatterns()+")"); 402 return ret; 403 } 404 405 public java.util.Hashtable getInfo(Vector variables) { 406 Hashtable ret = super.getInfo(variables); 407 ret.put("Memory usage", getMem()); 408 409 int roomPref = 0, minRoomPref = 0, maxRoomPref = 0; 410 double timePref = 0, minTimePref = 0, maxTimePref = 0; 411 double grPref = 0, minGrPref = 0, maxGrPref = 0; 412 long allSC = 0, hardSC = 0, distSC = 0; 413 int instPref = 0, worstInstrPref = 0; 414 int spreadPen = 0, deptSpreadPen = 0; 415 int tooBigRooms = 0; 416 int rcs = 0, uselessSlots = 0, uselessSlotsHH = 0, uselessSlotsBTP = 0; 417 418 HashSet used = new HashSet(); 419 420 for (Enumeration e=variables.elements();e.hasMoreElements();) { 421 Lecture lecture = (Lecture)e.nextElement(); 422 if (lecture.isCommitted()) continue; 423 Placement placement = (Placement)lecture.getAssignment(); 424 425 int[] minMaxRoomPref = lecture.getMinMaxRoomPreference(); 426 minRoomPref += minMaxRoomPref[0]; 427 maxRoomPref += minMaxRoomPref[1]; 428 429 double[] minMaxTimePref = lecture.getMinMaxTimePreference(); 430 minTimePref += minMaxTimePref[0]; 431 maxTimePref += minMaxTimePref[1]; 432 433 if (placement!=null) { 434 roomPref += placement.getRoomPreference(); 435 timePref += placement.getTimeLocation().getNormalizedPreference(); 436 tooBigRooms += placement.getTooBigRoomPreference(); 437 } 438 439 for (Enumeration f=lecture.constraints().elements();f.hasMoreElements();) { 440 Constraint c = (Constraint)f.nextElement(); 441 if (!used.add(c)) continue; 442 443 if (c instanceof InstructorConstraint) { 444 InstructorConstraint ic = (InstructorConstraint)c; 445 instPref += ic.getPreference(); 446 worstInstrPref += ic.getWorstPreference(); 447 } 448 449 if (c instanceof DepartmentSpreadConstraint) { 450 DepartmentSpreadConstraint dsc = (DepartmentSpreadConstraint)c; 451 deptSpreadPen += dsc.getPenalty(); 452 } else if (c instanceof SpreadConstraint) { 453 SpreadConstraint sc = (SpreadConstraint)c; 454 spreadPen += sc.getPenalty(); 455 } 456 457 if (c instanceof GroupConstraint) { 458 GroupConstraint gc = (GroupConstraint)c; 459 if (gc.isHard()) continue; 460 minGrPref += Math.min(gc.getPreference(),0); 461 maxGrPref += Math.max(gc.getPreference(),0); 462 grPref += gc.getCurrentPreference(); 463 } 464 465 if (c instanceof JenrlConstraint) { 466 JenrlConstraint jc = (JenrlConstraint)c; 467 if (!jc.isInConflict() || !jc.isOfTheSameProblem()) continue; 468 Lecture l1 = (Lecture)jc.first(); 469 Lecture l2 = (Lecture)jc.second(); 470 allSC += jc.getJenrl(); 471 if (l1.areStudentConflictsHard(l2)) 472 hardSC += jc.getJenrl(); 473 Placement p1 = (Placement)l1.getAssignment(); 474 Placement p2 = (Placement)l2.getAssignment(); 475 if (!p1.getTimeLocation().hasIntersection(p2.getTimeLocation())) 476 distSC += jc.getJenrl(); 477 } 478 479 if (c instanceof RoomConstraint) { 480 RoomConstraint rc = (RoomConstraint)c; 481 uselessSlots+=rc.countUselessSlots(); 482 uselessSlotsHH+=rc.countUselessSlotsHalfHours(); 483 uselessSlotsBTP+=rc.countUselessSlotsBrokenTimePatterns(); 484 rcs ++; 485 } 486 } 487 } 488 489 490 ret.put("Room preferences", getPerc(roomPref,minRoomPref,maxRoomPref)+"% ("+roomPref+")"); 491 ret.put("Time preferences", getPerc(timePref,minTimePref,maxTimePref)+"% ("+sDoubleFormat.format(timePref)+")"); 492 ret.put("Distribution preferences", getPerc(grPref,minGrPref,maxGrPref)+"% ("+grPref+")"); 493 ret.put("Student conflicts", allSC+" [committed:"+0+", hard:"+hardSC+"]"); 494 if (getProperties().getPropertyBoolean("General.UseDistanceConstraints",false)) { 495 ret.put("Student conflicts", allSC+" [committed:"+0+", distance:"+distSC+", hard:"+hardSC+"]"); 496 ret.put("Back-to-back instructor preferences", getPerc(instPref,0,worstInstrPref)+"% ("+instPref+")"); 497 } 498 if (getProperties().getPropertyBoolean("General.DeptBalancing", false)) { 499 ret.put("Department balancing penalty", sDoubleFormat.format(((double)deptSpreadPen)/12.0)); 500 } 501 ret.put("Same subpart balancing penalty", sDoubleFormat.format(((double)spreadPen)/12.0)); 502 ret.put("Too big rooms", getPercRev(tooBigRooms,0,Constants.sPreferenceLevelStronglyDiscouraged*variables.size())+"% ("+tooBigRooms+")"); 503 ret.put("Useless half-hours", getPercRev(uselessSlots,0,Constants.sPreferenceLevelStronglyDiscouraged*rcs*Constants.SLOTS_PER_DAY_NO_EVENINGS*Constants.NR_DAYS_WEEK)+"% ("+uselessSlotsHH+" + "+uselessSlotsBTP+")"); 504 505 return ret; 506 } 507 508 private int iBestTooBigRooms; 509 private long iBestUselessSlots; 510 private double iBestGlobalTimePreference; 511 private long iBestGlobalRoomPreference; 512 private long iBestGlobalGroupConstraintPreference; 513 private long iBestViolatedStudentConflicts; 514 private long iBestHardStudentConflicts; 515 516 /** Overall number of too big rooms of the best solution ever found */ 517 public int bestTooBigRooms() { return iBestTooBigRooms; } 518 /** Overall number of useless slots of the best solution ever found */ 519 public long bestUselessSlots() { return iBestUselessSlots;} 520 /** Overall time preference of the best solution ever found */ 521 public double bestGlobalTimePreference() { return iBestGlobalTimePreference;} 522 /** Overall room preference of the best solution ever found */ 523 public long bestGlobalRoomPreference() { return iBestGlobalRoomPreference;} 524 /** Overall group constraint preference of the best solution ever found */ 525 public long bestGlobalGroupConstraintPreference() { return iBestGlobalGroupConstraintPreference;} 526 /** Overall number of student conflicts of the best solution ever found */ 527 public long bestViolatedStudentConflicts() { return iBestViolatedStudentConflicts;} 528 /** Overall number of student conflicts between single section classes of the best solution ever found */ 529 public long bestHardStudentConflicts() { return iBestHardStudentConflicts;} 530 /** Overall instructor distance preference of the best solution ever found */ 531 public long bestInstructorDistancePreference() { return iBestInstructorDistancePreference; } 532 /** Overall departmental spread penalty of the best solution ever found */ 533 public int bestDepartmentSpreadPenalty() { return iBestDepartmentSpreadPenalty; } 534 public int bestSpreadPenalty() { return iBestSpreadPenalty; } 535 public int bestCommitedStudentConflicts() { return iBestCommitedStudentConflicts; } 536 537 public void saveBest() { 538 super.saveBest(); 539 iBestTooBigRooms = countTooBigRooms(); 540 iBestUselessSlots = getUselessSlots(); 541 iBestGlobalTimePreference = getGlobalTimePreference(); 542 iBestGlobalRoomPreference = getGlobalRoomPreference(); 543 iBestGlobalGroupConstraintPreference = getGlobalGroupConstraintPreference(); 544 iBestViolatedStudentConflicts = getViolatedStudentConflicts(); 545 iBestHardStudentConflicts = getHardStudentConflicts(); 546 iBestInstructorDistancePreference = getInstructorDistancePreference(); 547 iBestDepartmentSpreadPenalty = getDepartmentSpreadPenalty(); 548 iBestSpreadPenalty = getSpreadPenalty(); 549 iBestCommitedStudentConflicts = getCommitedStudentConflicts(); 550 } 551 552 public void addConstraint(Constraint constraint) { 553 super.addConstraint(constraint); 554 if (constraint instanceof InstructorConstraint) { 555 iInstructorConstraints.addElement(constraint); 556 } else if (constraint instanceof JenrlConstraint) { 557 iJenrlConstraints.addElement(constraint); 558 } else if (constraint instanceof RoomConstraint) { 559 iRoomConstraints.addElement(constraint); 560 } else if (constraint instanceof DepartmentSpreadConstraint) { 561 iDepartmentSpreadConstraints.addElement(constraint); 562 } else if (constraint instanceof SpreadConstraint) { 563 iSpreadConstraints.addElement(constraint); 564 } else if (constraint instanceof ClassLimitConstraint) { 565 iClassLimitConstraints.addElement(constraint); 566 } else if (constraint instanceof GroupConstraint) { 567 iGroupConstraints.addElement(constraint); 568 if (!constraint.isHard()) { 569 GroupConstraint gc = (GroupConstraint)constraint; 570 iMinGroupConstraintPreference += Math.min(gc.getPreference(),0); 571 iMaxGroupConstraintPreference += Math.max(gc.getPreference(),0); 572 } 573 } 574 } 575 public void removeConstraint(Constraint constraint) { 576 super.removeConstraint(constraint); 577 if (constraint instanceof InstructorConstraint) { 578 iInstructorConstraints.removeElement(constraint); 579 } else if (constraint instanceof JenrlConstraint) { 580 iJenrlConstraints.removeElement(constraint); 581 } else if (constraint instanceof RoomConstraint) { 582 iRoomConstraints.removeElement(constraint); 583 } else if (constraint instanceof DepartmentSpreadConstraint) { 584 iDepartmentSpreadConstraints.removeElement(constraint); 585 } else if (constraint instanceof SpreadConstraint) { 586 iSpreadConstraints.removeElement(constraint); 587 } else if (constraint instanceof ClassLimitConstraint) { 588 iClassLimitConstraints.removeElement(constraint); 589 } else if (constraint instanceof GroupConstraint) { 590 iGroupConstraints.removeElement(constraint); 591 } 592 } 593 594 /** The list of all instructor constraints */ 595 public Vector getInstructorConstraints() { return iInstructorConstraints; } 596 /** The list of all group constraints */ 597 public Vector getGroupConstraints() { return iGroupConstraints; } 598 /** The list of all jenrl constraints */ 599 public Vector getJenrlConstraints() { return iJenrlConstraints; } 600 /** The list of all room constraints */ 601 public Vector getRoomConstraints() { return iRoomConstraints; } 602 /** The list of all departmental spread constraints */ 603 public Vector getDepartmentSpreadConstraints() { return iDepartmentSpreadConstraints; } 604 public Vector getSpreadConstraints() { return iSpreadConstraints; } 605 public Vector getClassLimitConstraints() { return iClassLimitConstraints; } 606 /** Max capacity for too big rooms (3/2 of the number of students) */ 607 public double getTotalValue() { 608 return iCmp.currentValue(this,iPertCnt); 609 } 610 public double getTotalValue(Vector variables) { 611 return iCmp.currentValue(this,iPertCnt, variables); 612 } 613 614 public int getYear() { return iYear; } 615 public void setYear(int year) { iYear=year; } 616 617 public TimetableComparator getTimetableComparator() { return iCmp;} 618 public PerturbationsCounter getPerturbationsCounter() { return iPertCnt; } 619 620 public Set getAllStudents() { 621 return iAllStudents; 622 } 623 public void addStudent(Student student) { 624 iAllStudents.add(student); 625 } 626 public void removeStudent(Student student) { 627 iAllStudents.remove(student); 628 } 629 630 /** Returns amount of allocated memory. 631 * @return amount of allocated memory to be written in the log 632 */ 633 public static synchronized String getMem() { 634 Runtime rt = Runtime.getRuntime(); 635 return sDoubleFormat.format(((double)(rt.totalMemory()-rt.freeMemory()))/1048576)+"M"; 636 } 637 }