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