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    }