001    package ttsolver;
002    
003    import ifs.model.*;
004    import ifs.util.*;
005    
006    import java.io.*;
007    import java.util.*;
008    
009    import org.dom4j.*;
010    import org.dom4j.io.*;
011    
012    import ttsolver.constraint.*;
013    import ttsolver.model.*;
014    
015    /**
016     * This class loads the input model from XML file.
017     * <br><br>
018     * Parameters:
019     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
020     * <tr><td>General.Input</td><td>{@link String}</td><td>Input XML file</td></tr>
021     * <tr><td>General.InitialAssignment</td><td>{@link Boolean}</td><td>Use the solution as initial assignment</td></tr>
022     * <tr><td>General.UseDepartmentSpreadConstraints</td><td>{@link Boolean}</td><td>Use {@link DepartmentSpreadConstraint}</td></tr>
023     * <tr><td>General.MPP</td><td>{@link Boolean}</td><td>Minimal perturbation problem (if true, initial assignments are set from solution)</td></tr>
024     * <tr><td>General.ForcedPerturbances</td><td>{@link Integer}</td><td>For testing of MPP: number of input perturbations, i.e., classes with prohibited intial assignment</td></tr>
025     * <tr><td>General.UseDistanceConstraints</td><td>{@link Boolean}</td><td>Consider distances between buildings</td></tr>
026     * </table>
027     * 
028     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
029     * @version 1.0
030     */
031    
032    public class TimetableXMLLoader extends TimetableLoader {
033        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(TimetableXMLLoader.class);
034    
035        private boolean iUseDepartmentSpreadConstraints = true;
036        private int iForcedPerturbances = 0;
037        
038        private boolean iInitialAssignment;
039        private boolean iMppAssignment;
040        private boolean iUseDistanceConstraints;
041        private File iInputFile;
042        
043        public TimetableXMLLoader(TimetableModel model) {
044            super(model);
045            iInputFile                 = new File(getModel().getProperties().getProperty("General.Input"));
046            iForcedPerturbances        = getModel().getProperties().getPropertyInt("General.ForcedPerturbances",0);
047            iMppAssignment             = getModel().getProperties().getPropertyBoolean("General.MPP",false);
048            iInitialAssignment         = !iMppAssignment && getModel().getProperties().getPropertyBoolean("General.InitialAssignment",false);
049            iUseDepartmentSpreadConstraints = getModel().getProperties().getPropertyBoolean("General.UseDepartmentSpreadConstraints",true);
050            iUseDistanceConstraints = getModel().getProperties().getPropertyBoolean("General.UseDistanceConstraints", true);
051        }
052    
053        public void load(PrintWriter out) throws Exception {
054            sLogger.debug("Reading XML data from "+iInputFile);
055            Progress.getInstance().setPhase("Reading "+iInputFile.getName()+" ...");
056            
057            Document document = (new SAXReader()).read(iInputFile);
058            Element root = document.getRootElement();
059            sLogger.debug("Root element: "+root.getName());
060            if (!"llrt".equals(root.getName())) {
061                sLogger.error("Given XML file is not large lecture room timetabling problem.");
062                return;
063            }
064            
065            if (root.element("input")!=null) root = root.element("input");
066            
067            sLogger.info("Going to load data "+root.attributeValue("semester")+root.attributeValue("year")+"v"+root.attributeValue("version")+" ...");
068            getModel().getProperties().setProperty("Data.Semester", root.attributeValue("semester"));
069            getModel().getProperties().setProperty("Data.Year", root.attributeValue("year"));
070            getModel().getProperties().setProperty("Data.Version", root.attributeValue("version"));
071            
072            Progress.getInstance().setPhase("Creating rooms ...",root.element("rooms").elements("room").size());
073            Hashtable roomElements = new Hashtable();
074            Hashtable roomConstraints = new Hashtable();
075            Hashtable sameLectures = new Hashtable();
076            for (Iterator i=root.element("rooms").elementIterator("room");i.hasNext();) {
077                Element roomEl = (Element)i.next();
078                RoomConstraint constraint = new RoomConstraint(roomEl.attributeValue("id"), "r"+roomEl.attributeValue("id"), edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY,edu.purdue.smas.timetable.util.Constants.DAY_CODES.length, roomEl.attributeValue("capacity")+" seats");
079                getModel().addConstraint(constraint);
080                Progress.getInstance().incProgress();
081                roomElements.put(roomEl.attributeValue("id"), roomEl);
082                roomConstraints.put(roomEl.attributeValue("id"), constraint);
083            }
084            
085            Progress.getInstance().setPhase("Creating variables ...",root.element("classes").elements("class").size());
086            
087            int nrClasses = root.element("classes").elements("class").size();
088            
089            Hashtable classElements = new Hashtable();
090            Hashtable lectures = new Hashtable();
091            Hashtable initialPlacements = new Hashtable();
092            Hashtable instructorConstraints = new Hashtable();
093            for (Iterator i1=root.element("classes").elementIterator("class");i1.hasNext();) {
094                Element classEl = (Element)i1.next();
095                
096                classElements.put(classEl.attributeValue("id"),classEl);
097                Element instructorEl = (Element)classEl.element("instructor");
098                InstructorConstraint instructorConstraint = null;
099                if (instructorEl!=null) {
100                    instructorConstraint = (InstructorConstraint)instructorConstraints.get(instructorEl.attributeValue("id"));
101                    if (instructorConstraint==null) {
102                        instructorConstraint = new InstructorConstraint(instructorEl.attributeValue("id"), "i"+instructorEl.attributeValue("id"), edu.purdue.smas.timetable.util.Constants.SLOTS_PER_DAY,edu.purdue.smas.timetable.util.Constants.DAY_CODES.length);
103                        instructorConstraints.put(instructorEl.attributeValue("id"), instructorConstraint);
104                        getModel().addConstraint(instructorConstraint);
105                    }
106                }
107                Vector roomLocations = new FastVector();
108                Vector roomConstraintsThisClass = new FastVector();
109                RoomLocation initialRoomLocation = null;
110                int bestRoomPref = Integer.MAX_VALUE;
111                for (Iterator i2=classEl.elementIterator("room");i2.hasNext();) {
112                    Element roomLocationEl = (Element)i2.next();
113                    Element roomEl = (Element)roomElements.get(roomLocationEl.attributeValue("id"));
114                    RoomConstraint roomConstraint = (RoomConstraint)roomConstraints.get(roomLocationEl.attributeValue("id"));
115                    roomConstraintsThisClass.add(roomConstraint);
116                    RoomLocation rl = new RoomLocation(roomConstraint.getResourceId(),roomConstraint.getName(),null,Integer.parseInt(roomLocationEl.attributeValue("pref")),Integer.parseInt(roomEl.attributeValue("capacity")));
117                    if (roomEl.attributeValue("location")!=null) {
118                        String loc = roomEl.attributeValue("location");
119                        int posX = Integer.parseInt(loc.substring(0,loc.indexOf(',')));
120                        int posY = Integer.parseInt(loc.substring(loc.indexOf(',')+1));
121                        rl.setCoordinates(posX, posY);
122                    }
123                    bestRoomPref = Math.min(bestRoomPref, Integer.parseInt(roomLocationEl.attributeValue("pref")));
124                    if ("true".equals(roomLocationEl.attributeValue("solution")))
125                        initialRoomLocation = rl;
126                    roomLocations.add(rl);
127                }
128                if (roomLocations.isEmpty()) {
129                    sLogger.error("  ERROR: No room.");
130                    continue;
131                }
132                double bestTimePref = Double.MAX_VALUE;
133                Vector timeLocations = new FastVector();
134                TimeLocation initialTimeLocation = null;
135                for (Iterator i2=classEl.elementIterator("time");i2.hasNext();) {
136                    Element timeLocationEl = (Element)i2.next();
137                    TimeLocation tl = new TimeLocation(
138                        Integer.parseInt(timeLocationEl.attributeValue("days"),2),
139                        Integer.parseInt(timeLocationEl.attributeValue("start")),
140                        Integer.parseInt(timeLocationEl.attributeValue("length")),
141                        Integer.parseInt(timeLocationEl.attributeValue("pref"))
142                        );
143                    bestTimePref = Math.min(bestTimePref, Integer.parseInt(timeLocationEl.attributeValue("pref")));
144                    if ("true".equals(timeLocationEl.attributeValue("solution")))
145                        initialTimeLocation = tl;
146                    timeLocations.add(tl);
147                }
148                if (timeLocations.isEmpty()) {
149                    sLogger.error("  ERROR: No time.");
150                    continue;
151                }
152                
153                Lecture lecture = new Lecture(Long.parseLong(classEl.attributeValue("id")),  "c"+classEl.attributeValue("id"),  timeLocations,  bestTimePref,  (instructorEl==null?null:instructorEl.attributeValue("id")), roomLocations, bestRoomPref,  null, Integer.parseInt(classEl.attributeValue("expectedCapacity")),  (instructorEl==null?null:"i"+instructorEl.attributeValue("id")), "?");
154                if (initialTimeLocation!=null && initialRoomLocation!=null) {
155                    initialPlacements.put(lecture, new Placement(null,initialTimeLocation, initialRoomLocation));
156                } else {
157                    sLogger.debug("Lecture "+lecture+" has no initial placement (time="+initialTimeLocation+", room="+initialRoomLocation+")");
158                }
159                lectures.put(classEl.attributeValue("id"), lecture);
160                lecture.setDepartment(classEl.attributeValue("department"));
161                Vector sames = (Vector)sameLectures.get(classEl.attributeValue("course"));
162                if (sames==null) {
163                    sames = new FastVector();
164                    sameLectures.put(classEl.attributeValue("course"), sames);
165                }
166                sames.addElement(lecture);
167    
168                getModel().setBestRoomPreference(getModel().getBestRoomPreference() + bestRoomPref);
169                getModel().setBestTimePreference(getModel().getBestTimePreference() + bestTimePref);
170                getModel().addVariable(lecture);
171                if (instructorConstraint!=null) instructorConstraint.addVariable(lecture);
172                
173                for (Enumeration e2=roomConstraintsThisClass.elements(); e2.hasMoreElements();)
174                    ((Constraint)e2.nextElement()).addVariable(lecture);
175                
176                if (lecture.getInitialAssignment()!=null && getModel().conflictValues(lecture.getInitialAssignment()).isEmpty()) {
177                    lecture.assign(0,lecture.getInitialAssignment());
178                }
179                Progress.getInstance().incProgress();
180            }
181            
182            Progress.getInstance().setPhase("Creating constraints ...",root.element("groupConstraints").elements("constraint").size());
183            Hashtable grConstraintElements = new Hashtable();
184            Hashtable groupConstraints = new Hashtable();
185            for (Iterator i1=root.element("groupConstraints").elementIterator("constraint");i1.hasNext();) {
186                Element grConstraintEl = (Element)i1.next();
187                GroupConstraint gc = new GroupConstraint(Long.parseLong(grConstraintEl.attributeValue("id")), grConstraintEl.attributeValue("type"), grConstraintEl.attributeValue("pref"));
188                gc.setGlobalPreference(getModel().getGlobalGroupConstraintPreferenceCounter());
189                getModel().addConstraint(gc);
190                for (Iterator i2=grConstraintEl.elementIterator("class");i2.hasNext();) {
191                    String classId = ((Element)i2.next()).attributeValue("id");
192                    gc.addVariable((Lecture)lectures.get(classId));
193                }
194                grConstraintElements.put(grConstraintEl.attributeValue("id"),grConstraintEl);
195                groupConstraints.put(grConstraintEl.attributeValue("id"),gc);
196                Progress.getInstance().incProgress();
197            }
198            
199            Progress.getInstance().setPhase("Loading students ...",root.element("students").elements("student").size());
200            Hashtable jenrlConstraints = new Hashtable();
201            for (Iterator i1=root.element("students").elementIterator("student");i1.hasNext();) {
202                Element studentEl = (Element)i1.next();
203                Vector lecturesThisStudent = new Vector();
204                for (Iterator i2=studentEl.elementIterator("class");i2.hasNext();) {
205                    String classId = ((Element)i2.next()).attributeValue("id");
206                    Lecture lecture = (Lecture)lectures.get(classId);
207                    lecture.addStudent(studentEl.attributeValue("id"));
208                    lecturesThisStudent.add(lecture);
209                }
210                for (Enumeration e1=lecturesThisStudent.elements();e1.hasMoreElements();) {
211                    Lecture lect1 = (Lecture)e1.nextElement();
212                    for (Enumeration e2=lecturesThisStudent.elements();e2.hasMoreElements();) {
213                        Lecture lect2 = (Lecture)e2.nextElement();
214                        if (lect1.getClassId()<lect2.getClassId()) {
215                            JenrlConstraint jenrl =  (JenrlConstraint)jenrlConstraints.get(lect1.getClassId()+","+lect2.getClassId());
216                            if (jenrl==null) {
217                                jenrl = new JenrlConstraint(1, getModel().getViolatedStudentConflictsCounter());
218                                getModel().addConstraint(jenrl);
219                                jenrl.addVariable(lect1);
220                                jenrl.addVariable(lect2);
221                                jenrlConstraints.put(lect1.getClassId()+","+lect2.getClassId(), jenrl);
222                            } else {
223                                jenrl.incJenrl();
224                            }
225                        }
226                    }
227                }
228                Progress.getInstance().incProgress();
229            }
230            
231            for (Enumeration e1=sameLectures.elements();e1.hasMoreElements();) {
232                Vector sames = (Vector)e1.nextElement();
233                for (Enumeration e2=sames.elements(); e2.hasMoreElements();) {
234                    Lecture lect = (Lecture)e2.nextElement();
235                    lect.setSameLectures(sames);
236                }
237            }
238    
239            if (iMppAssignment || iInitialAssignment) {
240                Progress.getInstance().setPhase("Creating initial assignment ...",initialPlacements.size());
241                for (Iterator ip=initialPlacements.entrySet().iterator();ip.hasNext();) {
242                    Map.Entry entry = (Map.Entry)ip.next();
243                    Lecture lecture = (Lecture)entry.getKey();
244                    Placement placement = (Placement)entry.getValue();
245                    placement.setVariable(lecture);
246                    if (iMppAssignment) lecture.setInitialAssignment(placement);
247                    Hashtable conflictConstraints = getModel().conflictConstraints(placement);
248                    if (conflictConstraints.isEmpty()) {
249                        lecture.assign(0,placement);
250                    } else {
251                        sLogger.warn("WARNING: Unable to assign "+lecture.getName()+" := "+placement.getName());
252                        sLogger.debug("  Reason:");
253                        for (Enumeration ex=conflictConstraints.keys();ex.hasMoreElements();) {
254                            Constraint c = (Constraint)ex.nextElement();
255                            Collection vals = (Collection)conflictConstraints.get(c);
256                            for (Iterator i=vals.iterator();i.hasNext();) {
257                                Value v = (Value) i.next();
258                                sLogger.debug("    "+v.variable().getName()+" = "+v.getName());
259                            }
260                            sLogger.debug("    in constraint "+c);
261                        }
262                    }
263                    Progress.getInstance().incProgress();
264                }
265            }
266    
267            if (iForcedPerturbances>0) {
268                Progress.getInstance().setPhase("Forcing perturbances",iForcedPerturbances);
269                for (int i=0;i<iForcedPerturbances;i++) {
270                    Progress.getInstance().setProgress(i);
271                    Variable var = null;
272                    do {
273                        var = (Variable)ToolBox.random(getModel().variables());
274                    } while (var.getInitialAssignment()==null || var.values().size()<=1);
275                    var.removeInitialValue();
276                }
277            }
278    
279            if (iUseDepartmentSpreadConstraints) {
280                Progress.getInstance().setPhase("Creating dept. spread constraints ...",getModel().variables().size());
281                Hashtable depSpreadConstraints = new Hashtable();
282                for (Enumeration e=getModel().variables().elements();e.hasMoreElements();) {
283                    Lecture lecture = (Lecture)e.nextElement();
284                    if (lecture.getDepartment()==null) continue;
285                    DepartmentSpreadConstraint deptConstr = (DepartmentSpreadConstraint)depSpreadConstraints.get(lecture.getDepartment());
286                    if (deptConstr==null) {
287                        deptConstr = new DepartmentSpreadConstraint(getModel().getProperties(),lecture.getDepartment());
288                        depSpreadConstraints.put(lecture.getDepartment(),deptConstr);
289                        getModel().addConstraint(deptConstr);
290                    }
291                    deptConstr.addVariable(lecture);
292                    Progress.getInstance().incProgress();
293                }
294                for (Enumeration e=depSpreadConstraints.elements();e.hasMoreElements();)
295                    ((DepartmentSpreadConstraint)e.nextElement()).init();
296            }
297            Progress.getInstance().setPhase("Done",1);Progress.getInstance().incProgress();
298    
299            sLogger.debug("Model successfully loaded.");
300            out.println("Model successfully loaded.");
301        }    
302    }