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