001 package ttsolver;
002
003 import ifs.extension.*;
004 import ifs.model.*;
005 import ifs.solution.*;
006 import ifs.solver.*;
007 import ifs.util.*;
008
009 import java.io.*;
010 import java.util.*;
011 import org.apache.log4j.helpers.FileWatchdog;
012
013 import ttsolver.constraint.*;
014 import ttsolver.model.*;
015 import ttsolver.heuristics.*;
016
017 /**
018 * A main class for running of the solver from command line.
019 * <br><br>
020 * Usage:<br>
021 * java -cp ifs.jar;ttsolver.jar;log4j.jar;dom4j.jar ttsolver.Test test.properties
022 *
023 * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
024 * @version 1.0
025 */
026
027 public class Test implements SolutionListener {
028 private static java.text.SimpleDateFormat sDateFormat = new java.text.SimpleDateFormat("dd-MMM-yy_HHmmss",java.util.Locale.US);
029 private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.000",new java.text.DecimalFormatSymbols(Locale.US));
030 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Test.class);
031
032 private PrintWriter iCSVFile = null;
033
034 private ConflictStatistics iStat = null;
035 private MacPropagation iProp = null;
036 private ViolatedInitials iViolatedInitials = null;
037 private int iLastNotified = -1;
038
039 public void init(Solver solver) {
040 for (Enumeration i=solver.getExtensions().elements();i.hasMoreElements();) {
041 Extension extension = (Extension)i.nextElement();
042 if (extension instanceof ConflictStatistics)
043 iStat = (ConflictStatistics) extension;
044 if (extension instanceof MacPropagation)
045 iProp = (MacPropagation)extension;
046 if (extension instanceof ViolatedInitials)
047 iViolatedInitials = (ViolatedInitials)extension;
048 }
049 solver.currentSolution().addSolutionListener(this);
050 }
051
052 private String getTimetableLoaderClass(DataProperties properties) {
053 String loader = properties.getProperty("TimetableLoader");
054 if (loader!=null) return loader;
055 if (properties.getPropertyInt("General.InputVersion",-1)>=0)
056 return "ttsolver.TimetableDatabaseLoader";
057 else
058 return "ttsolver.TimetablePrologLoader";
059 }
060
061 private String getTimetableSaverClass(DataProperties properties) {
062 String saver = properties.getProperty("TimetableSaver");
063 if (saver!=null) return saver;
064 if (properties.getPropertyInt("General.InputVersion",-1)>=0)
065 return "ttsolver.TimetableDatabaseSaver";
066 else
067 return "ttsolver.TimetablePrologSaver";
068 }
069
070 public Test(String[] args) {
071 try {
072 Progress.getInstance().addProgressListener(new ProgressWriter(System.out));
073 DataProperties properties = ToolBox.loadProperties(new java.io.File(args[0]));
074 properties.setProperty("General.Output", properties.getProperty("General.Output",".")+File.separator+(sDateFormat.format(new Date())));
075 if (args.length>1)
076 properties.setProperty("General.Output", args[1]+File.separator+(sDateFormat.format(new Date())));
077 System.out.println("Output folder: "+properties.getProperty("General.Output"));
078 ToolBox.configureLogging(properties.getProperty("General.Output"),null);
079
080 edu.purdue.smas.timetable.data.Preferences.loadStatic();
081 edu.purdue.smas.timetable.data.GroupConstraintTypes.loadStatic();
082
083 File outDir = new File(properties.getProperty("General.Output","."));
084 outDir.mkdirs();
085
086 Solver solver = new Solver(properties);
087 TimetableModel model = new TimetableModel(properties);
088
089 TimetableLoader loader = (TimetableLoader)Class.forName(getTimetableLoaderClass(properties)).getConstructor(new Class[] {TimetableModel.class}).newInstance(new Object[] {model});
090 PrintWriter out = new PrintWriter(new FileWriter(new File(outDir, "load.txt")));
091 loader.load(out);
092 out.flush(); out.close();
093
094 printSomeStuff(model);
095
096 solver.setInitalSolution(model);
097 init(solver);
098
099 iCSVFile = new PrintWriter(new FileWriter(outDir.toString()+File.separator+"stat.csv"));
100 String colSeparator = ";";
101 iCSVFile.println(
102 "Assigned"+colSeparator+
103 "Assigned[%]"+colSeparator+
104 "Time[min]"+colSeparator+
105 "Iter"+colSeparator+
106 "IterYield[%]"+colSeparator+
107 "Speed[it/s]"+colSeparator+
108 "AddedPert"+colSeparator+
109 "AddedPert[%]"+colSeparator+
110 "HardStudentConf"+colSeparator+
111 "StudentConf"+colSeparator+
112 "DistStudentConf"+colSeparator+
113 "TimePref"+colSeparator+
114 "RoomPref"+colSeparator+
115 "DistInstrPref"+colSeparator+
116 "GrConstPref"+colSeparator+
117 "UselessSlots"+colSeparator+
118 "TooBigRooms"+
119 (iProp!=null?colSeparator+"GoodVars"+colSeparator+
120 "GoodVars[%]"+colSeparator+
121 "GoodVals"+colSeparator+
122 "GoodVals[%]":"")
123 );
124 iCSVFile.flush();
125
126 solver.start();
127 solver.getSolverThread().join();
128
129 long lastIt = solver.lastSolution().getIteration();
130 double lastTime = solver.lastSolution().getTime();
131
132 if (solver.lastSolution().getBestInfo()!=null) {
133 Solution bestSolution = solver.lastSolution();//.cloneBest();
134 sLogger.info("Last solution: "+ToolBox.dict2string(bestSolution.getInfo(),1));
135 bestSolution.restoreBest();
136 sLogger.info("Best solution: "+ToolBox.dict2string(bestSolution.getInfo(),1));
137 ((TimetableModel)bestSolution.getModel()).switchStudents();
138 sLogger.info("Best solution: "+ToolBox.dict2string(bestSolution.getInfo(),1));
139 saveOutputCSV(bestSolution,new File(outDir,"output.csv"));
140
141 TimetableSaver saver = (TimetableSaver)Class.forName(getTimetableSaverClass(properties)).getConstructor(new Class[] {Solution.class}).newInstance(new Object[] {bestSolution});
142 out = new PrintWriter(new FileWriter(new File(outDir, "save.txt")));
143 saver.save(out);
144 out.flush(); out.close();
145 } else sLogger.info("Last solution:"+ToolBox.dict2string(solver.lastSolution().getInfo(),1));
146
147 iCSVFile.close();
148
149 sLogger.info("Total number of done iteration steps:"+lastIt);
150 sLogger.info("Achieved speed: "+sDoubleFormat.format(lastIt/lastTime)+" iterations/second");
151 } catch (Throwable t) {
152 sLogger.error("Test failed.",t);
153 }
154 }
155
156 public static void main(String[] args) {
157 new Test(args);
158 }
159
160 public void bestCleared(Solution solution) {
161 }
162
163 public void bestRestored(Solution solution) {
164 }
165
166 public void bestSaved(Solution solution) {
167 notify(solution);
168 }
169
170 public void getInfo(Solution solution, java.util.Dictionary info) {
171 }
172
173 public void solutionUpdated(Solution solution) {
174 }
175
176 public void notify(Solution solution) {
177 String colSeparator = ";";
178 if (!solution.getModel().unassignedVariables().isEmpty() && iLastNotified==solution.getModel().assignedVariables().size()) return;
179 iLastNotified=solution.getModel().assignedVariables().size();
180 if (iCSVFile!=null) {
181 TimetableModel model = (TimetableModel) solution.getModel();
182 iCSVFile.print(model.variables().size()-model.unassignedVariables().size());
183 iCSVFile.print(colSeparator);
184 iCSVFile.print(sDoubleFormat.format(100.0*(model.variables().size()-model.unassignedVariables().size())/model.variables().size()));
185 iCSVFile.print(colSeparator);
186 iCSVFile.print(sDoubleFormat.format(((double)solution.getTime())/60.0));
187 iCSVFile.print(colSeparator);
188 iCSVFile.print(solution.getIteration());
189 iCSVFile.print(colSeparator);
190 iCSVFile.print(sDoubleFormat.format(100.0*(model.variables().size()-model.unassignedVariables().size())/solution.getIteration()));
191 iCSVFile.print(colSeparator);
192 iCSVFile.print(sDoubleFormat.format(((double)solution.getIteration())/(double)solution.getTime()));
193 iCSVFile.print(colSeparator);
194 iCSVFile.print(model.perturbVariables().size());
195 iCSVFile.print(colSeparator);
196 iCSVFile.print(sDoubleFormat.format(100.0*model.perturbVariables().size()/model.variables().size()));
197
198 long studentConflicts = 0;
199 long hardStudentConflicts = 0;
200 long uselessSlots = 0;
201 for (Enumeration it1=((TimetableModel)solution.getModel()).getRoomConstraints().elements();it1.hasMoreElements();) {
202 RoomConstraint constraint = (RoomConstraint)it1.nextElement();
203 uselessSlots+=constraint.countUselessSlots();
204 }
205 for (Enumeration it1=((TimetableModel)solution.getModel()).getJenrlConstraints().elements();it1.hasMoreElements();) {
206 JenrlConstraint jenrl = (JenrlConstraint) it1.nextElement();
207 if (jenrl.isInConflict()) {
208 studentConflicts+=jenrl.getJenrl();
209 Lecture l1 = (Lecture)jenrl.first();
210 Lecture l2 = (Lecture)jenrl.second();
211 if (l1.sameLectures()!=null && l1.sameLectures().size()==1 &&
212 l2.sameLectures()!=null && l2.sameLectures().size()==1)
213 hardStudentConflicts+=jenrl.getJenrl();
214 }
215 }
216 iCSVFile.print(colSeparator);
217 iCSVFile.print(hardStudentConflicts);
218 iCSVFile.print(colSeparator);
219 iCSVFile.print(studentConflicts);
220 iCSVFile.print(colSeparator);
221 iCSVFile.print(((TimetableModel)solution.getModel()).getStudentDistanceConflicts());
222 iCSVFile.print(colSeparator);
223 iCSVFile.print(sDoubleFormat.format(((TimetableModel)solution.getModel()).getGlobalTimePreference()));
224 iCSVFile.print(colSeparator);
225 iCSVFile.print(((TimetableModel)solution.getModel()).getGlobalRoomPreference());
226 iCSVFile.print(colSeparator);
227 iCSVFile.print(((TimetableModel)solution.getModel()).getInstructorDistancePreference());
228 iCSVFile.print(colSeparator);
229 iCSVFile.print(((TimetableModel)solution.getModel()).getGlobalGroupConstraintPreference());
230 iCSVFile.print(colSeparator);
231 iCSVFile.print(uselessSlots);
232 iCSVFile.print(colSeparator);
233 iCSVFile.print(((TimetableModel)solution.getModel()).countTooBigRooms());
234 if (iProp!=null) {
235 if (solution.getModel().unassignedVariables().size()>0) {
236 int goodVariables=0;
237 long goodValues=0;
238 long allValues=0;
239 for (Enumeration i=solution.getModel().unassignedVariables().elements();i.hasMoreElements();) {
240 Lecture variable = (Lecture)i.nextElement();
241 goodValues += iProp.goodValues(variable).size();
242 allValues += variable.values().size();
243 if (!iProp.goodValues(variable).isEmpty()) goodVariables++;
244 }
245 iCSVFile.print(colSeparator);
246 iCSVFile.print(goodVariables);
247 iCSVFile.print(colSeparator);
248 iCSVFile.print(sDoubleFormat.format(100.0*goodVariables/solution.getModel().unassignedVariables().size()));
249 iCSVFile.print(colSeparator);
250 iCSVFile.print(goodValues);
251 iCSVFile.print(colSeparator);
252 iCSVFile.print(sDoubleFormat.format(100.0*goodValues/allValues));
253 } else {
254 iCSVFile.print(colSeparator);
255 iCSVFile.print(colSeparator);
256 iCSVFile.print(colSeparator);
257 iCSVFile.print(colSeparator);
258 }
259 }
260 iCSVFile.println();
261 iCSVFile.flush();
262 }
263 }
264
265 private void printSomeStuff(TimetableModel model) {
266 long nrValues = 0;
267 double totalMaxNormTimePref = 0.0;
268 double totalMinNormTimePref = 0.0;
269 int totalMaxTimePref = 0;
270 int totalMinTimePref = 0;
271 int totalMaxRoomPref = 0;
272 int totalMinRoomPref = 0;
273 long nrStudentEnrls = 0;
274 long nrInevitableStudentConflicts = 0;
275 long nrJenrls = 0;
276 int nrHalfHours = 0;
277 int nrMeetings = 0;
278 int nrPairs = 0;
279 int nrPairsNoSameClass = 0;
280 int nrStudentSharingPairs = 0;
281 int nrRoomSharingPairs = 0;
282 int nrInstructorSharingPairs = 0;
283 int nrSingleValueVariables = 0;
284 for (Enumeration e1=model.variables().elements();e1.hasMoreElements();) {
285 Lecture lect = (Lecture)e1.nextElement();
286 double maxNormTimePref = Double.MIN_VALUE;
287 double minNormTimePref = Double.MAX_VALUE;
288 int maxTimePref = Integer.MIN_VALUE;
289 int minTimePref = Integer.MAX_VALUE;
290 int maxRoomPref = Integer.MIN_VALUE;
291 int minRoomPref = Integer.MAX_VALUE;
292 nrStudentEnrls += (lect.allStudents()==null?0:lect.allStudents().size());
293 nrValues += lect.values().size();
294 for (Enumeration e2=lect.values().elements();e2.hasMoreElements();) {
295 Placement placement = (Placement)e2.nextElement();
296 maxNormTimePref = Math.max(maxNormTimePref,placement.getTimeLocation().getNormalizedPreference());
297 minNormTimePref = Math.min(minNormTimePref,placement.getTimeLocation().getNormalizedPreference());
298 maxTimePref = Math.max(maxTimePref,placement.getTimeLocation().getPreference());
299 minTimePref = Math.min(maxTimePref,placement.getTimeLocation().getPreference());
300 maxRoomPref = Math.max(maxRoomPref,placement.getRoomLocation().getPreference());
301 minRoomPref = Math.min(minRoomPref,placement.getRoomLocation().getPreference());
302 }
303 if (!lect.values().isEmpty()) {
304 Placement p = (Placement)lect.values().firstElement();
305 nrMeetings += p.getTimeLocation().getNrMeetings();
306 nrHalfHours += p.getTimeLocation().getNrMeetings() * p.getTimeLocation().getNrHalfHoursPerMeeting();
307 totalMaxNormTimePref += maxNormTimePref;
308 totalMinNormTimePref += minNormTimePref;
309 totalMaxTimePref += maxTimePref;
310 totalMinTimePref += minTimePref;
311 totalMaxRoomPref += maxRoomPref;
312 totalMinRoomPref += minRoomPref;
313 }
314 if (lect.values().size()==1) {
315 nrSingleValueVariables++;
316 Placement p1 = (Placement)lect.values().firstElement();
317 for (Enumeration e2=lect.jenrlConstraints().elements();e2.hasMoreElements();) {
318 JenrlConstraint jenrl = (JenrlConstraint)e2.nextElement();
319 Lecture another = (Lecture)jenrl.another(lect);
320 if (another.values().size()==1) {
321 Placement p2 = (Placement)another.values().firstElement();
322 if (JenrlConstraint.isInConflict(p1,p2)) {
323 nrInevitableStudentConflicts += jenrl.getJenrl();
324 }
325 }
326 }
327 }
328 }
329 for (Enumeration e=model.getJenrlConstraints().elements();e.hasMoreElements();) {
330 JenrlConstraint jenrl = (JenrlConstraint)e.nextElement();
331 nrJenrls += jenrl.getJenrl();
332 }
333 sLogger.debug("Total number of variables: "+model.variables().size());
334 sLogger.debug("Total number of variables with only one value: "+nrSingleValueVariables);
335 sLogger.debug("Total number of values: "+nrValues);
336 sLogger.debug("Total maximum normalized time preference: "+sDoubleFormat.format(totalMaxNormTimePref));
337 sLogger.debug("Total minimum normalized time preference: "+sDoubleFormat.format(totalMinNormTimePref));
338 sLogger.debug("Total maximum time preferences: "+totalMaxTimePref);
339 sLogger.debug("Total minimum time preferences: "+totalMinTimePref);
340 sLogger.debug("Total maximum room preferences: "+totalMaxRoomPref);
341 sLogger.debug("Total minimum room preferences: "+totalMinRoomPref);
342 sLogger.debug("Total amount of student enrollments: "+nrStudentEnrls);
343 sLogger.debug("Total amount of joined enrollments: "+nrJenrls);
344 sLogger.debug("Total amount of inevitable student conflicts: "+nrInevitableStudentConflicts);
345 sLogger.debug("Total number of meetings: "+nrMeetings);
346 sLogger.debug("Total number of half-hours: "+nrHalfHours);
347 sLogger.debug("Total number of rooms: "+model.getRoomConstraints().size());
348 }
349
350 private void saveOutputCSV(Solution s,File f) {
351 try {
352 PrintWriter w = new PrintWriter(new FileWriter(f));
353 TimetableModel m = (TimetableModel)s.getModel();
354 w.println("Assigned variables;"+m.assignedVariables().size());
355 if (m.getProperties().getPropertyBoolean("General.MPP",false))
356 w.println("Add. perturbancies;"+s.getPerturbationsCounter().getPerturbationPenalty(s));
357 w.println("Time [sec];"+sDoubleFormat.format(s.getBestTime()));
358 w.println("Hard student conflicts;"+m.getHardStudentConflicts());
359 if (m.getProperties().getPropertyBoolean("General.UseDistanceConstraints", true))
360 w.println("Distance student conf.;"+m.getStudentDistanceConflicts());
361 w.println("Student conflicts;"+m.getViolatedStudentConflicts());
362 w.println("Time preferences;"+sDoubleFormat.format(m.getGlobalTimePreference()));
363 w.println("Room preferences;"+m.getGlobalRoomPreference());
364 w.println("Useless half-hours;"+m.getUselessSlots());
365 w.println("Too big room;"+m.countTooBigRooms());
366 if (m.getProperties().getPropertyBoolean("General.UseDistanceConstraints", true))
367 w.println("Distance instructor pref.;"+m.getInstructorDistancePreference());
368 if (m.getProperties().getPropertyBoolean("General.UseDepartmentSpreadConstraints",true)) {
369 w.println("Dept. spread penalty;"+sDoubleFormat.format(m.getDepartmentSpreadPenalty()));
370 }
371 if (m.getProperties().getPropertyBoolean("General.MPP",false)) {
372 Hashtable mppInfo = ((UniversalPerturbationsCounter)s.getPerturbationsCounter()).getCompactInfo(s, false, false);
373 for (Enumeration e=ToolBox.sortEnumeration(mppInfo.keys());e.hasMoreElements();) {
374 String key = (String)e.nextElement();
375 w.println(key+";"+mppInfo.get(key));
376 }
377 }
378 w.flush();w.close();
379 } catch (java.io.IOException io) {
380 sLogger.error(io.getMessage(),io);
381 }
382 }
383 }