001package org.cpsolver.coursett; 002 003import java.io.File; 004import java.text.SimpleDateFormat; 005import java.util.ArrayList; 006import java.util.BitSet; 007import java.util.Calendar; 008import java.util.Date; 009import java.util.HashSet; 010import java.util.HashMap; 011import java.util.Hashtable; 012import java.util.Iterator; 013import java.util.List; 014import java.util.Locale; 015import java.util.Map; 016import java.util.Set; 017 018 019import org.cpsolver.coursett.constraint.ClassLimitConstraint; 020import org.cpsolver.coursett.constraint.DepartmentSpreadConstraint; 021import org.cpsolver.coursett.constraint.DiscouragedRoomConstraint; 022import org.cpsolver.coursett.constraint.GroupConstraint; 023import org.cpsolver.coursett.constraint.IgnoreStudentConflictsConstraint; 024import org.cpsolver.coursett.constraint.InstructorConstraint; 025import org.cpsolver.coursett.constraint.JenrlConstraint; 026import org.cpsolver.coursett.constraint.MinimizeNumberOfUsedGroupsOfTime; 027import org.cpsolver.coursett.constraint.MinimizeNumberOfUsedRoomsConstraint; 028import org.cpsolver.coursett.constraint.RoomConstraint; 029import org.cpsolver.coursett.constraint.SoftInstructorConstraint; 030import org.cpsolver.coursett.constraint.SpreadConstraint; 031import org.cpsolver.coursett.constraint.FlexibleConstraint.FlexibleConstraintType; 032import org.cpsolver.coursett.model.Configuration; 033import org.cpsolver.coursett.model.Lecture; 034import org.cpsolver.coursett.model.Placement; 035import org.cpsolver.coursett.model.RoomLocation; 036import org.cpsolver.coursett.model.RoomSharingModel; 037import org.cpsolver.coursett.model.Student; 038import org.cpsolver.coursett.model.StudentGroup; 039import org.cpsolver.coursett.model.TimeLocation; 040import org.cpsolver.coursett.model.TimetableModel; 041import org.cpsolver.ifs.assignment.Assignment; 042import org.cpsolver.ifs.model.Constraint; 043import org.cpsolver.ifs.solution.Solution; 044import org.cpsolver.ifs.solver.Solver; 045import org.cpsolver.ifs.util.Progress; 046import org.cpsolver.ifs.util.ToolBox; 047import org.dom4j.Document; 048import org.dom4j.Element; 049import org.dom4j.io.SAXReader; 050 051/** 052 * This class loads the input model from XML file. <br> 053 * <br> 054 * Parameters: 055 * <table border='1' summary='Related Solver Parameters'> 056 * <tr> 057 * <th>Parameter</th> 058 * <th>Type</th> 059 * <th>Comment</th> 060 * </tr> 061 * <tr> 062 * <td>General.Input</td> 063 * <td>{@link String}</td> 064 * <td>Input XML file</td> 065 * </tr> 066 * <tr> 067 * <td>General.DeptBalancing</td> 068 * <td>{@link Boolean}</td> 069 * <td>Use {@link DepartmentSpreadConstraint}</td> 070 * </tr> 071 * <tr> 072 * <td>General.InteractiveMode</td> 073 * <td>{@link Boolean}</td> 074 * <td>Interactive mode (see {@link Lecture#purgeInvalidValues(boolean)})</td> 075 * </tr> 076 * <tr> 077 * <td>General.ForcedPerturbances</td> 078 * <td>{@link Integer}</td> 079 * <td>For testing of MPP: number of input perturbations, i.e., classes with 080 * prohibited intial assignment</td> 081 * </tr> 082 * <tr> 083 * <td>General.UseDistanceConstraints</td> 084 * <td>{@link Boolean}</td> 085 * <td>Consider distances between buildings</td> 086 * </tr> 087 * </table> 088 * 089 * @version CourseTT 1.3 (University Course Timetabling)<br> 090 * Copyright (C) 2006 - 2014 Tomáš Müller<br> 091 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 092 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 093 * <br> 094 * This library is free software; you can redistribute it and/or modify 095 * it under the terms of the GNU Lesser General Public License as 096 * published by the Free Software Foundation; either version 3 of the 097 * License, or (at your option) any later version. <br> 098 * <br> 099 * This library is distributed in the hope that it will be useful, but 100 * WITHOUT ANY WARRANTY; without even the implied warranty of 101 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 102 * Lesser General Public License for more details. <br> 103 * <br> 104 * You should have received a copy of the GNU Lesser General Public 105 * License along with this library; if not see 106 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 107 */ 108 109public class TimetableXMLLoader extends TimetableLoader { 110 private static org.apache.logging.log4j.Logger sLogger = org.apache.logging.log4j.LogManager.getLogger(TimetableXMLLoader.class); 111 private static SimpleDateFormat sDF = new SimpleDateFormat("MM/dd"); 112 113 private boolean iDeptBalancing = true; 114 private int iForcedPerturbances = 0; 115 116 private boolean iInteractiveMode = false; 117 private File iInputFile; 118 119 private Progress iProgress = null; 120 121 public TimetableXMLLoader(TimetableModel model, Assignment<Lecture, Placement> assignment) { 122 super(model, assignment); 123 iProgress = Progress.getInstance(getModel()); 124 iInputFile = new File(getModel().getProperties().getProperty("General.Input", 125 "." + File.separator + "solution.xml")); 126 iForcedPerturbances = getModel().getProperties().getPropertyInt("General.ForcedPerturbances", 0); 127 iDeptBalancing = getModel().getProperties().getPropertyBoolean("General.DeptBalancing", true); 128 iInteractiveMode = getModel().getProperties().getPropertyBoolean("General.InteractiveMode", iInteractiveMode); 129 } 130 131 private Solver<Lecture, Placement> iSolver = null; 132 133 public void setSolver(Solver<Lecture, Placement> solver) { 134 iSolver = solver; 135 } 136 137 public Solver<Lecture, Placement> getSolver() { 138 return iSolver; 139 } 140 141 public void setInputFile(File inputFile) { 142 iInputFile = inputFile; 143 } 144 145 @Override 146 public void load() throws Exception { 147 load(null); 148 } 149 150 public void load(Solution<Lecture, Placement> currentSolution) throws Exception { 151 sLogger.debug("Reading XML data from " + iInputFile); 152 iProgress.setPhase("Reading " + iInputFile.getName() + " ..."); 153 154 Document document = (new SAXReader()).read(iInputFile); 155 Element root = document.getRootElement(); 156 157 sLogger.debug("Root element: " + root.getName()); 158 if (!"llrt".equals(root.getName()) && !"timetable".equals(root.getName())) { 159 throw new IllegalArgumentException("Given XML file is not large lecture room timetabling problem."); 160 } 161 162 if (root.element("input") != null) 163 root = root.element("input"); 164 165 iProgress.load(root, true); 166 iProgress.message(Progress.MSGLEVEL_STAGE, "Restoring from backup ..."); 167 168 doLoad(currentSolution, root); 169 170 try { 171 getSolver().getClass().getMethod("load", new Class[] { Element.class }).invoke(getSolver(), new Object[] { root }); 172 } catch (Exception e) { 173 } 174 175 iProgress.setPhase("Done", 1); 176 iProgress.incProgress(); 177 178 sLogger.debug("Model successfully loaded."); 179 iProgress.info("Model successfully loaded."); 180 } 181 182 public void load(Solution<Lecture, Placement> currentSolution, Document document) { 183 iProgress.setPhase("Reading solution file ..."); 184 185 Element root = document.getRootElement(); 186 187 sLogger.debug("Root element: " + root.getName()); 188 if (!"llrt".equals(root.getName()) && !"timetable".equals(root.getName())) { 189 throw new IllegalArgumentException("Given XML file is not large lecture room timetabling problem."); 190 } 191 192 if (root.element("input") != null) 193 root = root.element("input"); 194 195 iProgress.load(root, true); 196 iProgress.message(Progress.MSGLEVEL_STAGE, "Restoring from backup ..."); 197 198 doLoad(currentSolution, root); 199 200 iProgress.setPhase("Done", 1); 201 iProgress.incProgress(); 202 203 iProgress.info("Model successfully loaded."); 204 } 205 206 protected void doLoad(Solution<Lecture, Placement> currentSolution, Element root) { 207 if (root.attributeValue("term") != null) 208 getModel().getProperties().setProperty("Data.Term", root.attributeValue("term")); 209 if (root.attributeValue("year") != null) 210 getModel().setYear(Integer.parseInt(root.attributeValue("year"))); 211 else if (root.attributeValue("term") != null) 212 getModel().setYear(Integer.parseInt(root.attributeValue("term").substring(0, 4))); 213 if (root.attributeValue("initiative") != null) 214 getModel().getProperties().setProperty("Data.Initiative", root.attributeValue("initiative")); 215 if (root.attributeValue("semester") != null && root.attributeValue("year") != null) 216 getModel().getProperties().setProperty("Data.Term", 217 root.attributeValue("semester") + root.attributeValue("year")); 218 if (root.attributeValue("session") != null) 219 getModel().getProperties().setProperty("General.SessionId", root.attributeValue("session")); 220 if (root.attributeValue("solverGroup") != null) 221 getModel().getProperties().setProperty("General.SolverGroupId", root.attributeValue("solverGroup")); 222 String version = root.attributeValue("version"); 223 224 // Student sectioning considers the whole course (including committed classes), since 2.5 225 boolean sectionWholeCourse = true; 226 227 if (version != null && version.indexOf('.') >= 0) { 228 int majorVersion = Integer.parseInt(version.substring(0, version.indexOf('.'))); 229 int minorVersion = Integer.parseInt(version.substring(1 + version.indexOf('.'))); 230 231 sectionWholeCourse = (majorVersion == 2 && minorVersion >= 5) || majorVersion > 2; 232 } 233 234 HashMap<Long, TimeLocation> perts = new HashMap<Long, TimeLocation>(); 235 if (getModel().getProperties().getPropertyInt("MPP.TimePert", 0) > 0) { 236 int nrChanges = getModel().getProperties().getPropertyInt("MPP.TimePert", 0); 237 int idx = 0; 238 for (Iterator<?> i = root.element("perturbations").elementIterator("class"); i.hasNext() && idx < nrChanges; idx++) { 239 Element pertEl = (Element) i.next(); 240 Long classId = Long.valueOf(pertEl.attributeValue("id")); 241 TimeLocation tl = new TimeLocation(Integer.parseInt(pertEl.attributeValue("days"), 2), Integer 242 .parseInt(pertEl.attributeValue("start")), Integer.parseInt(pertEl.attributeValue("length")), 243 0, 0.0, 0, null, null, null, 0); 244 perts.put(classId, tl); 245 } 246 } 247 248 iProgress.setPhase("Creating rooms ...", root.element("rooms").elements("room").size()); 249 HashMap<String, Element> roomElements = new HashMap<String, Element>(); 250 HashMap<String, RoomConstraint> roomConstraints = new HashMap<String, RoomConstraint>(); 251 HashMap<Long, List<Lecture>> sameLectures = new HashMap<Long, List<Lecture>>(); 252 HashMap<RoomConstraint, String> roomPartitions = new HashMap<RoomConstraint, String>(); 253 for (Iterator<?> i = root.element("rooms").elementIterator("room"); i.hasNext();) { 254 Element roomEl = (Element) i.next(); 255 iProgress.incProgress(); 256 roomElements.put(roomEl.attributeValue("id"), roomEl); 257 if ("false".equals(roomEl.attributeValue("constraint"))) 258 continue; 259 RoomSharingModel sharingModel = null; 260 Element sharingEl = roomEl.element("sharing"); 261 if (sharingEl != null) { 262 Character freeForAllPrefChar = null; 263 Element freeForAllEl = sharingEl.element("freeForAll"); 264 if (freeForAllEl != null) 265 freeForAllPrefChar = freeForAllEl.attributeValue("value", "F").charAt(0); 266 Character notAvailablePrefChar = null; 267 Element notAvailableEl = sharingEl.element("notAvailable"); 268 if (notAvailableEl != null) 269 notAvailablePrefChar = notAvailableEl.attributeValue("value", "X").charAt(0); 270 String pattern = sharingEl.element("pattern").getText(); 271 int unit = Integer.parseInt(sharingEl.element("pattern").attributeValue("unit", "1")); 272 Map<Character, Long> departments = new HashMap<Character, Long>(); 273 for (Iterator<?> j = sharingEl.elementIterator("department"); j.hasNext(); ) { 274 Element deptEl = (Element)j.next(); 275 char value = deptEl.attributeValue("value", String.valueOf((char)('0' + departments.size()))).charAt(0); 276 Long id = Long.valueOf(deptEl.attributeValue("id")); 277 departments.put(value, id); 278 } 279 sharingModel = new RoomSharingModel(unit, departments, pattern, freeForAllPrefChar, notAvailablePrefChar); 280 } 281 boolean ignoreTooFar = false; 282 if ("true".equals(roomEl.attributeValue("ignoreTooFar"))) 283 ignoreTooFar = true; 284 boolean fake = false; 285 if ("true".equals(roomEl.attributeValue("fake"))) 286 fake = true; 287 Double posX = null, posY = null; 288 if (roomEl.attributeValue("location") != null) { 289 String loc = roomEl.attributeValue("location"); 290 posX = Double.valueOf(loc.substring(0, loc.indexOf(','))); 291 posY = Double.valueOf(loc.substring(loc.indexOf(',') + 1)); 292 } 293 boolean discouraged = "true".equals(roomEl.attributeValue("discouraged")); 294 RoomConstraint constraint = (discouraged ? new DiscouragedRoomConstraint( 295 getModel().getProperties(), 296 Long.valueOf(roomEl.attributeValue("id")), 297 (roomEl.attributeValue("name") != null ? roomEl.attributeValue("name") : "r" 298 + roomEl.attributeValue("id")), 299 (roomEl.attributeValue("building") == null ? null : Long.valueOf(roomEl.attributeValue("building"))), 300 Integer.parseInt(roomEl.attributeValue("capacity")), sharingModel, posX, posY, ignoreTooFar, !fake) 301 : new RoomConstraint(Long.valueOf(roomEl.attributeValue("id")), 302 (roomEl.attributeValue("name") != null ? roomEl.attributeValue("name") : "r" 303 + roomEl.attributeValue("id")), (roomEl.attributeValue("building") == null ? null 304 : Long.valueOf(roomEl.attributeValue("building"))), Integer.parseInt(roomEl 305 .attributeValue("capacity")), sharingModel, posX, posY, ignoreTooFar, !fake)); 306 if (roomEl.attributeValue("type") != null) 307 constraint.setType(Long.valueOf(roomEl.attributeValue("type"))); 308 getModel().addConstraint(constraint); 309 roomConstraints.put(roomEl.attributeValue("id"), constraint); 310 if (roomEl.attributeValue("parentId") != null) 311 roomPartitions.put(constraint, roomEl.attributeValue("parentId")); 312 313 for (Iterator<?> j = roomEl.elementIterator("travel-time"); j.hasNext();) { 314 Element travelTimeEl = (Element)j.next(); 315 getModel().getDistanceMetric().addTravelTime(constraint.getResourceId(), 316 Long.valueOf(travelTimeEl.attributeValue("id")), 317 Integer.valueOf(travelTimeEl.attributeValue("minutes"))); 318 } 319 } 320 for (Map.Entry<RoomConstraint, String> partition: roomPartitions.entrySet()) { 321 RoomConstraint parent = roomConstraints.get(partition.getValue()); 322 if (parent != null) 323 parent.addPartition(partition.getKey()); 324 } 325 326 HashMap<String, InstructorConstraint> instructorConstraints = new HashMap<String, InstructorConstraint>(); 327 if (root.element("instructors") != null) { 328 for (Iterator<?> i = root.element("instructors").elementIterator("instructor"); i.hasNext();) { 329 Element instructorEl = (Element) i.next(); 330 InstructorConstraint instructorConstraint = null; 331 if ("true".equalsIgnoreCase(instructorEl.attributeValue("soft", "false"))) { 332 instructorConstraint = new SoftInstructorConstraint(Long.valueOf(instructorEl 333 .attributeValue("id")), instructorEl.attributeValue("puid"), (instructorEl 334 .attributeValue("name") != null ? instructorEl.attributeValue("name") : "i" 335 + instructorEl.attributeValue("id")), "true".equals(instructorEl.attributeValue("ignDist"))); 336 } else { 337 instructorConstraint = new InstructorConstraint(Long.valueOf(instructorEl 338 .attributeValue("id")), instructorEl.attributeValue("puid"), (instructorEl 339 .attributeValue("name") != null ? instructorEl.attributeValue("name") : "i" 340 + instructorEl.attributeValue("id")), "true".equals(instructorEl.attributeValue("ignDist"))); 341 } 342 if (instructorEl.attributeValue("type") != null) 343 instructorConstraint.setType(Long.valueOf(instructorEl.attributeValue("type"))); 344 instructorConstraints.put(instructorEl.attributeValue("id"), instructorConstraint); 345 346 getModel().addConstraint(instructorConstraint); 347 } 348 } 349 HashMap<Long, String> depts = new HashMap<Long, String>(); 350 if (root.element("departments") != null) { 351 for (Iterator<?> i = root.element("departments").elementIterator("department"); i.hasNext();) { 352 Element deptEl = (Element) i.next(); 353 depts.put(Long.valueOf(deptEl.attributeValue("id")), (deptEl.attributeValue("name") != null ? deptEl 354 .attributeValue("name") : "d" + deptEl.attributeValue("id"))); 355 } 356 } 357 358 HashMap<Long, Configuration> configs = new HashMap<Long, Configuration>(); 359 HashMap<Long, List<Configuration>> alternativeConfigurations = new HashMap<Long, List<Configuration>>(); 360 if (root.element("configurations") != null) { 361 for (Iterator<?> i = root.element("configurations").elementIterator("config"); i.hasNext();) { 362 Element configEl = (Element) i.next(); 363 Long configId = Long.valueOf(configEl.attributeValue("id")); 364 int limit = Integer.parseInt(configEl.attributeValue("limit")); 365 Long offeringId = Long.valueOf(configEl.attributeValue("offering")); 366 Configuration config = new Configuration(offeringId, configId, limit); 367 configs.put(configId, config); 368 List<Configuration> altConfigs = alternativeConfigurations.get(offeringId); 369 if (altConfigs == null) { 370 altConfigs = new ArrayList<Configuration>(); 371 alternativeConfigurations.put(offeringId, altConfigs); 372 } 373 altConfigs.add(config); 374 config.setAltConfigurations(altConfigs); 375 } 376 } 377 378 iProgress.setPhase("Creating variables ...", root.element("classes").elements("class").size()); 379 380 HashMap<String, Element> classElements = new HashMap<String, Element>(); 381 HashMap<String, Lecture> lectures = new HashMap<String, Lecture>(); 382 HashMap<Lecture, Placement> assignedPlacements = new HashMap<Lecture, Placement>(); 383 HashMap<Lecture, String> parents = new HashMap<Lecture, String>(); 384 int ord = 0; 385 for (Iterator<?> i1 = root.element("classes").elementIterator("class"); i1.hasNext();) { 386 Element classEl = (Element) i1.next(); 387 388 Configuration config = null; 389 if (classEl.attributeValue("config") != null) { 390 config = configs.get(Long.valueOf(classEl.attributeValue("config"))); 391 } 392 if (config == null && classEl.attributeValue("offering") != null) { 393 Long offeringId = Long.valueOf(classEl.attributeValue("offering")); 394 Long configId = Long.valueOf(classEl.attributeValue("config")); 395 List<Configuration> altConfigs = alternativeConfigurations.get(offeringId); 396 if (altConfigs == null) { 397 altConfigs = new ArrayList<Configuration>(); 398 alternativeConfigurations.put(offeringId, altConfigs); 399 } 400 for (Configuration c : altConfigs) { 401 if (c.getConfigId().equals(configId)) { 402 config = c; 403 break; 404 } 405 } 406 if (config == null) { 407 config = new Configuration(offeringId, configId, -1); 408 altConfigs.add(config); 409 config.setAltConfigurations(altConfigs); 410 configs.put(config.getConfigId(), config); 411 } 412 } 413 414 DatePattern defaultDatePattern = new DatePattern(); 415 if (classEl.attributeValue("dates") == null) { 416 int startDay = Integer.parseInt(classEl.attributeValue("startDay", "0")); 417 int endDay = Integer.parseInt(classEl.attributeValue("endDay", "1")); 418 defaultDatePattern.setPattern(startDay, endDay); 419 defaultDatePattern.setName(sDF.format(getDate(getModel().getYear(), startDay)) + "-" + sDF.format(getDate(getModel().getYear(), endDay))); 420 } else { 421 defaultDatePattern.setId(classEl.attributeValue("datePattern") == null ? null : Long.valueOf(classEl.attributeValue("datePattern"))); 422 defaultDatePattern.setName(classEl.attributeValue("datePatternName")); 423 defaultDatePattern.setPattern(classEl.attributeValue("dates")); 424 } 425 Hashtable<Long, DatePattern> datePatterns = new Hashtable<Long, TimetableXMLLoader.DatePattern>(); 426 for (Iterator<?> i2 = classEl.elementIterator("date"); i2.hasNext();) { 427 Element dateEl = (Element) i2.next(); 428 Long id = Long.valueOf(dateEl.attributeValue("id")); 429 datePatterns.put(id, new DatePattern( 430 id, 431 dateEl.attributeValue("name"), 432 dateEl.attributeValue("pattern"))); 433 } 434 classElements.put(classEl.attributeValue("id"), classEl); 435 List<InstructorConstraint> ics = new ArrayList<InstructorConstraint>(); 436 for (Iterator<?> i2 = classEl.elementIterator("instructor"); i2.hasNext();) { 437 Element instructorEl = (Element) i2.next(); 438 InstructorConstraint instructorConstraint = instructorConstraints 439 .get(instructorEl.attributeValue("id")); 440 if (instructorConstraint == null) { 441 instructorConstraint = new InstructorConstraint(Long.valueOf(instructorEl.attributeValue("id")), 442 instructorEl.attributeValue("puid"), 443 (instructorEl.attributeValue("name") != null ? instructorEl.attributeValue("name") : "i" 444 + instructorEl.attributeValue("id")), "true".equals(instructorEl 445 .attributeValue("ignDist"))); 446 instructorConstraints.put(instructorEl.attributeValue("id"), instructorConstraint); 447 getModel().addConstraint(instructorConstraint); 448 } 449 ics.add(instructorConstraint); 450 } 451 List<RoomLocation> roomLocations = new ArrayList<RoomLocation>(); 452 List<RoomConstraint> roomConstraintsThisClass = new ArrayList<RoomConstraint>(); 453 List<RoomLocation> initialRoomLocations = new ArrayList<RoomLocation>(); 454 List<RoomLocation> assignedRoomLocations = new ArrayList<RoomLocation>(); 455 List<RoomLocation> bestRoomLocations = new ArrayList<RoomLocation>(); 456 for (Iterator<?> i2 = classEl.elementIterator("room"); i2.hasNext();) { 457 Element roomLocationEl = (Element) i2.next(); 458 Element roomEl = roomElements.get(roomLocationEl.attributeValue("id")); 459 RoomConstraint roomConstraint = roomConstraints.get(roomLocationEl.attributeValue("id")); 460 461 Long roomId = null; 462 String roomName = null; 463 Long bldgId = null; 464 465 if (roomConstraint != null) { 466 roomConstraintsThisClass.add(roomConstraint); 467 roomId = roomConstraint.getResourceId(); 468 roomName = roomConstraint.getRoomName(); 469 bldgId = roomConstraint.getBuildingId(); 470 } else { 471 roomId = Long.valueOf(roomEl.attributeValue("id")); 472 roomName = (roomEl.attributeValue("name") != null ? roomEl.attributeValue("name") : "r" 473 + roomEl.attributeValue("id")); 474 bldgId = (roomEl.attributeValue("building") == null ? null : Long.valueOf(roomEl 475 .attributeValue("building"))); 476 } 477 478 boolean ignoreTooFar = false; 479 if ("true".equals(roomEl.attributeValue("ignoreTooFar"))) 480 ignoreTooFar = true; 481 Double posX = null, posY = null; 482 if (roomEl.attributeValue("location") != null) { 483 String loc = roomEl.attributeValue("location"); 484 posX = Double.valueOf(loc.substring(0, loc.indexOf(','))); 485 posY = Double.valueOf(loc.substring(loc.indexOf(',') + 1)); 486 } 487 RoomLocation rl = new RoomLocation(roomId, roomName, bldgId, Integer.parseInt(roomLocationEl 488 .attributeValue("pref")), Integer.parseInt(roomEl.attributeValue("capacity")), posX, posY, 489 ignoreTooFar, roomConstraint); 490 if ("true".equals(roomLocationEl.attributeValue("initial"))) 491 initialRoomLocations.add(rl); 492 if ("true".equals(roomLocationEl.attributeValue("solution"))) 493 assignedRoomLocations.add(rl); 494 if ("true".equals(roomLocationEl.attributeValue("best"))) 495 bestRoomLocations.add(rl); 496 roomLocations.add(rl); 497 } 498 List<TimeLocation> timeLocations = new ArrayList<TimeLocation>(); 499 TimeLocation initialTimeLocation = null; 500 TimeLocation assignedTimeLocation = null; 501 TimeLocation bestTimeLocation = null; 502 TimeLocation prohibitedTime = perts.get(Long.valueOf(classEl.attributeValue("id"))); 503 504 for (Iterator<?> i2 = classEl.elementIterator("time"); i2.hasNext();) { 505 Element timeLocationEl = (Element) i2.next(); 506 DatePattern dp = defaultDatePattern; 507 if (timeLocationEl.attributeValue("date") != null) 508 dp = datePatterns.get(Long.valueOf(timeLocationEl.attributeValue("date"))); 509 TimeLocation tl = new TimeLocation( 510 Integer.parseInt(timeLocationEl.attributeValue("days"), 2), 511 Integer.parseInt(timeLocationEl.attributeValue("start")), 512 Integer.parseInt(timeLocationEl.attributeValue("length")), 513 (int) Double.parseDouble(timeLocationEl.attributeValue("pref")), 514 Double.parseDouble(timeLocationEl.attributeValue("npref", timeLocationEl.attributeValue("pref"))), 515 Integer.parseInt(timeLocationEl.attributeValue("datePref", "0")), 516 dp.getId(), dp.getName(), dp.getPattern(), 517 Integer.parseInt(timeLocationEl.attributeValue("breakTime") == null ? "-1" : timeLocationEl.attributeValue("breakTime"))); 518 if (tl.getBreakTime() < 0) tl.setBreakTime(tl.getLength() == 18 ? 15 : 10); 519 if (timeLocationEl.attributeValue("pattern") != null) 520 tl.setTimePatternId(Long.valueOf(timeLocationEl.attributeValue("pattern"))); 521 /* 522 * if (timePatternTransform) tl = 523 * transformTimePattern(Long.valueOf 524 * (classEl.attributeValue("id")),tl); 525 */ 526 if (prohibitedTime != null && prohibitedTime.getDayCode() == tl.getDayCode() 527 && prohibitedTime.getStartSlot() == tl.getStartSlot() 528 && prohibitedTime.getLength() == tl.getLength()) { 529 sLogger.info("Time " + tl.getLongName(true) + " is prohibited for class " + classEl.attributeValue("id")); 530 continue; 531 } 532 if ("true".equals(timeLocationEl.attributeValue("solution"))) 533 assignedTimeLocation = tl; 534 if ("true".equals(timeLocationEl.attributeValue("initial"))) 535 initialTimeLocation = tl; 536 if ("true".equals(timeLocationEl.attributeValue("best"))) 537 bestTimeLocation = tl; 538 timeLocations.add(tl); 539 } 540 if (timeLocations.isEmpty()) { 541 sLogger.error(" ERROR: No time."); 542 continue; 543 } 544 545 int minClassLimit = 0; 546 int maxClassLimit = 0; 547 float room2limitRatio = 1.0f; 548 if (!"true".equals(classEl.attributeValue("committed"))) { 549 if (classEl.attributeValue("expectedCapacity") != null) { 550 minClassLimit = maxClassLimit = Integer.parseInt(classEl.attributeValue("expectedCapacity")); 551 int roomCapacity = Integer.parseInt(classEl.attributeValue("roomCapacity", classEl 552 .attributeValue("expectedCapacity"))); 553 if (minClassLimit == 0) 554 minClassLimit = maxClassLimit = roomCapacity; 555 room2limitRatio = (minClassLimit == 0 ? 1.0f : ((float) roomCapacity) / minClassLimit); 556 } else { 557 if (classEl.attribute("classLimit") != null) { 558 minClassLimit = maxClassLimit = Integer.parseInt(classEl.attributeValue("classLimit")); 559 } else { 560 minClassLimit = Integer.parseInt(classEl.attributeValue("minClassLimit")); 561 maxClassLimit = Integer.parseInt(classEl.attributeValue("maxClassLimit")); 562 } 563 room2limitRatio = Float.parseFloat(classEl.attributeValue("roomToLimitRatio", "1.0")); 564 } 565 } 566 567 Lecture lecture = new Lecture(Long.valueOf(classEl.attributeValue("id")), 568 (classEl.attributeValue("solverGroup") != null ? Long 569 .valueOf(classEl.attributeValue("solverGroup")) : null), Long.valueOf(classEl 570 .attributeValue("subpart", classEl.attributeValue("course", "-1"))), (classEl 571 .attributeValue("name") != null ? classEl.attributeValue("name") : "c" 572 + classEl.attributeValue("id")), timeLocations, roomLocations, Integer.parseInt(classEl 573 .attributeValue("nrRooms", roomLocations.isEmpty() ? "0" : "1")), null, minClassLimit, maxClassLimit, room2limitRatio); 574 lecture.setNote(classEl.attributeValue("note")); 575 576 if ("true".equals(classEl.attributeValue("committed"))) 577 lecture.setCommitted(true); 578 579 if (!lecture.isCommitted() && classEl.attributeValue("ord") != null) 580 lecture.setOrd(Integer.parseInt(classEl.attributeValue("ord"))); 581 else 582 lecture.setOrd(ord++); 583 584 lecture.setWeight(Double.parseDouble(classEl.attributeValue("weight", "1.0"))); 585 586 if (lecture.getNrRooms() > 1) 587 lecture.setMaxRoomCombinations(Integer.parseInt(classEl.attributeValue("maxRoomCombinations", "-1"))); 588 589 if (config != null) 590 lecture.setConfiguration(config); 591 592 if (initialTimeLocation != null && initialRoomLocations.size() == lecture.getNrRooms()) { 593 lecture.setInitialAssignment(new Placement(lecture, initialTimeLocation, initialRoomLocations)); 594 } 595 if (assignedTimeLocation != null && assignedRoomLocations.size() == lecture.getNrRooms()) { 596 assignedPlacements.put(lecture, new Placement(lecture, assignedTimeLocation, assignedRoomLocations)); 597 } else if (lecture.getInitialAssignment() != null) { 598 // assignedPlacements.put(lecture, lecture.getInitialAssignment()); 599 } 600 if (bestTimeLocation != null && bestRoomLocations.size() == lecture.getNrRooms()) { 601 lecture.setBestAssignment(new Placement(lecture, bestTimeLocation, bestRoomLocations), 0); 602 } else if (assignedTimeLocation != null && assignedRoomLocations.size() == lecture.getNrRooms()) { 603 // lecture.setBestAssignment(assignedPlacements.get(lecture), 0); 604 } 605 606 lectures.put(classEl.attributeValue("id"), lecture); 607 if (classEl.attributeValue("department") != null) 608 lecture.setDepartment(Long.valueOf(classEl.attributeValue("department"))); 609 if (classEl.attribute("scheduler") != null) 610 lecture.setScheduler(Long.valueOf(classEl.attributeValue("scheduler"))); 611 if ((sectionWholeCourse || !lecture.isCommitted()) && classEl.attributeValue("subpart", classEl.attributeValue("course")) != null) { 612 Long subpartId = Long.valueOf(classEl.attributeValue("subpart", classEl.attributeValue("course"))); 613 List<Lecture> sames = sameLectures.get(subpartId); 614 if (sames == null) { 615 sames = new ArrayList<Lecture>(); 616 sameLectures.put(subpartId, sames); 617 } 618 sames.add(lecture); 619 } 620 String parent = classEl.attributeValue("parent"); 621 if (parent != null) 622 parents.put(lecture, parent); 623 624 getModel().addVariable(lecture); 625 626 if (lecture.isCommitted()) { 627 Placement placement = assignedPlacements.get(lecture); 628 if (classEl.attribute("assignment") != null) 629 placement.setAssignmentId(Long.valueOf(classEl.attributeValue("assignment"))); 630 for (InstructorConstraint ic : ics) 631 ic.setNotAvailable(placement); 632 for (RoomConstraint rc : roomConstraintsThisClass) 633 if (rc.getConstraint()) 634 rc.setNotAvailable(placement); 635 } else { 636 for (InstructorConstraint ic : ics) 637 ic.addVariable(lecture); 638 for (RoomConstraint rc : roomConstraintsThisClass) 639 rc.addVariable(lecture); 640 } 641 642 iProgress.incProgress(); 643 } 644 645 for (Map.Entry<Lecture, String> entry : parents.entrySet()) { 646 Lecture lecture = entry.getKey(); 647 Lecture parent = lectures.get(entry.getValue()); 648 if (parent == null) { 649 iProgress.warn("Parent class " + entry.getValue() + " does not exists."); 650 } else { 651 lecture.setParent(parent); 652 } 653 } 654 655 iProgress.setPhase("Creating constraints ...", root.element("groupConstraints").elements("constraint").size()); 656 HashMap<String, Element> grConstraintElements = new HashMap<String, Element>(); 657 HashMap<String, Constraint<Lecture, Placement>> groupConstraints = new HashMap<String, Constraint<Lecture, Placement>>(); 658 for (Iterator<?> i1 = root.element("groupConstraints").elementIterator("constraint"); i1.hasNext();) { 659 Element grConstraintEl = (Element) i1.next(); 660 Constraint<Lecture, Placement> c = null; 661 if ("SPREAD".equals(grConstraintEl.attributeValue("type"))) { 662 c = new SpreadConstraint(getModel().getProperties(), grConstraintEl.attributeValue("name", "spread")); 663 } else if ("MIN_ROOM_USE".equals(grConstraintEl.attributeValue("type"))) { 664 c = new MinimizeNumberOfUsedRoomsConstraint(getModel().getProperties()); 665 } else if ("CLASS_LIMIT".equals(grConstraintEl.attributeValue("type"))) { 666 if (grConstraintEl.element("parentClass") == null) { 667 c = new ClassLimitConstraint(Integer.parseInt(grConstraintEl.attributeValue("courseLimit")), 668 grConstraintEl.attributeValue("name", "class-limit")); 669 } else { 670 String classId = grConstraintEl.element("parentClass").attributeValue("id"); 671 c = new ClassLimitConstraint(lectures.get(classId), grConstraintEl.attributeValue("name", 672 "class-limit")); 673 } 674 if (grConstraintEl.attributeValue("delta") != null) 675 ((ClassLimitConstraint) c).setClassLimitDelta(Integer.parseInt(grConstraintEl 676 .attributeValue("delta"))); 677 } else if ("MIN_GRUSE(10x1h)".equals(grConstraintEl.attributeValue("type"))) { 678 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(), "10x1h", 679 MinimizeNumberOfUsedGroupsOfTime.sGroups10of1h); 680 } else if ("MIN_GRUSE(5x2h)".equals(grConstraintEl.attributeValue("type"))) { 681 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(), "5x2h", 682 MinimizeNumberOfUsedGroupsOfTime.sGroups5of2h); 683 } else if ("MIN_GRUSE(3x3h)".equals(grConstraintEl.attributeValue("type"))) { 684 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(), "3x3h", 685 MinimizeNumberOfUsedGroupsOfTime.sGroups3of3h); 686 } else if ("MIN_GRUSE(2x5h)".equals(grConstraintEl.attributeValue("type"))) { 687 c = new MinimizeNumberOfUsedGroupsOfTime(getModel().getProperties(), "2x5h", 688 MinimizeNumberOfUsedGroupsOfTime.sGroups2of5h); 689 } else if (IgnoreStudentConflictsConstraint.REFERENCE.equals(grConstraintEl.attributeValue("type"))) { 690 c = new IgnoreStudentConflictsConstraint(); 691 } else { 692 try { 693 FlexibleConstraintType f = FlexibleConstraintType.valueOf(grConstraintEl.attributeValue("type")); 694 try { 695 c = f.create( 696 Long.valueOf(grConstraintEl.attributeValue("id")), 697 grConstraintEl.attributeValue("owner"), 698 grConstraintEl.attributeValue("pref"), 699 grConstraintEl.attributeValue("reference")); 700 } catch (IllegalArgumentException e) { 701 iProgress.warn("Failed to create flexible constraint " + grConstraintEl.attributeValue("type") + ": " + e.getMessage(), e); 702 continue; 703 } 704 } catch (IllegalArgumentException e) { 705 // type did not match, continue with group constraint types 706 c = new GroupConstraint( 707 Long.valueOf(grConstraintEl.attributeValue("id")), 708 GroupConstraint.getConstraintType(grConstraintEl.attributeValue("type")), 709 grConstraintEl.attributeValue("pref")); 710 } 711 } 712 getModel().addConstraint(c); 713 for (Iterator<?> i2 = grConstraintEl.elementIterator("class"); i2.hasNext();) { 714 String classId = ((Element) i2.next()).attributeValue("id"); 715 Lecture other = lectures.get(classId); 716 if (other != null) 717 c.addVariable(other); 718 else 719 iProgress.warn("Class " + classId + " does not exists, but it is referred from group constraint " + c.getId() + " (" + c.getName() + ")"); 720 } 721 grConstraintElements.put(grConstraintEl.attributeValue("id"), grConstraintEl); 722 groupConstraints.put(grConstraintEl.attributeValue("id"), c); 723 iProgress.incProgress(); 724 } 725 726 iProgress.setPhase("Loading students ...", root.element("students").elements("student").size()); 727 boolean initialSectioning = true; 728 HashMap<Long, Student> students = new HashMap<Long, Student>(); 729 HashMap<Long, Set<Student>> offering2students = new HashMap<Long, Set<Student>>(); 730 for (Iterator<?> i1 = root.element("students").elementIterator("student"); i1.hasNext();) { 731 Element studentEl = (Element) i1.next(); 732 List<Lecture> lecturesThisStudent = new ArrayList<Lecture>(); 733 Long studentId = Long.valueOf(studentEl.attributeValue("id")); 734 Student student = students.get(studentId); 735 if (student == null) { 736 student = new Student(studentId); 737 students.put(studentId, student); 738 getModel().addStudent(student); 739 } 740 student.setAcademicArea(studentEl.attributeValue("area")); 741 student.setAcademicClassification(studentEl.attributeValue("classification")); 742 student.setMajor(studentEl.attributeValue("major")); 743 student.setCurriculum(studentEl.attributeValue("curriculum")); 744 for (Iterator<?> i2 = studentEl.elementIterator("offering"); i2.hasNext();) { 745 Element ofEl = (Element) i2.next(); 746 Long offeringId = Long.valueOf(ofEl.attributeValue("id")); 747 String priority = ofEl.attributeValue("priority"); 748 student.addOffering(offeringId, Double.parseDouble(ofEl.attributeValue("weight", "1.0")), priority == null ? null : Double.valueOf(priority)); 749 Set<Student> studentsThisOffering = offering2students.get(offeringId); 750 if (studentsThisOffering == null) { 751 studentsThisOffering = new HashSet<Student>(); 752 offering2students.put(offeringId, studentsThisOffering); 753 } 754 studentsThisOffering.add(student); 755 String altId = ofEl.attributeValue("alternative"); 756 if (altId != null) 757 student.addAlternatives(Long.valueOf(altId), offeringId); 758 } 759 for (Iterator<?> i2 = studentEl.elementIterator("class"); i2.hasNext();) { 760 String classId = ((Element) i2.next()).attributeValue("id"); 761 Lecture lecture = lectures.get(classId); 762 if (lecture == null) { 763 iProgress.warn("Class " + classId + " does not exists, but it is referred from student " + student.getId()); 764 continue; 765 } 766 if (lecture.isCommitted()) { 767 if (sectionWholeCourse && (lecture.getParent() != null || lecture.getConfiguration() != null)) { 768 // committed, but with course structure -- sectioning can be used 769 student.addLecture(lecture); 770 student.addConfiguration(lecture.getConfiguration()); 771 lecture.addStudent(getAssignment(), student); 772 lecturesThisStudent.add(lecture); 773 initialSectioning = false; 774 } else { 775 Placement placement = assignedPlacements.get(lecture); 776 student.addCommitedPlacement(placement); 777 } 778 } else { 779 student.addLecture(lecture); 780 student.addConfiguration(lecture.getConfiguration()); 781 lecture.addStudent(getAssignment(), student); 782 lecturesThisStudent.add(lecture); 783 initialSectioning = false; 784 } 785 } 786 787 for (Iterator<?> i2 = studentEl.elementIterator("prohibited-class"); i2.hasNext();) { 788 String classId = ((Element) i2.next()).attributeValue("id"); 789 Lecture lecture = lectures.get(classId); 790 if (lecture != null) 791 student.addCanNotEnroll(lecture); 792 else 793 iProgress.warn("Class " + classId + " does not exists, but it is referred from student " + student.getId()); 794 } 795 796 if (studentEl.attributeValue("instructor") != null) 797 student.setInstructor(instructorConstraints.get(studentEl.attributeValue("instructor"))); 798 799 iProgress.incProgress(); 800 } 801 802 if (root.element("groups") != null) { 803 iProgress.setPhase("Loading student groups ...", root.element("groups").elements("group").size()); 804 for (Iterator<?> i1 = root.element("groups").elementIterator("group"); i1.hasNext();) { 805 Element groupEl = (Element)i1.next(); 806 long groupId = Long.parseLong(groupEl.attributeValue("id")); 807 StudentGroup group = new StudentGroup(groupId, Double.parseDouble(groupEl.attributeValue("weight", "1.0")), groupEl.attributeValue("name", "Group-" + groupId)); 808 getModel().addStudentGroup(group); 809 for (Iterator<?> i2 = groupEl.elementIterator("student"); i2.hasNext();) { 810 Element studentEl = (Element)i2.next(); 811 Student student = students.get(Long.valueOf(studentEl.attributeValue("id"))); 812 if (student != null) { 813 group.addStudent(student); student.addGroup(group); 814 } 815 } 816 } 817 } 818 819 for (List<Lecture> sames: sameLectures.values()) { 820 for (Lecture lect : sames) { 821 lect.setSameSubpartLectures(sames); 822 } 823 } 824 825 if (initialSectioning) { 826 iProgress.setPhase("Initial sectioning ...", offering2students.size()); 827 for (Map.Entry<Long, Set<Student>> entry : offering2students.entrySet()) { 828 Long offeringId = entry.getKey(); 829 Set<Student> studentsThisOffering = entry.getValue(); 830 List<Configuration> altConfigs = alternativeConfigurations.get(offeringId); 831 getModel().getStudentSectioning().initialSectioning(getAssignment(), offeringId, String.valueOf(offeringId), studentsThisOffering, altConfigs); 832 iProgress.incProgress(); 833 } 834 for (Student student: students.values()) { 835 student.clearDistanceCache(); 836 if (student.getInstructor() != null) 837 for (Lecture lecture: student.getInstructor().variables()) { 838 student.addLecture(lecture); 839 student.addConfiguration(lecture.getConfiguration()); 840 lecture.addStudent(getAssignment(), student); 841 } 842 } 843 } 844 845 iProgress.setPhase("Computing jenrl ...", students.size()); 846 HashMap<Lecture, HashMap<Lecture, JenrlConstraint>> jenrls = new HashMap<Lecture, HashMap<Lecture, JenrlConstraint>>(); 847 for (Iterator<Student> i1 = students.values().iterator(); i1.hasNext();) { 848 Student st = i1.next(); 849 for (Iterator<Lecture> i2 = st.getLectures().iterator(); i2.hasNext();) { 850 Lecture l1 = i2.next(); 851 for (Iterator<Lecture> i3 = st.getLectures().iterator(); i3.hasNext();) { 852 Lecture l2 = i3.next(); 853 if (l1.getId() >= l2.getId()) 854 continue; 855 HashMap<Lecture, JenrlConstraint> x = jenrls.get(l1); 856 if (x == null) { 857 x = new HashMap<Lecture, JenrlConstraint>(); 858 jenrls.put(l1, x); 859 } 860 JenrlConstraint jenrl = x.get(l2); 861 if (jenrl == null) { 862 jenrl = new JenrlConstraint(); 863 jenrl.addVariable(l1); 864 jenrl.addVariable(l2); 865 getModel().addConstraint(jenrl); 866 x.put(l2, jenrl); 867 } 868 jenrl.incJenrl(getAssignment(), st); 869 } 870 } 871 iProgress.incProgress(); 872 } 873 874 if (iDeptBalancing) { 875 iProgress.setPhase("Creating dept. spread constraints ...", getModel().variables().size()); 876 HashMap<Long, DepartmentSpreadConstraint> depSpreadConstraints = new HashMap<Long, DepartmentSpreadConstraint>(); 877 for (Lecture lecture : getModel().variables()) { 878 if (lecture.getDepartment() == null) 879 continue; 880 DepartmentSpreadConstraint deptConstr = depSpreadConstraints.get(lecture.getDepartment()); 881 if (deptConstr == null) { 882 String name = depts.get(lecture.getDepartment()); 883 deptConstr = new DepartmentSpreadConstraint(getModel().getProperties(), lecture.getDepartment(), 884 (name != null ? name : "d" + lecture.getDepartment())); 885 depSpreadConstraints.put(lecture.getDepartment(), deptConstr); 886 getModel().addConstraint(deptConstr); 887 } 888 deptConstr.addVariable(lecture); 889 iProgress.incProgress(); 890 } 891 } 892 893 if (getModel().getProperties().getPropertyBoolean("General.PurgeInvalidPlacements", true)) { 894 iProgress.setPhase("Purging invalid placements ...", getModel().variables().size()); 895 for (Lecture lecture : getModel().variables()) { 896 lecture.purgeInvalidValues(iInteractiveMode); 897 iProgress.incProgress(); 898 } 899 } 900 901 if (getModel().hasConstantVariables() && getModel().constantVariables().size() > 0) { 902 iProgress.setPhase("Assigning committed classes ...", assignedPlacements.size()); 903 for (Map.Entry<Lecture, Placement> entry : assignedPlacements.entrySet()) { 904 Lecture lecture = entry.getKey(); 905 Placement placement = entry.getValue(); 906 if (!lecture.isCommitted()) { iProgress.incProgress(); continue; } 907 lecture.setConstantValue(placement); 908 getModel().weaken(getAssignment(), placement); 909 Map<Constraint<Lecture, Placement>, Set<Placement>> conflictConstraints = getModel().conflictConstraints(getAssignment(), placement); 910 if (conflictConstraints.isEmpty()) { 911 getAssignment().assign(0, placement); 912 } else { 913 iProgress.warn("WARNING: Unable to assign " + lecture.getName() + " := " + placement.getName()); 914 iProgress.debug(" Reason:"); 915 for (Constraint<Lecture, Placement> c : conflictConstraints.keySet()) { 916 Set<Placement> vals = conflictConstraints.get(c); 917 for (Placement v : vals) { 918 iProgress.debug(" " + v.variable().getName() + " = " + v.getName()); 919 } 920 iProgress.debug(" in constraint " + c); 921 } 922 } 923 iProgress.incProgress(); 924 } 925 } 926 927 if (currentSolution != null) { 928 iProgress.setPhase("Creating best assignment ...", 2 * getModel().variables().size()); 929 for (Lecture lecture : getModel().variables()) { 930 iProgress.incProgress(); 931 Placement placement = lecture.getBestAssignment(); 932 if (placement == null) continue; 933 getModel().weaken(getAssignment(), placement); 934 getAssignment().assign(0, placement); 935 } 936 937 currentSolution.saveBest(); 938 for (Lecture lecture : getModel().variables()) { 939 iProgress.incProgress(); 940 getAssignment().unassign(0, lecture); 941 } 942 } 943 944 iProgress.setPhase("Creating initial assignment ...", assignedPlacements.size()); 945 for (Map.Entry<Lecture, Placement> entry : assignedPlacements.entrySet()) { 946 Lecture lecture = entry.getKey(); 947 Placement placement = entry.getValue(); 948 if (lecture.isCommitted()) { iProgress.incProgress(); continue; } 949 getModel().weaken(getAssignment(), placement); 950 Map<Constraint<Lecture, Placement>, Set<Placement>> conflictConstraints = getModel().conflictConstraints(getAssignment(), placement); 951 if (conflictConstraints.isEmpty()) { 952 if (!placement.isValid()) { 953 iProgress.warn("WARNING: Lecture " + lecture.getName() + " does not contain assignment " 954 + placement.getLongName(true) + " in its domain (" + placement.getNotValidReason(getAssignment(), true) + ")."); 955 } else 956 getAssignment().assign(0, placement); 957 } else { 958 iProgress.warn("WARNING: Unable to assign " + lecture.getName() + " := " + placement.getName()); 959 iProgress.debug(" Reason:"); 960 for (Constraint<Lecture, Placement> c : conflictConstraints.keySet()) { 961 Set<Placement> vals = conflictConstraints.get(c); 962 for (Placement v : vals) { 963 iProgress.debug(" " + v.variable().getName() + " = " + v.getName()); 964 } 965 iProgress.debug(" in constraint " + c); 966 } 967 } 968 iProgress.incProgress(); 969 } 970 971 if (initialSectioning && getAssignment().nrAssignedVariables() != 0 && !getModel().getProperties().getPropertyBoolean("Global.LoadStudentEnrlsFromSolution", false)) 972 getModel().switchStudents(getAssignment()); 973 974 if (iForcedPerturbances > 0) { 975 iProgress.setPhase("Forcing perturbances", iForcedPerturbances); 976 for (int i = 0; i < iForcedPerturbances; i++) { 977 iProgress.setProgress(i); 978 Lecture var = null; 979 do { 980 var = ToolBox.random(getModel().variables()); 981 } while (var.getInitialAssignment() == null || var.values(getAssignment()).size() <= 1); 982 var.removeInitialValue(); 983 } 984 } 985 986 /* 987 for (Constraint<Lecture, Placement> c : getModel().constraints()) { 988 if (c instanceof SpreadConstraint) 989 ((SpreadConstraint) c).init(); 990 if (c instanceof DiscouragedRoomConstraint) 991 ((DiscouragedRoomConstraint) c).setEnabled(true); 992 if (c instanceof MinimizeNumberOfUsedRoomsConstraint) 993 ((MinimizeNumberOfUsedRoomsConstraint) c).setEnabled(true); 994 if (c instanceof MinimizeNumberOfUsedGroupsOfTime) 995 ((MinimizeNumberOfUsedGroupsOfTime) c).setEnabled(true); 996 } 997 */ 998 } 999 1000 public static Date getDate(int year, int dayOfYear) { 1001 Calendar c = Calendar.getInstance(Locale.US); 1002 c.set(year, 1, 1, 0, 0, 0); 1003 c.set(Calendar.DAY_OF_YEAR, dayOfYear); 1004 return c.getTime(); 1005 } 1006 1007 public static class DatePattern { 1008 Long iId; 1009 String iName; 1010 BitSet iPattern; 1011 public DatePattern() {} 1012 public DatePattern(Long id, String name, BitSet pattern) { 1013 setId(id); setName(name); setPattern(pattern); 1014 } 1015 public DatePattern(Long id, String name, String pattern) { 1016 setId(id); setName(name); setPattern(pattern); 1017 } 1018 public Long getId() { return iId; } 1019 public void setId(Long id) { iId = id; } 1020 public String getName() { return iName; } 1021 public void setName(String name) { iName = name; } 1022 public BitSet getPattern() { return iPattern; } 1023 public void setPattern(BitSet pattern) { iPattern = pattern; } 1024 public void setPattern(String pattern) { 1025 iPattern = new BitSet(pattern.length()); 1026 for (int i = 0; i < pattern.length(); i++) 1027 if (pattern.charAt(i) == '1') 1028 iPattern.set(i); 1029 } 1030 public void setPattern(int startDay, int endDay) { 1031 iPattern = new BitSet(366); 1032 for (int d = startDay; d <= endDay; d++) 1033 iPattern.set(d); 1034 } 1035 } 1036}