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