001 package net.sf.cpsolver.coursett; 002 003 004 import java.io.File; 005 import java.text.SimpleDateFormat; 006 import java.util.BitSet; 007 import java.util.Calendar; 008 import java.util.Collection; 009 import java.util.Date; 010 import java.util.Enumeration; 011 import java.util.HashSet; 012 import java.util.Hashtable; 013 import java.util.Iterator; 014 import java.util.List; 015 import java.util.Locale; 016 import java.util.Map; 017 import java.util.Set; 018 import java.util.Vector; 019 020 import org.dom4j.Document; 021 import org.dom4j.Element; 022 import org.dom4j.io.SAXReader; 023 024 import net.sf.cpsolver.coursett.constraint.ClassLimitConstraint; 025 import net.sf.cpsolver.coursett.constraint.DepartmentSpreadConstraint; 026 import net.sf.cpsolver.coursett.constraint.DiscouragedRoomConstraint; 027 import net.sf.cpsolver.coursett.constraint.GroupConstraint; 028 import net.sf.cpsolver.coursett.constraint.InstructorConstraint; 029 import net.sf.cpsolver.coursett.constraint.JenrlConstraint; 030 import net.sf.cpsolver.coursett.constraint.MinimizeNumberOfUsedGroupsOfTime; 031 import net.sf.cpsolver.coursett.constraint.MinimizeNumberOfUsedRoomsConstraint; 032 import net.sf.cpsolver.coursett.constraint.RoomConstraint; 033 import net.sf.cpsolver.coursett.constraint.SpreadConstraint; 034 import net.sf.cpsolver.coursett.model.Configuration; 035 import net.sf.cpsolver.coursett.model.InitialSectioning; 036 import net.sf.cpsolver.coursett.model.Lecture; 037 import net.sf.cpsolver.coursett.model.Placement; 038 import net.sf.cpsolver.coursett.model.RoomLocation; 039 import net.sf.cpsolver.coursett.model.RoomSharingModel; 040 import net.sf.cpsolver.coursett.model.Student; 041 import net.sf.cpsolver.coursett.model.TimeLocation; 042 import net.sf.cpsolver.coursett.model.TimetableModel; 043 import net.sf.cpsolver.ifs.model.Constraint; 044 import net.sf.cpsolver.ifs.model.Value; 045 import net.sf.cpsolver.ifs.model.Variable; 046 import net.sf.cpsolver.ifs.solution.Solution; 047 import net.sf.cpsolver.ifs.solver.Solver; 048 import net.sf.cpsolver.ifs.util.FastVector; 049 import net.sf.cpsolver.ifs.util.Progress; 050 import net.sf.cpsolver.ifs.util.ToolBox; 051 052 053 /** 054 * This class loads the input model from XML file. 055 * <br><br> 056 * Parameters: 057 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr> 058 * <tr><td>General.Input</td><td>{@link String}</td><td>Input XML file</td></tr> 059 * <tr><td>General.DeptBalancing</td><td>{@link Boolean}</td><td>Use {@link DepartmentSpreadConstraint}</td></tr> 060 * <tr><td>General.InteractiveMode</td><td>{@link Boolean}</td><td>Interactive mode (see {@link Lecture#purgeInvalidValues(boolean)})</td></tr> 061 * <tr><td>General.ForcedPerturbances</td><td>{@link Integer}</td><td>For testing of MPP: number of input perturbations, i.e., classes with prohibited intial assignment</td></tr> 062 * <tr><td>General.UseDistanceConstraints</td><td>{@link Boolean}</td><td>Consider distances between buildings</td></tr> 063 * </table> 064 * 065 * @version 066 * CourseTT 1.1 (University Course Timetabling)<br> 067 * Copyright (C) 2006 Tomáš Müller<br> 068 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 069 * Lazenska 391, 76314 Zlin, Czech Republic<br> 070 * <br> 071 * This library is free software; you can redistribute it and/or 072 * modify it under the terms of the GNU Lesser General Public 073 * License as published by the Free Software Foundation; either 074 * version 2.1 of the License, or (at your option) any later version. 075 * <br><br> 076 * This library is distributed in the hope that it will be useful, 077 * but WITHOUT ANY WARRANTY; without even the implied warranty of 078 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 079 * Lesser General Public License for more details. 080 * <br><br> 081 * You should have received a copy of the GNU Lesser General Public 082 * License along with this library; if not, write to the Free Software 083 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 084 */ 085 086 public class TimetableXMLLoader extends TimetableLoader { 087 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(TimetableXMLLoader.class); 088 private static SimpleDateFormat sDF = new SimpleDateFormat("MM/dd"); 089 090 private boolean iDeptBalancing = true; 091 private int iForcedPerturbances = 0; 092 093 private boolean iUseDistanceConstraints; 094 private boolean iInteractiveMode = false; 095 private File iInputFile; 096 097 private Progress iProgress = null; 098 099 public TimetableXMLLoader(TimetableModel model) { 100 super(model); 101 iProgress = Progress.getInstance(getModel()); 102 iInputFile = new File(getModel().getProperties().getProperty("General.Input","."+File.separator+"solution.xml")); 103 iForcedPerturbances = getModel().getProperties().getPropertyInt("General.ForcedPerturbances",0); 104 iDeptBalancing = getModel().getProperties().getPropertyBoolean("General.DeptBalancing",true); 105 iUseDistanceConstraints = getModel().getProperties().getPropertyBoolean("General.UseDistanceConstraints", true); 106 iInteractiveMode = getModel().getProperties().getPropertyBoolean("General.InteractiveMode", iInteractiveMode); 107 } 108 109 private Solver iSolver = null; 110 public void setSolver(Solver solver) { 111 iSolver = solver; 112 } 113 public Solver getSolver() { 114 return iSolver; 115 } 116 117 public void setInputFile(File inputFile) { 118 iInputFile=inputFile; 119 } 120 121 public void load() throws Exception { 122 load(null); 123 } 124 125 /* 126 public static boolean match(TimePatternModel model, TimeLocation time) { 127 if (model.getNrMeetings()!=time.getNrMeetings()) return false; 128 if (model.getSlotsPerMtg()!=6*time.getLength()) return false; 129 int matchTime = -1, matchDays = -1; 130 for (int i=0;i<model.getNrDays();i++) { 131 if (time.getDayCode()==model.getDayCode(i)) 132 matchDays = i; 133 } 134 for (int i=0;i<model.getNrTimes();i++) { 135 if (90+time.getStartSlot()*6==model.getStartSlot(i)) 136 matchTime = i; 137 } 138 return matchTime>=0 && matchDays>=0; 139 } 140 141 Vector iAllTimePatterns = null; 142 Hashtable iClasses = new Hashtable(); 143 private TimeLocation transformTimePattern(Long classId, TimeLocation oldLocation) { 144 if (iAllTimePatterns==null) { 145 iAllTimePatterns = TimePattern.findAll(getModel().getProperties().getProperty("Data.Initiative"), getModel().getProperties().getProperty("Data.Term").substring(4), null); 146 Collections.sort(iAllTimePatterns); 147 } 148 TimeLocation newLocation = new TimeLocation( 149 oldLocation.getDayCode(), 150 90+oldLocation.getStartSlot()*6, 151 oldLocation.getLength()*6, 152 oldLocation.getPreference(), 153 oldLocation.getNormalizedPreference(), 154 oldLocation.getDatePatternId(), 155 oldLocation.getDatePatternName(), 156 oldLocation.getWeekCode(), 157 oldLocation.getBreakTime()); 158 159 if (classId!=null) { 160 Class_ clazz = (Class_)iClasses.get(classId); 161 if (clazz==null) { 162 clazz = (new Class_DAO()).get(classId); 163 if (clazz!=null) 164 iClasses.put(classId, clazz); 165 } 166 if (clazz!=null) { 167 for (Iterator i=clazz.effectiveTimePatterns().iterator();i.hasNext();) { 168 TimePattern tp = (TimePattern)i.next(); 169 if (LoadTimePreferences.match(tp.getTimePatternModel(),oldLocation)) { 170 newLocation.setTimePatternId(tp.getUniqueId()); 171 break; 172 } 173 } 174 } 175 } 176 if (newLocation.getTimePatternId()==null) { 177 for (Enumeration e=iAllTimePatterns.elements();e.hasMoreElements();) { 178 TimePattern tp = (TimePattern)e.nextElement(); 179 if (LoadTimePreferences.match(tp.getTimePatternModel(),oldLocation)) { 180 newLocation.setTimePatternId(tp.getUniqueId()); 181 break; 182 } 183 } 184 } 185 return newLocation; 186 } 187 */ 188 189 private static BitSet createBitSet(String bitString) { 190 BitSet ret = new BitSet(bitString.length()); 191 for (int i=0;i<bitString.length();i++) 192 if (bitString.charAt(i)=='1') ret.set(i); 193 return ret; 194 } 195 196 public void load(Solution currentSolution) throws Exception { 197 sLogger.debug("Reading XML data from "+iInputFile); 198 iProgress.setPhase("Reading "+iInputFile.getName()+" ..."); 199 200 Document document = (new SAXReader()).read(iInputFile); 201 Element root = document.getRootElement(); 202 sLogger.debug("Root element: "+root.getName()); 203 if (!"llrt".equals(root.getName()) && !"timetable".equals(root.getName())) { 204 sLogger.error("Given XML file is not large lecture room timetabling problem."); 205 return; 206 } 207 208 iProgress.load(root, true); 209 iProgress.message(Progress.MSGLEVEL_STAGE, "Restoring from backup ..."); 210 211 if (root.element("input")!=null) root = root.element("input"); 212 213 if (root.attributeValue("term")!=null) 214 getModel().getProperties().setProperty("Data.Term", root.attributeValue("term")); 215 if (root.attributeValue("year")!=null) 216 getModel().setYear(Integer.parseInt(root.attributeValue("year"))); 217 else if (root.attributeValue("term")!=null) 218 getModel().setYear(Integer.parseInt(root.attributeValue("term").substring(0,4))); 219 if (root.attributeValue("initiative")!=null) 220 getModel().getProperties().setProperty("Data.Initiative", root.attributeValue("initiative")); 221 if (root.attributeValue("semester")!=null && root.attributeValue("year")!=null) 222 getModel().getProperties().setProperty("Data.Term", root.attributeValue("semester")+root.attributeValue("year")); 223 if (root.attributeValue("session")!=null) 224 getModel().getProperties().setProperty("General.SessionId", root.attributeValue("session")); 225 if (root.attributeValue("solverGroup")!=null) 226 getModel().getProperties().setProperty("General.SolverGroupId", root.attributeValue("solverGroup")); 227 String version = root.attributeValue("version"); 228 //boolean timePatternTransform = "1.0".equals(version) || "2.0".equals(version); 229 230 Hashtable perts = new Hashtable(); 231 if (getModel().getProperties().getPropertyInt("MPP.TimePert", 0)>0) { 232 int nrChanges = getModel().getProperties().getPropertyInt("MPP.TimePert", 0); 233 int idx = 0; 234 for (Iterator i=root.element("perturbations").elementIterator("class");i.hasNext() && idx<nrChanges;idx++) { 235 Element pertEl = (Element)i.next(); 236 Long classId = Long.valueOf(pertEl.attributeValue("id")); 237 TimeLocation tl = new TimeLocation( 238 Integer.parseInt(pertEl.attributeValue("days"),2), 239 Integer.parseInt(pertEl.attributeValue("start")), 240 Integer.parseInt(pertEl.attributeValue("length")), 241 0, 242 0.0, 243 null, null, null, 0); 244 perts.put(classId, tl); 245 } 246 } 247 248 iProgress.setPhase("Creating rooms ...",root.element("rooms").elements("room").size()); 249 Hashtable roomElements = new Hashtable(); 250 Hashtable roomConstraints = new Hashtable(); 251 Hashtable sameLectures = new Hashtable(); 252 for (Iterator i=root.element("rooms").elementIterator("room");i.hasNext();) { 253 Element roomEl = (Element)i.next(); 254 iProgress.incProgress(); 255 roomElements.put(roomEl.attributeValue("id"), roomEl); 256 if ("false".equals(roomEl.attributeValue("constraint"))) continue; 257 RoomSharingModel sharingModel = null; 258 Element sharingEl = roomEl.element("sharing"); 259 if (sharingEl!=null) { 260 String pattern = sharingEl.element("pattern").getText(); 261 List depts = sharingEl.elements("department"); 262 Long departmentIds[] = new Long[depts.size()]; 263 for (int j=0;j<departmentIds.length;j++) 264 departmentIds[j] = Long.valueOf(((Element)depts.get(j)).attributeValue("id")); 265 sharingModel = new RoomSharingModel(departmentIds, pattern); 266 } 267 boolean ignoreTooFar = false; 268 if ("true".equals(roomEl.attributeValue("ignoreTooFar"))) 269 ignoreTooFar = true; 270 boolean fake=false; 271 if ("true".equals(roomEl.attributeValue("fake"))) 272 fake = true; 273 int posX = -1, posY = -1; 274 if (roomEl.attributeValue("location")!=null) { 275 String loc = roomEl.attributeValue("location"); 276 posX = Integer.parseInt(loc.substring(0,loc.indexOf(','))); 277 posY = Integer.parseInt(loc.substring(loc.indexOf(',')+1)); 278 } 279 boolean discouraged = "true".equals(roomEl.attributeValue("discouraged")); 280 RoomConstraint constraint = (discouraged ? 281 new DiscouragedRoomConstraint(getModel().getProperties(), 282 Long.valueOf(roomEl.attributeValue("id")), 283 (roomEl.attributeValue("name")!=null?roomEl.attributeValue("name"):"r"+roomEl.attributeValue("id")), 284 (roomEl.attributeValue("building")==null?null:Long.valueOf(roomEl.attributeValue("building"))), 285 Integer.parseInt(roomEl.attributeValue("capacity")), sharingModel, posX, posY, ignoreTooFar, !fake) 286 : 287 new RoomConstraint( 288 Long.valueOf(roomEl.attributeValue("id")), 289 (roomEl.attributeValue("name")!=null?roomEl.attributeValue("name"):"r"+roomEl.attributeValue("id")), 290 (roomEl.attributeValue("building")==null?null:Long.valueOf(roomEl.attributeValue("building"))), 291 Integer.parseInt(roomEl.attributeValue("capacity")), sharingModel, posX, posY, ignoreTooFar, !fake) 292 ); 293 if (roomEl.attributeValue("type")!=null) 294 constraint.setType(Long.valueOf(roomEl.attributeValue("type"))); 295 getModel().addConstraint(constraint); 296 roomConstraints.put(roomEl.attributeValue("id"), constraint); 297 } 298 299 Hashtable instructorConstraints = new Hashtable(); 300 if (root.element("instructors")!=null) { 301 for (Iterator i=root.element("instructors").elementIterator("instructor");i.hasNext();) { 302 Element instructorEl = (Element)i.next(); 303 InstructorConstraint instructorConstraint = new InstructorConstraint(Long.valueOf(instructorEl.attributeValue("id")), instructorEl.attributeValue("puid"), (instructorEl.attributeValue("name")!=null?instructorEl.attributeValue("name"):"i"+instructorEl.attributeValue("id")), "true".equals(instructorEl.attributeValue("ignDist"))); 304 if (instructorEl.attributeValue("type")!=null) 305 instructorConstraint.setType(Long.valueOf(instructorEl.attributeValue("type"))); 306 instructorConstraints.put(instructorEl.attributeValue("id"), instructorConstraint); 307 308 getModel().addConstraint(instructorConstraint); 309 } 310 } 311 Hashtable depts = new Hashtable(); 312 if (root.element("departments")!=null) { 313 for (Iterator i=root.element("departments").elementIterator("department");i.hasNext();) { 314 Element deptEl = (Element)i.next(); 315 depts.put(Long.valueOf(deptEl.attributeValue("id")),(deptEl.attributeValue("name")!=null?deptEl.attributeValue("name"):"d"+deptEl.attributeValue("id"))); 316 } 317 } 318 319 Hashtable configs = new Hashtable(); 320 Hashtable alternativeConfigurations = new Hashtable(); 321 if (root.element("configurations")!=null) { 322 for (Iterator i=root.element("configurations").elementIterator("config");i.hasNext();) { 323 Element configEl = (Element)i.next(); 324 Long configId = Long.valueOf(configEl.attributeValue("id")); 325 int limit = Integer.parseInt(configEl.attributeValue("limit")); 326 Long offeringId = Long.valueOf(configEl.attributeValue("offering")); 327 Configuration config = new Configuration(offeringId, configId, limit); 328 configs.put(configId, config); 329 Vector altConfigs = (Vector)alternativeConfigurations.get(offeringId); 330 if (altConfigs==null) { 331 altConfigs = new FastVector(); 332 alternativeConfigurations.put(offeringId, altConfigs); 333 } 334 altConfigs.add(config); 335 config.setAltConfigurations(altConfigs); 336 } 337 } 338 339 iProgress.setPhase("Creating variables ...",root.element("classes").elements("class").size()); 340 341 int nrClasses = root.element("classes").elements("class").size(); 342 343 Hashtable classElements = new Hashtable(); 344 Hashtable lectures = new Hashtable(); 345 Hashtable assignedPlacements = new Hashtable(); 346 Hashtable parents = new Hashtable(); 347 int ord = 0; 348 for (Iterator i1=root.element("classes").elementIterator("class");i1.hasNext();) { 349 Element classEl = (Element)i1.next(); 350 351 Configuration config = null; 352 if (classEl.attributeValue("config")!=null) { 353 config = (Configuration)configs.get(Long.valueOf(classEl.attributeValue("config"))); 354 } 355 if (config==null && classEl.attributeValue("offering")!=null) { 356 Long offeringId = Long.valueOf(classEl.attributeValue("offering")); 357 Long configId = Long.valueOf(classEl.attributeValue("config")); 358 Vector altConfigs = (Vector)alternativeConfigurations.get(offeringId); 359 if (altConfigs==null) { 360 altConfigs = new FastVector(); 361 alternativeConfigurations.put(offeringId, altConfigs); 362 } 363 for (Enumeration e=altConfigs.elements();e.hasMoreElements();) { 364 Configuration c = (Configuration)e.nextElement(); 365 if (c.getConfigId().equals(configId)) { config = c; break; } 366 } 367 if (config==null) { 368 config = new Configuration(offeringId,configId,-1); 369 altConfigs.add(config); 370 config.setAltConfigurations(altConfigs); 371 } 372 } 373 374 Long datePatternId = null; 375 String datePatternName = null; 376 BitSet weekCode = null; 377 if (classEl.attributeValue("dates")==null) { 378 int startDay = Integer.parseInt(classEl.attributeValue("startDay","0")); 379 int endDay = Integer.parseInt(classEl.attributeValue("endDay","1")); 380 weekCode = new BitSet(366); 381 for (int d=startDay;d<=endDay;d++) 382 weekCode.set(d); 383 datePatternName = sDF.format(getDate(getModel().getYear(),startDay))+"-"+sDF.format(getDate(getModel().getYear(),endDay)); 384 } else { 385 datePatternId = (classEl.attributeValue("datePattern")==null?null:Long.valueOf(classEl.attributeValue("datePattern"))); 386 datePatternName = classEl.attributeValue("datePatternName"); 387 weekCode = createBitSet(classEl.attributeValue("dates")); 388 } 389 classElements.put(classEl.attributeValue("id"),classEl); 390 Vector ics = new Vector(); 391 for (Iterator i2=classEl.elementIterator("instructor");i2.hasNext();) { 392 Element instructorEl = (Element)i2.next(); 393 InstructorConstraint instructorConstraint = (InstructorConstraint)instructorConstraints.get(instructorEl.attributeValue("id")); 394 if (instructorConstraint==null) { 395 instructorConstraint = new InstructorConstraint(Long.valueOf(instructorEl.attributeValue("id")), instructorEl.attributeValue("puid"), (instructorEl.attributeValue("name")!=null?instructorEl.attributeValue("name"):"i"+instructorEl.attributeValue("id")), "true".equals(instructorEl.attributeValue("ignDist"))); 396 instructorConstraints.put(instructorEl.attributeValue("id"), instructorConstraint); 397 getModel().addConstraint(instructorConstraint); 398 } 399 ics.add(instructorConstraint); 400 } 401 Vector roomLocations = new FastVector(); 402 Vector roomConstraintsThisClass = new FastVector(); 403 Vector initialRoomLocations = new Vector(); 404 Vector assignedRoomLocations = new Vector(); 405 Vector bestRoomLocations = new Vector(); 406 for (Iterator i2=classEl.elementIterator("room");i2.hasNext();) { 407 Element roomLocationEl = (Element)i2.next(); 408 Element roomEl = (Element)roomElements.get(roomLocationEl.attributeValue("id")); 409 RoomConstraint roomConstraint = (RoomConstraint)roomConstraints.get(roomLocationEl.attributeValue("id")); 410 411 Long roomId = null; 412 String roomName = null; 413 Long bldgId = null; 414 415 if (roomConstraint!=null) { 416 roomConstraintsThisClass.add(roomConstraint); 417 roomId = roomConstraint.getResourceId(); 418 roomName = roomConstraint.getRoomName(); 419 bldgId = roomConstraint.getBuildingId(); 420 } else { 421 roomId = Long.valueOf(roomEl.attributeValue("id")); 422 roomName = (roomEl.attributeValue("name")!=null?roomEl.attributeValue("name"):"r"+roomEl.attributeValue("id")); 423 bldgId = (roomEl.attributeValue("building")==null?null:Long.valueOf(roomEl.attributeValue("building"))); 424 } 425 426 boolean ignoreTooFar = false; 427 if ("true".equals(roomEl.attributeValue("ignoreTooFar"))) 428 ignoreTooFar = true; 429 int posX = -1, posY = -1; 430 if (roomEl.attributeValue("location")!=null) { 431 String loc = roomEl.attributeValue("location"); 432 posX = Integer.parseInt(loc.substring(0,loc.indexOf(','))); 433 posY = Integer.parseInt(loc.substring(loc.indexOf(',')+1)); 434 } 435 RoomLocation rl = new RoomLocation(roomId,roomName,bldgId,Integer.parseInt(roomLocationEl.attributeValue("pref")),Integer.parseInt(roomEl.attributeValue("capacity")),posX,posY,ignoreTooFar, roomConstraint); 436 if ("true".equals(roomLocationEl.attributeValue("initial"))) 437 initialRoomLocations.addElement(rl); 438 if ("true".equals(roomLocationEl.attributeValue("solution"))) 439 assignedRoomLocations.addElement(rl); 440 if ("true".equals(roomLocationEl.attributeValue("best"))) 441 bestRoomLocations.addElement(rl); 442 roomLocations.add(rl); 443 } 444 Vector timeLocations = new FastVector(); 445 TimeLocation initialTimeLocation = null; 446 TimeLocation assignedTimeLocation = null; 447 TimeLocation bestTimeLocation = null; 448 TimeLocation prohibitedTime = (TimeLocation)perts.get(Long.valueOf(classEl.attributeValue("id"))); 449 for (Iterator i2=classEl.elementIterator("time");i2.hasNext();) { 450 Element timeLocationEl = (Element)i2.next(); 451 TimeLocation tl = new TimeLocation( 452 Integer.parseInt(timeLocationEl.attributeValue("days"),2), 453 Integer.parseInt(timeLocationEl.attributeValue("start")), 454 Integer.parseInt(timeLocationEl.attributeValue("length")), 455 (int)Double.parseDouble(timeLocationEl.attributeValue("pref")), 456 Double.parseDouble(timeLocationEl.attributeValue("npref",timeLocationEl.attributeValue("pref"))), 457 datePatternId, datePatternName, weekCode, 458 Integer.parseInt(timeLocationEl.attributeValue("breakTime")==null?"0":timeLocationEl.attributeValue("breakTime")) 459 ); 460 if (timeLocationEl.attributeValue("pattern")!=null) 461 tl.setTimePatternId(Long.valueOf(timeLocationEl.attributeValue("pattern"))); 462 /* 463 if (timePatternTransform) 464 tl = transformTimePattern(Long.valueOf(classEl.attributeValue("id")),tl); 465 */ 466 if (prohibitedTime!=null && 467 prohibitedTime.getDayCode()==tl.getDayCode() && 468 prohibitedTime.getStartSlot()==tl.getStartSlot() && 469 prohibitedTime.getLength()==tl.getLength()) { 470 sLogger.info("Time "+tl.getLongName()+" is prohibited for class "+classEl.attributeValue("id")); 471 continue; 472 } 473 if ("true".equals(timeLocationEl.attributeValue("solution"))) 474 assignedTimeLocation = tl; 475 if ("true".equals(timeLocationEl.attributeValue("initial"))) 476 initialTimeLocation = tl; 477 if ("true".equals(timeLocationEl.attributeValue("best"))) 478 bestTimeLocation = tl; 479 timeLocations.add(tl); 480 } 481 if (timeLocations.isEmpty()) { 482 sLogger.error(" ERROR: No time."); 483 continue; 484 } 485 486 int minClassLimit = 0; 487 int maxClassLimit = 0; 488 double room2limitRatio = 1.0; 489 if (!"true".equals(classEl.attributeValue("committed"))) { 490 if (classEl.attributeValue("expectedCapacity")!=null) { 491 minClassLimit = maxClassLimit = Integer.parseInt(classEl.attributeValue("expectedCapacity")); 492 int roomCapacity = Integer.parseInt(classEl.attributeValue("roomCapacity",classEl.attributeValue("expectedCapacity"))); 493 if (minClassLimit==0) minClassLimit = maxClassLimit = roomCapacity; 494 room2limitRatio = (minClassLimit==0?1.0:((double)roomCapacity)/minClassLimit); 495 } else { 496 if (classEl.attribute("classLimit")!=null) { 497 minClassLimit = maxClassLimit = Integer.parseInt(classEl.attributeValue("classLimit")); 498 } else { 499 minClassLimit = Integer.parseInt(classEl.attributeValue("minClassLimit")); 500 maxClassLimit = Integer.parseInt(classEl.attributeValue("maxClassLimit")); 501 } 502 room2limitRatio = Double.parseDouble(classEl.attributeValue("roomToLimitRatio","1.0")); 503 } 504 } 505 506 Lecture lecture = new Lecture( 507 Long.valueOf(classEl.attributeValue("id")), 508 (classEl.attributeValue("solverGroup")!=null?Long.valueOf(classEl.attributeValue("solverGroup")):null), 509 Long.valueOf(classEl.attributeValue("subpart", classEl.attributeValue("course","-1"))), 510 (classEl.attributeValue("name")!=null?classEl.attributeValue("name"):"c"+classEl.attributeValue("id")), 511 timeLocations, 512 roomLocations, 513 Integer.parseInt(classEl.attributeValue("nrRooms","1")), 514 null, 515 minClassLimit,maxClassLimit,room2limitRatio); 516 lecture.setNote(classEl.attributeValue("note")); 517 518 if ("true".equals(classEl.attributeValue("committed"))) 519 lecture.setCommitted(true); 520 521 if (!lecture.isCommitted() && classEl.attributeValue("ord")!=null) 522 lecture.setOrd(Integer.parseInt(classEl.attributeValue("ord"))); 523 else 524 lecture.setOrd(ord++); 525 526 if (config!=null) 527 lecture.setConfiguration(config); 528 529 if (initialTimeLocation!=null && initialRoomLocations!=null && initialRoomLocations.size()==lecture.getNrRooms()) { 530 lecture.setInitialAssignment(new Placement(lecture,initialTimeLocation, initialRoomLocations)); 531 } 532 if (assignedTimeLocation!=null && assignedRoomLocations!=null && assignedRoomLocations.size()==lecture.getNrRooms()) { 533 assignedPlacements.put(lecture, new Placement(lecture,assignedTimeLocation, assignedRoomLocations)); 534 } else if (lecture.getInitialAssignment()!=null) { 535 assignedPlacements.put(lecture, lecture.getInitialAssignment()); 536 } 537 if (bestTimeLocation!=null && bestRoomLocations!=null && bestRoomLocations.size()==lecture.getNrRooms()) { 538 lecture.setBestAssignment(new Placement(lecture,bestTimeLocation, bestRoomLocations)); 539 } else if (assignedTimeLocation!=null && assignedRoomLocations!=null && assignedRoomLocations.size()==lecture.getNrRooms()) { 540 lecture.setBestAssignment((Placement)assignedPlacements.get(lecture)); 541 } 542 543 lectures.put(classEl.attributeValue("id"), lecture); 544 if (classEl.attributeValue("department")!=null) 545 lecture.setDepartment(Long.valueOf(classEl.attributeValue("department"))); 546 if (classEl.attribute("scheduler")!=null) 547 lecture.setScheduler(Long.valueOf(classEl.attributeValue("scheduler"))); 548 if (!lecture.isCommitted() && classEl.attributeValue("subpart",classEl.attributeValue("course"))!=null) { 549 Long subpartId = Long.valueOf(classEl.attributeValue("subpart",classEl.attributeValue("course"))); 550 Vector sames = (Vector)sameLectures.get(subpartId); 551 if (sames==null) { 552 sames = new FastVector(); 553 sameLectures.put(subpartId, sames); 554 } 555 sames.addElement(lecture); 556 } 557 String parent = classEl.attributeValue("parent"); 558 if (parent!=null) 559 parents.put(lecture, parent); 560 561 getModel().addVariable(lecture); 562 563 if (lecture.isCommitted()) { 564 Placement placement = (Placement)assignedPlacements.get(lecture); 565 if (classEl.attribute("assignment")!=null) 566 placement.setAssignmentId(Long.valueOf(classEl.attributeValue("assignment"))); 567 for (Enumeration e2=ics.elements();e2.hasMoreElements();) 568 ((InstructorConstraint)e2.nextElement()).setNotAvailable(placement); 569 for (Enumeration e2=roomConstraintsThisClass.elements(); e2.hasMoreElements();) 570 ((RoomConstraint)e2.nextElement()).setNotAvailable(placement); 571 } else { 572 for (Enumeration e2=ics.elements();e2.hasMoreElements();) 573 ((InstructorConstraint)e2.nextElement()).addVariable(lecture); 574 for (Enumeration e2=roomConstraintsThisClass.elements(); e2.hasMoreElements();) 575 ((Constraint)e2.nextElement()).addVariable(lecture); 576 } 577 578 iProgress.incProgress(); 579 } 580 581 for (Iterator i=parents.entrySet().iterator();i.hasNext();) { 582 Map.Entry entry = (Map.Entry)i.next(); 583 Lecture lecture = (Lecture)entry.getKey(); 584 Lecture parent = (Lecture)lectures.get(entry.getValue()); 585 lecture.setParent(parent); 586 } 587 588 iProgress.setPhase("Creating constraints ...",root.element("groupConstraints").elements("constraint").size()); 589 Hashtable grConstraintElements = new Hashtable(); 590 Hashtable groupConstraints = new Hashtable(); 591 for (Iterator i1=root.element("groupConstraints").elementIterator("constraint");i1.hasNext();) { 592 Element grConstraintEl = (Element)i1.next(); 593 Constraint c = null; 594 if ("SPREAD".equals(grConstraintEl.attributeValue("type"))) { 595 c = new SpreadConstraint(getModel().getProperties(),grConstraintEl.attributeValue("name","spread")); 596 } else if ("MIN_ROOM_USE".equals(grConstraintEl.attributeValue("type"))){ 597 c = new MinimizeNumberOfUsedRoomsConstraint(getModel().getProperties()); 598 } else if ("CLASS_LIMIT".equals(grConstraintEl.attributeValue("type"))){ 599 if (grConstraintEl.element("parentClass")==null) { 600 c = new ClassLimitConstraint(Integer.parseInt(grConstraintEl.attributeValue("courseLimit")),grConstraintEl.attributeValue("name","class-limit")); 601 } else { 602 String classId = grConstraintEl.element("parentClass").attributeValue("id"); 603 c = new ClassLimitConstraint((Lecture)lectures.get(classId),grConstraintEl.attributeValue("name","class-limit")); 604 } 605 if (grConstraintEl.attributeValue("delta")!=null) 606 ((ClassLimitConstraint)c).setClassLimitDelta(Integer.parseInt(grConstraintEl.attributeValue("delta"))); 607 } else if ("MIN_GRUSE(10x1h)".equals(grConstraintEl.attributeValue("type"))) { 608 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(),"10x1h",MinimizeNumberOfUsedGroupsOfTime.sGroups10of1h); 609 } else if ("MIN_GRUSE(5x2h)".equals(grConstraintEl.attributeValue("type"))) { 610 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(),"5x2h",MinimizeNumberOfUsedGroupsOfTime.sGroups5of2h); 611 } else if ("MIN_GRUSE(3x3h)".equals(grConstraintEl.attributeValue("type"))) { 612 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(),"3x3h",MinimizeNumberOfUsedGroupsOfTime.sGroups3of3h); 613 } else if ("MIN_GRUSE(2x5h)".equals(grConstraintEl.attributeValue("type"))) { 614 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(),"2x5h",MinimizeNumberOfUsedGroupsOfTime.sGroups2of5h); 615 } else { 616 c = new GroupConstraint(Long.valueOf(grConstraintEl.attributeValue("id")), grConstraintEl.attributeValue("type"), grConstraintEl.attributeValue("pref")); 617 } 618 getModel().addConstraint(c); 619 for (Iterator i2=grConstraintEl.elementIterator("class");i2.hasNext();) { 620 String classId = ((Element)i2.next()).attributeValue("id"); 621 c.addVariable((Lecture)lectures.get(classId)); 622 } 623 grConstraintElements.put(grConstraintEl.attributeValue("id"),grConstraintEl); 624 groupConstraints.put(grConstraintEl.attributeValue("id"),c); 625 iProgress.incProgress(); 626 } 627 628 iProgress.setPhase("Loading students ...",root.element("students").elements("student").size()); 629 boolean initialSectioning = true; 630 Hashtable jenrlConstraints = new Hashtable(); 631 Hashtable students = new Hashtable(); 632 Hashtable offering2students = new Hashtable(); 633 for (Iterator i1=root.element("students").elementIterator("student");i1.hasNext();) { 634 Element studentEl = (Element)i1.next(); 635 Vector lecturesThisStudent = new Vector(); 636 Long studentId = Long.valueOf(studentEl.attributeValue("id")); 637 Student student = (Student)students.get(studentId); 638 if (student==null) { 639 student = new Student(studentId); 640 students.put(studentId, student); 641 } 642 for (Iterator i2=studentEl.elementIterator("offering");i2.hasNext();) { 643 Element ofEl = (Element)i2.next(); 644 Long offeringId = Long.valueOf(ofEl.attributeValue("id")); 645 student.addOffering(offeringId, Double.parseDouble(ofEl.attributeValue("weight", "1.0"))); 646 Set studentsThisOffering = (Set)offering2students.get(offeringId); 647 if (studentsThisOffering==null) { 648 studentsThisOffering = new HashSet(); 649 offering2students.put(offeringId, studentsThisOffering); 650 } 651 studentsThisOffering.add(student); 652 } 653 for (Iterator i2=studentEl.elementIterator("class");i2.hasNext();) { 654 String classId = ((Element)i2.next()).attributeValue("id"); 655 Lecture lecture = (Lecture)lectures.get(classId); 656 if (lecture.isCommitted()) { 657 Placement placement = (Placement)assignedPlacements.get(lecture); 658 student.addCommitedPlacement(placement); 659 } else { 660 student.addLecture(lecture); 661 lecture.addStudent(student); 662 lecturesThisStudent.add(lecture); 663 initialSectioning = false; 664 } 665 } 666 667 if (student!=null) { 668 for (Iterator i2=studentEl.elementIterator("prohibited-class");i2.hasNext();) { 669 String classId = ((Element)i2.next()).attributeValue("id"); 670 Lecture lecture = (Lecture)lectures.get(classId); 671 student.addCanNotEnroll(lecture); 672 } 673 } 674 675 iProgress.incProgress(); 676 } 677 678 for (Enumeration e1=sameLectures.elements();e1.hasMoreElements();) { 679 Vector sames = (Vector)e1.nextElement(); 680 for (Enumeration e2=sames.elements(); e2.hasMoreElements();) { 681 Lecture lect = (Lecture)e2.nextElement(); 682 lect.setSameSubpartLectures(sames); 683 } 684 } 685 686 if (initialSectioning) { 687 iProgress.setPhase("Initial sectioning ...", offering2students.size()); 688 for (Iterator i1=offering2students.entrySet().iterator();i1.hasNext();) { 689 Map.Entry entry = (Map.Entry)i1.next(); 690 Long offeringId = (Long)entry.getKey(); 691 Set studentsThisOffering = (Set)entry.getValue(); 692 Vector altConfigs = (Vector)alternativeConfigurations.get(offeringId); 693 InitialSectioning.initialSectioningCfg(iProgress, offeringId, String.valueOf(offeringId), studentsThisOffering, altConfigs); 694 iProgress.incProgress(); 695 } 696 for (Enumeration e=students.elements();e.hasMoreElements();) { 697 ((Student)e.nextElement()).clearDistanceCache(); 698 } 699 } 700 701 iProgress.setPhase("Computing jenrl ...",students.size()); 702 Hashtable jenrls = new Hashtable(); 703 for (Iterator i1=students.values().iterator();i1.hasNext();) { 704 Student st = (Student)i1.next(); 705 for (Iterator i2=st.getLectures().iterator();i2.hasNext();) { 706 Lecture l1 = (Lecture)i2.next(); 707 for (Iterator i3=st.getLectures().iterator();i3.hasNext();) { 708 Lecture l2 = (Lecture)i3.next(); 709 if (l1.getId()>=l2.getId()) continue; 710 Hashtable x = (Hashtable)jenrls.get(l1); 711 if (x==null) { x = new Hashtable(); jenrls.put(l1, x); } 712 JenrlConstraint jenrl = (JenrlConstraint)x.get(l2); 713 if (jenrl==null) { 714 jenrl = new JenrlConstraint(); 715 jenrl.addVariable(l1); 716 jenrl.addVariable(l2); 717 getModel().addConstraint(jenrl); 718 x.put(l2, jenrl); 719 } 720 jenrl.incJenrl(st); 721 } 722 } 723 iProgress.incProgress(); 724 } 725 726 if (iDeptBalancing) { 727 iProgress.setPhase("Creating dept. spread constraints ...",getModel().variables().size()); 728 Hashtable depSpreadConstraints = new Hashtable(); 729 for (Enumeration e=getModel().variables().elements();e.hasMoreElements();) { 730 Lecture lecture = (Lecture)e.nextElement(); 731 if (lecture.getDepartment()==null) continue; 732 DepartmentSpreadConstraint deptConstr = (DepartmentSpreadConstraint)depSpreadConstraints.get(lecture.getDepartment()); 733 if (deptConstr==null) { 734 String name = (String)depts.get(lecture.getDepartment()); 735 deptConstr = new DepartmentSpreadConstraint(getModel().getProperties(),lecture.getDepartment(),(name!=null?name:"d"+lecture.getDepartment())); 736 depSpreadConstraints.put(lecture.getDepartment(),deptConstr); 737 getModel().addConstraint(deptConstr); 738 } 739 deptConstr.addVariable(lecture); 740 iProgress.incProgress(); 741 } 742 } 743 744 iProgress.setPhase("Purging invalid placements ...", getModel().variables().size()); 745 for (Enumeration e=getModel().variables().elements();e.hasMoreElements();) { 746 Lecture lecture = (Lecture)e.nextElement(); 747 lecture.purgeInvalidValues(iInteractiveMode); 748 iProgress.incProgress(); 749 } 750 751 if (currentSolution!=null) { 752 iProgress.setPhase("Creating best assignment ...",2*getModel().variables().size()); 753 for (Enumeration e=getModel().variables().elements();e.hasMoreElements();) { 754 Lecture lecture = (Lecture)e.nextElement(); 755 iProgress.incProgress(); 756 Placement placement = (Placement)lecture.getBestAssignment(); 757 if (placement==null) continue; 758 lecture.assign(0,placement); 759 } 760 761 currentSolution.saveBest(); 762 for (Enumeration e=getModel().variables().elements();e.hasMoreElements();) { 763 Lecture lecture = (Lecture)e.nextElement(); 764 iProgress.incProgress(); 765 if (lecture.getAssignment()!=null) 766 lecture.unassign(0); 767 } 768 } 769 770 iProgress.setPhase("Creating initial assignment ...",assignedPlacements.size()); 771 for (Iterator ip=assignedPlacements.entrySet().iterator();ip.hasNext();) { 772 Map.Entry entry = (Map.Entry)ip.next(); 773 Lecture lecture = (Lecture)entry.getKey(); 774 Placement placement = (Placement)entry.getValue(); 775 Hashtable conflictConstraints = getModel().conflictConstraints(placement); 776 if (conflictConstraints.isEmpty()) { 777 if (!lecture.isCommitted() && !placement.isValid()) { 778 sLogger.warn("WARNING: Lecture "+lecture.getName()+" does not contain assignment "+placement.getLongName()+" in its domain ("+placement.getNotValidReason()+")."); 779 } else 780 lecture.assign(0,placement); 781 } else { 782 sLogger.warn("WARNING: Unable to assign "+lecture.getName()+" := "+placement.getName()); 783 sLogger.debug(" Reason:"); 784 for (Enumeration ex=conflictConstraints.keys();ex.hasMoreElements();) { 785 Constraint c = (Constraint)ex.nextElement(); 786 Collection vals = (Collection)conflictConstraints.get(c); 787 for (Iterator i=vals.iterator();i.hasNext();) { 788 Value v = (Value) i.next(); 789 sLogger.debug(" "+v.variable().getName()+" = "+v.getName()); 790 } 791 sLogger.debug(" in constraint "+c); 792 } 793 } 794 iProgress.incProgress(); 795 } 796 797 if (initialSectioning && !getModel().assignedVariables().isEmpty() && !getModel().getProperties().getPropertyBoolean("Global.LoadStudentEnrlsFromSolution", false)) 798 getModel().switchStudents(); 799 800 if (iForcedPerturbances>0) { 801 iProgress.setPhase("Forcing perturbances",iForcedPerturbances); 802 for (int i=0;i<iForcedPerturbances;i++) { 803 iProgress.setProgress(i); 804 Variable var = null; 805 do { 806 var = (Variable)ToolBox.random(getModel().variables()); 807 } while (var.getInitialAssignment()==null || var.values().size()<=1); 808 var.removeInitialValue(); 809 } 810 } 811 812 for (Enumeration e=getModel().constraints().elements();e.hasMoreElements();) { 813 Constraint c = (Constraint)e.nextElement(); 814 if (c instanceof SpreadConstraint) 815 ((SpreadConstraint)c).init(); 816 if (c instanceof DiscouragedRoomConstraint) 817 ((DiscouragedRoomConstraint)c).setEnabled(true); 818 if (c instanceof MinimizeNumberOfUsedRoomsConstraint) 819 ((MinimizeNumberOfUsedRoomsConstraint)c).setEnabled(true); 820 if (c instanceof MinimizeNumberOfUsedGroupsOfTime) 821 ((MinimizeNumberOfUsedGroupsOfTime)c).setEnabled(true); 822 } 823 824 try { 825 getSolver().getClass().getMethod("load", new Class[] {Element.class}).invoke(getSolver(), new Object[]{root}); 826 } catch (Exception e) {} 827 828 iProgress.setPhase("Done",1);iProgress.incProgress(); 829 830 sLogger.debug("Model successfully loaded."); 831 iProgress.info("Model successfully loaded."); 832 } 833 834 public static Date getDate(int year, int dayOfYear) { 835 Calendar c = Calendar.getInstance(Locale.US); 836 c.set(year,1,1,0,0,0); 837 c.set(Calendar.DAY_OF_YEAR,dayOfYear); 838 return c.getTime(); 839 } 840 }