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