    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    }