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