001 package net.sf.cpsolver.coursett; 002 003 import java.io.File; 004 import java.io.FileOutputStream; 005 import java.io.IOException; 006 import java.text.DecimalFormat; 007 import java.util.BitSet; 008 import java.util.Collections; 009 import java.util.Date; 010 import java.util.Dictionary; 011 import java.util.Enumeration; 012 import java.util.HashSet; 013 import java.util.Hashtable; 014 import java.util.Iterator; 015 import java.util.Map; 016 import java.util.Set; 017 import java.util.Vector; 018 019 import org.dom4j.Document; 020 import org.dom4j.DocumentHelper; 021 import org.dom4j.Element; 022 import org.dom4j.io.OutputFormat; 023 import org.dom4j.io.XMLWriter; 024 025 import net.sf.cpsolver.coursett.constraint.ClassLimitConstraint; 026 import net.sf.cpsolver.coursett.constraint.DiscouragedRoomConstraint; 027 import net.sf.cpsolver.coursett.constraint.InstructorConstraint; 028 import net.sf.cpsolver.coursett.constraint.MinimizeNumberOfUsedGroupsOfTime; 029 import net.sf.cpsolver.coursett.constraint.MinimizeNumberOfUsedRoomsConstraint; 030 import net.sf.cpsolver.coursett.constraint.RoomConstraint; 031 import net.sf.cpsolver.coursett.constraint.SpreadConstraint; 032 import net.sf.cpsolver.coursett.model.Lecture; 033 import net.sf.cpsolver.coursett.model.Placement; 034 import net.sf.cpsolver.coursett.model.RoomLocation; 035 import net.sf.cpsolver.coursett.model.RoomSharingModel; 036 import net.sf.cpsolver.coursett.model.Student; 037 import net.sf.cpsolver.coursett.model.TimeLocation; 038 import net.sf.cpsolver.ifs.model.Constraint; 039 import net.sf.cpsolver.ifs.solver.Solver; 040 import net.sf.cpsolver.ifs.util.Progress; 041 import net.sf.cpsolver.ifs.util.ToolBox; 042 043 044 /** 045 * This class saves the resultant solution in the XML format. 046 * <br><br> 047 * Parameters: 048 * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr> 049 * <tr><td>General.Output</td><td>{@link String}</td><td>Folder with the output solution in XML format (solution.xml)</td></tr> 050 * <tr><td>Xml.ConvertIds</td><td>{@link Boolean}</td><td>If true, ids are converted (to be able to make input data public)</td></tr> 051 * <tr><td>Xml.ShowNames</td><td>{@link Boolean}</td><td>If false, names are not exported (to be able to make input data public)</td></tr> 052 * <tr><td>Xml.SaveBest</td><td>{@link Boolean}</td><td>If true, best solution is saved.</td></tr> 053 * <tr><td>Xml.SaveInitial</td><td>{@link Boolean}</td><td>If true, initial solution is saved.</td></tr> 054 * <tr><td>Xml.SaveCurrent</td><td>{@link Boolean}</td><td>If true, current solution is saved.</td></tr> 055 * <tr><td>Xml.ExportStudentSectioning</td><td>{@link Boolean}</td><td>If true, student sectioning is saved even when there is no solution.</td></tr> 056 * </table> 057 * 058 * @version 059 * CourseTT 1.1 (University Course Timetabling)<br> 060 * Copyright (C) 2006 Tomáš Müller<br> 061 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 062 * Lazenska 391, 76314 Zlin, Czech Republic<br> 063 * <br> 064 * This library is free software; you can redistribute it and/or 065 * modify it under the terms of the GNU Lesser General Public 066 * License as published by the Free Software Foundation; either 067 * version 2.1 of the License, or (at your option) any later version. 068 * <br><br> 069 * This library is distributed in the hope that it will be useful, 070 * but WITHOUT ANY WARRANTY; without even the implied warranty of 071 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 072 * Lesser General Public License for more details. 073 * <br><br> 074 * You should have received a copy of the GNU Lesser General Public 075 * License along with this library; if not, write to the Free Software 076 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 077 */ 078 079 public class TimetableXMLSaver extends TimetableSaver { 080 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(TimetableXMLSaver.class); 081 private static DecimalFormat[] sDF = {new DecimalFormat(""),new DecimalFormat("0"),new DecimalFormat("00"),new DecimalFormat("000"),new DecimalFormat("0000"),new DecimalFormat("00000"),new DecimalFormat("000000"),new DecimalFormat("0000000")}; 082 private static DecimalFormat sStudentWeightFormat = new DecimalFormat("0.0000"); 083 public static boolean ANONYMISE = false; 084 085 private boolean iConvertIds = false; 086 private boolean iShowNames = false; 087 private File iOutputFolder = null; 088 private File iOutFile = null; 089 private boolean iSaveBest = false; 090 private boolean iSaveInitial = false; 091 private boolean iSaveCurrent = false; 092 private boolean iExportStudentSectioning = false; 093 094 private IdConvertor iIdConvertor = null; 095 096 public TimetableXMLSaver(Solver solver) { 097 super(solver); 098 iOutputFolder = new File(getModel().getProperties().getProperty("General.Output","."+File.separator+"output")); 099 iShowNames = getModel().getProperties().getPropertyBoolean("Xml.ShowNames",false); 100 iExportStudentSectioning = getModel().getProperties().getPropertyBoolean("Xml.ExportStudentSectioning", false); 101 if (ANONYMISE) { 102 //anonymise saved XML file -- if not set otherwise in the configuration 103 iConvertIds = getModel().getProperties().getPropertyBoolean("Xml.ConvertIds",true); 104 iSaveBest = getModel().getProperties().getPropertyBoolean("Xml.SaveBest", false); 105 iSaveInitial = getModel().getProperties().getPropertyBoolean("Xml.SaveInitial", false); 106 iSaveCurrent = getModel().getProperties().getPropertyBoolean("Xml.SaveCurrent", true); 107 } else { 108 // normal operation -- if not set otherwise in the configuration 109 iConvertIds = getModel().getProperties().getPropertyBoolean("Xml.ConvertIds",false); 110 iSaveBest = getModel().getProperties().getPropertyBoolean("Xml.SaveBest", true); 111 iSaveInitial = getModel().getProperties().getPropertyBoolean("Xml.SaveInitial", true); 112 iSaveCurrent = getModel().getProperties().getPropertyBoolean("Xml.SaveCurrent", true); 113 } 114 } 115 116 private String getId(String type, String id) { 117 if (!iConvertIds) return id.toString(); 118 if (iIdConvertor==null) iIdConvertor = new IdConvertor(getModel().getProperties().getProperty("Xml.IdConv")); 119 return iIdConvertor.convert(type, id); 120 } 121 122 private String getId(String type, Number id) { 123 return getId(type, id.toString()); 124 } 125 126 private String getAvailableString(boolean[] availableArray) { 127 if (availableArray==null) return null; 128 StringBuffer sb = new StringBuffer(); 129 for (int i=0;i<availableArray.length;i++) 130 sb.append(availableArray[i]?"1":"0"); 131 return sb.toString(); 132 } 133 134 private static String bitset2string(BitSet b) { 135 StringBuffer sb = new StringBuffer(); 136 for (int i=0;i<b.length();i++) 137 sb.append(b.get(i)?"1":"0"); 138 return sb.toString(); 139 } 140 141 public void save() throws Exception { 142 save(null); 143 } 144 145 public void save(File outFile) throws Exception { 146 if (outFile==null) 147 outFile = new File(iOutputFolder,"solution.xml"); 148 outFile.getParentFile().mkdirs(); 149 sLogger.debug("Writting XML data to:"+outFile); 150 151 Document document = DocumentHelper.createDocument(); 152 document.addComment("University Course Timetabling"); 153 154 if (iSaveCurrent && !getModel().assignedVariables().isEmpty()) { 155 StringBuffer comments = new StringBuffer("Solution Info:\n"); 156 Dictionary solutionInfo=(getSolution()==null?getModel().getInfo():getSolution().getInfo()); 157 for (Enumeration e=ToolBox.sortEnumeration(solutionInfo.keys());e.hasMoreElements();) { 158 String key = (String)e.nextElement(); 159 Object value = solutionInfo.get(key); 160 comments.append(" "+key+": "+value+"\n"); 161 } 162 document.addComment(comments.toString()); 163 } 164 165 Element root = document.addElement("timetable"); 166 root.addAttribute("version","2.4"); 167 root.addAttribute("initiative", getModel().getProperties().getProperty("Data.Initiative")); 168 root.addAttribute("term", getModel().getProperties().getProperty("Data.Term")); 169 root.addAttribute("year", String.valueOf(getModel().getYear())); 170 root.addAttribute("created", String.valueOf(new Date())); 171 root.addAttribute("nrDays", String.valueOf(Constants.DAY_CODES.length)); 172 root.addAttribute("slotsPerDay", String.valueOf(Constants.SLOTS_PER_DAY)); 173 if (!iConvertIds && getModel().getProperties().getProperty("General.SessionId")!=null) 174 root.addAttribute("session", getModel().getProperties().getProperty("General.SessionId")); 175 if (iShowNames && !iConvertIds && getModel().getProperties().getProperty("General.SolverGroupId")!=null) 176 root.addAttribute("solverGroup", getId("solverGroup",getModel().getProperties().getProperty("General.SolverGroupId"))); 177 178 Hashtable roomElements = new Hashtable(); 179 180 Element roomsEl = root.addElement("rooms"); 181 for (Enumeration e=getModel().getRoomConstraints().elements();e.hasMoreElements();) { 182 RoomConstraint roomConstraint = (RoomConstraint)e.nextElement(); 183 Element roomEl = roomsEl.addElement("room").addAttribute("id", getId("room", roomConstraint.getResourceId())); 184 roomEl.addAttribute("constraint", "true"); 185 if (roomConstraint instanceof DiscouragedRoomConstraint) 186 roomEl.addAttribute("discouraged", "true"); 187 if (iShowNames) { 188 roomEl.addAttribute("name",roomConstraint.getRoomName()); 189 } 190 if (!iConvertIds && roomConstraint.getBuildingId()!=null) 191 roomEl.addAttribute("building", getId("bldg", roomConstraint.getBuildingId())); 192 roomElements.put(getId("room", roomConstraint.getResourceId()), roomEl); 193 roomEl.addAttribute("capacity", String.valueOf(roomConstraint.getCapacity())); 194 if (roomConstraint.getPosX()>0 || roomConstraint.getPosY()>0) 195 roomEl.addAttribute("location", roomConstraint.getPosX()+","+roomConstraint.getPosY()); 196 if (roomConstraint.getIgnoreTooFar()) 197 roomEl.addAttribute("ignoreTooFar", "true"); 198 if (!roomConstraint.getConstraint()) 199 roomEl.addAttribute("fake", "true"); 200 if (roomConstraint.getSharingModel()!=null) { 201 RoomSharingModel sharingModel = roomConstraint.getSharingModel(); 202 Element sharingEl = roomEl.addElement("sharing"); 203 sharingEl.addElement("pattern").addAttribute("unit", "6").setText(sharingModel.getPreferences()); 204 sharingEl.addElement("freeForAll").addAttribute("value",String.valueOf(RoomSharingModel.sFreeForAllPrefChar)); 205 sharingEl.addElement("notAvailable").addAttribute("value",String.valueOf(RoomSharingModel.sNotAvailablePrefChar)); 206 for (int i=0;i<sharingModel.getNrDepartments();i++) { 207 sharingEl.addElement("department").addAttribute("value", String.valueOf((char)('0'+i))).addAttribute("id", getId("dept", sharingModel.getDepartmentIds()[i])); 208 } 209 } 210 if (roomConstraint.getType()!=null && iShowNames) 211 roomEl.addAttribute("type",roomConstraint.getType().toString()); 212 } 213 214 Element instructorsEl = root.addElement("instructors"); 215 216 Element departmentsEl = root.addElement("departments"); 217 Hashtable depts = new Hashtable(); 218 219 Element configsEl = (iShowNames?root.addElement("configurations"):null); 220 HashSet configs = new HashSet(); 221 222 Element classesEl = root.addElement("classes"); 223 Hashtable classElements = new Hashtable(); 224 Vector vars = new Vector(getModel().variables()); 225 if (getModel().hasConstantVariables()) vars.addAll(getModel().constantVariables()); 226 for (Enumeration e1=vars.elements();e1.hasMoreElements();) { 227 Lecture lecture = (Lecture)e1.nextElement(); 228 Placement placement = (Placement)lecture.getAssignment(); 229 if (lecture.isCommitted() && placement==null) 230 placement = (Placement)lecture.getInitialAssignment(); 231 Placement initialPlacement = (Placement)lecture.getInitialAssignment(); 232 //if (initialPlacement==null) initialPlacement = (Placement)lecture.getAssignment(); 233 Placement bestPlacement = (Placement)lecture.getBestAssignment(); 234 Element classEl = classesEl.addElement("class").addAttribute("id", getId("class", lecture.getClassId())); 235 classElements.put(lecture.getClassId(), classEl); 236 if (iShowNames && lecture.getNote()!=null) 237 classEl.addAttribute("note",lecture.getNote()); 238 if (iShowNames && !lecture.isCommitted()) classEl.addAttribute("ord",String.valueOf(lecture.getOrd())); 239 if (iShowNames && lecture.getSolverGroupId()!=null) 240 classEl.addAttribute("solverGroup", getId("solverGroup",lecture.getSolverGroupId())); 241 if (lecture.getParent()==null && lecture.getConfiguration()!=null) { 242 if (!iShowNames) 243 classEl.addAttribute("offering", getId("offering", lecture.getConfiguration().getOfferingId().toString())); 244 classEl.addAttribute("config", getId("config", lecture.getConfiguration().getConfigId().toString())); 245 if (iShowNames && configs.add(lecture.getConfiguration())) { 246 configsEl.addElement("config"). 247 addAttribute("id", getId("config", lecture.getConfiguration().getConfigId().toString())). 248 addAttribute("limit", String.valueOf(lecture.getConfiguration().getLimit())). 249 addAttribute("offering", getId("offering", lecture.getConfiguration().getOfferingId().toString())); 250 } 251 } 252 classEl.addAttribute("committed", (lecture.isCommitted()?"true":"false")); 253 if (lecture.getParent()!=null) 254 classEl.addAttribute("parent", getId("class", lecture.getParent().getClassId())); 255 if (lecture.getSchedulingSubpartId()!=null) 256 classEl.addAttribute("subpart", getId("subpart", lecture.getSchedulingSubpartId())); 257 if (iShowNames && lecture.isCommitted() && placement!=null && placement.getAssignmentId()!=null) { 258 classEl.addAttribute("assignment", getId("assignment", placement.getAssignmentId())); 259 } 260 if (!lecture.isCommitted()) { 261 if (lecture.minClassLimit()==lecture.maxClassLimit()) { 262 classEl.addAttribute("classLimit", String.valueOf(lecture.maxClassLimit())); 263 } else { 264 classEl.addAttribute("minClassLimit", String.valueOf(lecture.minClassLimit())); 265 classEl.addAttribute("maxClassLimit", String.valueOf(lecture.maxClassLimit())); 266 } 267 if (lecture.roomToLimitRatio()!=1.0) 268 classEl.addAttribute("roomToLimitRatio", String.valueOf(lecture.roomToLimitRatio())); 269 } 270 if (lecture.getNrRooms()!=1) 271 classEl.addAttribute("nrRooms",String.valueOf(lecture.getNrRooms())); 272 if (iShowNames) 273 classEl.addAttribute("name", lecture.getName()); 274 if (lecture.getDeptSpreadConstraint()!=null) { 275 classEl.addAttribute("department", getId("dept", lecture.getDeptSpreadConstraint().getDepartmentId())); 276 depts.put(lecture.getDeptSpreadConstraint().getDepartmentId(),lecture.getDeptSpreadConstraint().getName()); 277 } 278 if (lecture.getScheduler()!=null) 279 classEl.addAttribute("scheduler", getId("dept", lecture.getScheduler())); 280 for (Enumeration e2=lecture.getInstructorConstraints().elements();e2.hasMoreElements();) { 281 InstructorConstraint ic = (InstructorConstraint)e2.nextElement(); 282 Element instrEl = classEl.addElement("instructor").addAttribute("id", getId("inst", ic.getResourceId())); 283 if ((lecture.isCommitted() || iSaveCurrent) && placement!=null) instrEl.addAttribute("solution","true"); 284 if (iSaveInitial && initialPlacement!=null) instrEl.addAttribute("initial","true"); 285 if (iSaveBest && bestPlacement!=null && !bestPlacement.equals(placement)) instrEl.addAttribute("best", "true"); 286 } 287 for (Enumeration e2=lecture.roomLocations().elements();e2.hasMoreElements();) { 288 RoomLocation rl = (RoomLocation)e2.nextElement(); 289 Element roomLocationEl = (Element)classEl.addElement("room"); 290 roomLocationEl.addAttribute("id", getId("room", rl.getId())); 291 roomLocationEl.addAttribute("pref", String.valueOf(rl.getPreference())); 292 if ((lecture.isCommitted() || iSaveCurrent) && placement!=null && placement.hasRoomLocation(rl.getId())) roomLocationEl.addAttribute("solution", "true"); 293 if (iSaveInitial && initialPlacement!=null && initialPlacement.hasRoomLocation(rl.getId())) roomLocationEl.addAttribute("initial", "true"); 294 if (iSaveBest && bestPlacement!=null && !bestPlacement.equals(placement) && bestPlacement.hasRoomLocation(rl.getId())) roomLocationEl.addAttribute("best", "true"); 295 if (!roomElements.containsKey(getId("room", rl.getId()))) { 296 //room location without room constraint 297 Element roomEl = roomsEl.addElement("room").addAttribute("id", getId("room", rl.getId())); 298 roomEl.addAttribute("constraint", "false"); 299 if (!iConvertIds && rl.getBuildingId()!=null) 300 roomEl.addAttribute("building", getId("bldg", rl.getBuildingId())); 301 if (iShowNames) { 302 roomEl.addAttribute("name",rl.getName()); 303 } 304 roomElements.put(getId("room", rl.getId()), roomEl); 305 roomEl.addAttribute("capacity", String.valueOf(rl.getRoomSize())); 306 if (rl.getPosX()>0 || rl.getPosY()>0) 307 roomEl.addAttribute("location", rl.getPosX()+","+rl.getPosY()); 308 if (rl.getIgnoreTooFar()) 309 roomEl.addAttribute("ignoreTooFar", "true"); 310 } 311 } 312 boolean first = true; 313 for (Enumeration e2=lecture.timeLocations().elements();e2.hasMoreElements();) { 314 TimeLocation tl = (TimeLocation)e2.nextElement(); 315 Element timeLocationEl = (Element)classEl.addElement("time"); 316 timeLocationEl.addAttribute("days", sDF[7].format(Long.parseLong(Integer.toBinaryString(tl.getDayCode())))); 317 timeLocationEl.addAttribute("start", String.valueOf(tl.getStartSlot())); 318 timeLocationEl.addAttribute("length", String.valueOf(tl.getLength())); 319 if (iShowNames) { 320 timeLocationEl.addAttribute("breakTime", String.valueOf(tl.getBreakTime())); 321 timeLocationEl.addAttribute("pref", String.valueOf((int)tl.getPreference())); 322 timeLocationEl.addAttribute("npref", String.valueOf(tl.getNormalizedPreference())); 323 } else { 324 timeLocationEl.addAttribute("pref", String.valueOf(tl.getNormalizedPreference())); 325 } 326 if (!iConvertIds && tl.getTimePatternId()!=null) 327 timeLocationEl.addAttribute("pattern", getId("pat",tl.getTimePatternId())); 328 if (first) { 329 if (!iConvertIds && tl.getDatePatternId()!=null) 330 classEl.addAttribute("datePattern", getId("dpat",String.valueOf(tl.getDatePatternId()))); 331 if (iShowNames) 332 classEl.addAttribute("datePatternName", tl.getDatePatternName()); 333 classEl.addAttribute("dates", bitset2string(tl.getWeekCode())); 334 first = false; 335 } 336 if ((lecture.isCommitted() || iSaveCurrent) && placement!=null && placement.getTimeLocation().equals(tl)) timeLocationEl.addAttribute("solution", "true"); 337 if (iSaveInitial && initialPlacement!=null && initialPlacement.getTimeLocation().equals(tl)) timeLocationEl.addAttribute("initial", "true"); 338 if (iSaveBest && bestPlacement!=null && !bestPlacement.equals(placement) && bestPlacement.getTimeLocation().equals(tl)) timeLocationEl.addAttribute("best", "true"); 339 } 340 } 341 342 for (Enumeration e=getModel().getInstructorConstraints().elements();e.hasMoreElements();) { 343 InstructorConstraint ic = (InstructorConstraint)e.nextElement(); 344 if (iShowNames || ic.isIgnoreDistances()) { 345 Element instrEl = instructorsEl.addElement("instructor").addAttribute("id", getId("inst", ic.getResourceId())); 346 if (iShowNames) { 347 if (ic.getPuid()!=null && ic.getPuid().length()>0) 348 instrEl.addAttribute("puid",ic.getPuid()); 349 instrEl.addAttribute("name",ic.getName()); 350 if (ic.getType()!=null && iShowNames) 351 instrEl.addAttribute("type",ic.getType().toString()); 352 } 353 if (ic.isIgnoreDistances()) { 354 instrEl.addAttribute("ignDist","true"); 355 } 356 } 357 if (ic.getAvailableArray()!=null) { 358 HashSet done = new HashSet(); 359 for (int i=0;i<ic.getAvailableArray().length;i++) { 360 if (ic.getAvailableArray()[i]!=null) { 361 for (Enumeration f=ic.getAvailableArray()[i].elements();f.hasMoreElements();) { 362 Placement placement = (Placement)f.nextElement(); 363 Lecture lecture = (Lecture)placement.variable(); 364 if (done.add(lecture.getClassId())) { 365 Element classEl = (Element)classElements.get(lecture.getClassId()); 366 classEl.addElement("instructor").addAttribute("id", getId("inst", ic.getResourceId())).addAttribute("solution","true"); 367 } 368 } 369 } 370 } 371 } 372 } 373 if (instructorsEl.elements().isEmpty()) 374 root.remove(instructorsEl); 375 376 377 Element grConstraintsEl = root.addElement("groupConstraints"); 378 Hashtable grConv = new Hashtable(); 379 for (Enumeration e1=getModel().getGroupConstraints().elements();e1.hasMoreElements();) { 380 net.sf.cpsolver.coursett.constraint.GroupConstraint gc = (net.sf.cpsolver.coursett.constraint.GroupConstraint)e1.nextElement(); 381 Element grEl = grConstraintsEl.addElement("constraint").addAttribute("id", getId("gr", String.valueOf(gc.getId()))); 382 grEl.addAttribute("type", gc.getType()); 383 grEl.addAttribute("pref", gc.getPrologPreference()); 384 for (Enumeration e2=gc.variables().elements(); e2.hasMoreElements();) { 385 Lecture l = (Lecture)e2.nextElement(); 386 grEl.addElement("class").addAttribute("id",getId("class", l.getClassId())); 387 } 388 } 389 for (Enumeration e1=getModel().getSpreadConstraints().elements();e1.hasMoreElements();) { 390 SpreadConstraint spread = (SpreadConstraint)e1.nextElement(); 391 Element grEl = grConstraintsEl.addElement("constraint").addAttribute("id", getId("gr", String.valueOf(spread.getId()))); 392 grEl.addAttribute("type", "SPREAD"); 393 grEl.addAttribute("pref", Constants.sPreferenceRequired); 394 if (iShowNames) 395 grEl.addAttribute("name", spread.getName()); 396 for (Enumeration e2=spread.variables().elements(); e2.hasMoreElements();) { 397 Lecture l = (Lecture)e2.nextElement(); 398 grEl.addElement("class").addAttribute("id",getId("class", l.getClassId())); 399 } 400 } 401 for (Enumeration e1=getModel().constraints().elements();e1.hasMoreElements();) { 402 Constraint c = (Constraint)e1.nextElement(); 403 if (c instanceof MinimizeNumberOfUsedRoomsConstraint) { 404 Element grEl = grConstraintsEl.addElement("constraint").addAttribute("id", getId("gr", String.valueOf(c.getId()))); 405 grEl.addAttribute("type", "MIN_ROOM_USE"); 406 grEl.addAttribute("pref", Constants.sPreferenceRequired); 407 for (Enumeration e2=c.variables().elements(); e2.hasMoreElements();) { 408 Lecture l = (Lecture)e2.nextElement(); 409 grEl.addElement("class").addAttribute("id",getId("class", l.getClassId())); 410 } 411 } 412 if (c instanceof MinimizeNumberOfUsedGroupsOfTime) { 413 Element grEl = grConstraintsEl.addElement("constraint").addAttribute("id", getId("gr", String.valueOf(c.getId()))); 414 grEl.addAttribute("type", ((MinimizeNumberOfUsedGroupsOfTime)c).getConstraintName()); 415 grEl.addAttribute("pref", Constants.sPreferenceRequired); 416 for (Enumeration e2=c.variables().elements(); e2.hasMoreElements();) { 417 Lecture l = (Lecture)e2.nextElement(); 418 grEl.addElement("class").addAttribute("id",getId("class", l.getClassId())); 419 } 420 } 421 } 422 for (Enumeration e1=getModel().getClassLimitConstraints().elements();e1.hasMoreElements();) { 423 ClassLimitConstraint clc = (ClassLimitConstraint)e1.nextElement(); 424 Element grEl = grConstraintsEl.addElement("constraint").addAttribute("id", getId("gr", String.valueOf(clc.getId()))); 425 grEl.addAttribute("type", "CLASS_LIMIT"); 426 grEl.addAttribute("pref", Constants.sPreferenceRequired); 427 if (clc.getParentLecture()!=null) { 428 grEl.addElement("parentClass").addAttribute("id",getId("class", clc.getParentLecture().getClassId())); 429 } else 430 grEl.addAttribute("courseLimit",String.valueOf(clc.classLimit()-clc.getClassLimitDelta())); 431 if (clc.getClassLimitDelta()!=0) 432 grEl.addAttribute("delta",String.valueOf(clc.getClassLimitDelta())); 433 if (iShowNames) 434 grEl.addAttribute("name", clc.getName()); 435 for (Enumeration e2=clc.variables().elements(); e2.hasMoreElements();) { 436 Lecture l = (Lecture)e2.nextElement(); 437 grEl.addElement("class").addAttribute("id",getId("class", l.getClassId())); 438 } 439 } 440 441 Hashtable students = new Hashtable(); 442 for (Enumeration e1=getModel().variables().elements();e1.hasMoreElements();) { 443 Lecture lecture = (Lecture)e1.nextElement(); 444 for (Iterator i2=lecture.students().iterator();i2.hasNext();) { 445 Student student = (Student)i2.next(); 446 Vector enrls = (Vector)students.get(student); 447 if (enrls==null) { 448 enrls = new Vector(); 449 students.put(student, enrls); 450 } 451 enrls.add(getId("class", lecture.getClassId())); 452 } 453 } 454 455 Element studentsEl = root.addElement("students"); 456 Hashtable studentConv = new Hashtable(); 457 for (Enumeration e1=ToolBox.sortEnumeration(students.keys());e1.hasMoreElements();) { 458 Student student = (Student)e1.nextElement(); 459 Element stEl = studentsEl.addElement("student").addAttribute("id", getId("student", student.getId())); 460 for (Iterator i=student.getOfferingsMap().entrySet().iterator();i.hasNext();) { 461 Map.Entry entry = (Map.Entry)i.next(); 462 Long offeringId = (Long)entry.getKey(); 463 Double weight = (Double)entry.getValue(); 464 Element offEl = stEl.addElement("offering").addAttribute("id", getId("offering", offeringId.toString())); 465 if (weight.doubleValue()!=1.0) 466 offEl.addAttribute("weight", sStudentWeightFormat.format(weight)); 467 } 468 if (iExportStudentSectioning || getModel().unassignedVariables().isEmpty() || student.getOfferingsMap().isEmpty()) { 469 Vector lectures = (Vector)students.get(student); 470 Collections.sort(lectures); 471 for (Enumeration e2=lectures.elements();e2.hasMoreElements();) { 472 stEl.addElement("class").addAttribute("id", (String)e2.nextElement()); 473 } 474 } 475 Hashtable canNotEnroll = student.canNotEnrollSections(); 476 if (canNotEnroll!=null) { 477 for (Enumeration e2=canNotEnroll.elements();e2.hasMoreElements();) { 478 Set canNotEnrollLects = (Set)e2.nextElement(); 479 for (Iterator i3=canNotEnrollLects.iterator();i3.hasNext();) { 480 stEl.addElement("prohibited-class").addAttribute("id", getId("class",((Lecture)i3.next()).getClassId())); 481 } 482 } 483 } 484 485 if (student.getCommitedPlacements()!=null) { 486 for (Iterator i2=student.getCommitedPlacements().iterator();i2.hasNext();) { 487 Placement placement = (Placement)i2.next(); 488 Lecture lecture = (Lecture)placement.variable(); 489 stEl.addElement("class").addAttribute("id",getId("class", lecture.getClassId())); 490 } 491 } 492 } 493 494 if (getModel().getProperties().getPropertyInt("MPP.GenTimePert", 0)>0) { 495 Element perturbationsEl = root.addElement("perturbations"); 496 int nrChanges = getModel().getProperties().getPropertyInt("MPP.GenTimePert", 0); 497 Vector lectures = new Vector(); 498 while (lectures.size()<nrChanges) { 499 Lecture lecture = (Lecture)ToolBox.random(getModel().assignedVariables()); 500 if (lecture.isCommitted() || lecture.timeLocations().size()<=1 || lectures.contains(lecture)) continue; 501 Placement placement = (Placement)lecture.getAssignment(); 502 TimeLocation tl = (TimeLocation)placement.getTimeLocation(); 503 perturbationsEl.addElement("class") 504 .addAttribute("id", getId("class", lecture.getClassId())) 505 .addAttribute("days", sDF[7].format(Long.parseLong(Integer.toBinaryString(tl.getDayCode())))) 506 .addAttribute("start", String.valueOf(tl.getStartSlot())) 507 .addAttribute("length", String.valueOf(tl.getLength())); 508 lectures.add(lecture); 509 } 510 } 511 512 for (Iterator i=depts.entrySet().iterator();i.hasNext();) { 513 Map.Entry entry = (Map.Entry)i.next(); 514 Object id = entry.getKey(); 515 String name = (String)entry.getValue(); 516 if (iShowNames) { 517 departmentsEl.addElement("department").addAttribute("id",getId("dept",id.toString())).addAttribute("name",name); 518 } 519 } 520 if (departmentsEl.elements().isEmpty()) 521 root.remove(departmentsEl); 522 523 if (iShowNames) { 524 Progress.getInstance(getModel()).save(root); 525 526 try { 527 getSolver().getClass().getMethod("save", new Class[] {Element.class}).invoke(getSolver(), new Object[] {root}); 528 } catch (Exception e) {} 529 } 530 531 FileOutputStream fos = null; 532 try { 533 fos = new FileOutputStream(outFile); 534 (new XMLWriter(fos,OutputFormat.createPrettyPrint())).write(document); 535 fos.flush();fos.close();fos=null; 536 } finally { 537 try { 538 if (fos!=null) fos.close(); 539 } catch (IOException e) {} 540 } 541 542 if (iConvertIds) iIdConvertor.save(); 543 } 544 }