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