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