001package org.cpsolver.ifs.example.tt;
002
003import java.io.File;
004import java.io.FileInputStream;
005import java.io.FileOutputStream;
006import java.io.FileWriter;
007import java.io.PrintWriter;
008import java.util.ArrayList;
009import java.util.Date;
010import java.util.List;
011import java.util.Locale;
012import java.util.StringTokenizer;
013
014import org.cpsolver.ifs.assignment.Assignment;
015import org.cpsolver.ifs.assignment.DefaultSingleAssignment;
016import org.cpsolver.ifs.solution.Solution;
017import org.cpsolver.ifs.solver.Solver;
018import org.cpsolver.ifs.util.DataProperties;
019import org.cpsolver.ifs.util.Progress;
020import org.cpsolver.ifs.util.ProgressWriter;
021import org.cpsolver.ifs.util.ToolBox;
022
023
024/**
025 * Test
026 * 
027 * @version IFS 1.3 (Iterative Forward Search)<br>
028 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
029 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
030 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
031 * <br>
032 *          This library is free software; you can redistribute it and/or modify
033 *          it under the terms of the GNU Lesser General Public License as
034 *          published by the Free Software Foundation; either version 3 of the
035 *          License, or (at your option) any later version. <br>
036 * <br>
037 *          This library is distributed in the hope that it will be useful, but
038 *          WITHOUT ANY WARRANTY; without even the implied warranty of
039 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
040 *          Lesser General Public License for more details. <br>
041 * <br>
042 *          You should have received a copy of the GNU Lesser General Public
043 *          License along with this library; if not see
044 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
045 */
046public class Test {
047    private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.000",
048            new java.text.DecimalFormatSymbols(Locale.US));
049    private static java.text.SimpleDateFormat sDateFormat = new java.text.SimpleDateFormat("dd-MMM-yy_HHmmss",
050            java.util.Locale.US);
051    private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Test.class);
052
053    public static void test2(DataProperties properties) throws Exception {
054        int nrTests = properties.getPropertyInt("Test.NrTests", 1);
055        PrintWriter logStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "output.csv"));
056        PrintWriter logAvgStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output")
057                + File.separator + "avg_stat.csv"));
058        logStat.println("fillFact;nrResources;testNr;time[s];iters;speed[it/s];assigned;assigned[%];value;totalValue");
059        logAvgStat
060                .println("fillFact;nrResources;time[s];RMStime[s];iters;RMSiters;speed[it/s];assigned;RMSassigned;assigned[%];value;RMSvalue");
061
062        int nrResourcesMin = properties.getPropertyInt("Test.NrResourcesMin", -1);
063        int nrResourcesMax = properties.getPropertyInt("Test.NrResourcesMax", -1);
064        int nrResourcesStep = properties.getPropertyInt("Test.NrResourcesStep", 1);
065        double fillFactorMin = properties.getPropertyDouble("Test.FillFactorMin", -1.0);
066        double fillFactorMax = properties.getPropertyDouble("Test.FillFactorMax", -1.0);
067        double fillFactorStep = properties.getPropertyDouble("Test.FillFactorStep", 0.01);
068
069        boolean saveInit = properties.getPropertyBoolean("General.SaveInitialXML", true);
070        boolean saveSol = properties.getPropertyBoolean("General.SaveSolutionXML", true);
071
072        for (int nrResources = nrResourcesMin; nrResources <= nrResourcesMax; nrResources += nrResourcesStep) {
073            for (double fillFactor = fillFactorMin; fillFactor <= fillFactorMax; fillFactor += fillFactorStep) {
074                double sumTime = 0;
075                double sumTime2 = 0;
076                int sumIters = 0;
077                int sumIters2 = 0;
078                int sumAssign = 0;
079                int sumAssign2 = 0;
080                int sumVal = 0;
081                int sumVal2 = 0;
082                int sumVar = 0;
083                for (int test = 1; test <= nrTests; test++) {
084                    if (nrResources >= 0) {
085                        properties.setProperty("Generator.NrRooms", String.valueOf(nrResources));
086                        properties.setProperty("Generator.NrClasses", String.valueOf(nrResources));
087                        properties.setProperty("Generator.NrInstructors", String.valueOf(nrResources));
088                    }
089                    if (fillFactor >= 0.0) {
090                        properties.setProperty("Generator.FillFactor", String.valueOf(fillFactor));
091                    }
092                    Assignment<Activity, Location> assignment = new DefaultSingleAssignment<Activity, Location>();
093                    TimetableModel m = TimetableModel.generate(properties, assignment);
094
095                    Solver<Activity, Location> s = new Solver<Activity, Location>(properties);
096                    if (saveInit)
097                        m.saveAsXML(properties, true, null, assignment, new File(properties.getProperty("General.Output")
098                                + File.separator
099                                + "SimpleTT("
100                                + (nrResources < 0 ? properties.getPropertyInt("Generator.NrRooms", 20) : nrResources)
101                                + ","
102                                + ((int) (100.0 * (fillFactor < 0.0 ? properties.getPropertyDouble(
103                                        "Generator.FillFactor", 0.8) : fillFactor) + 0.5)) + ","
104                                + properties.getPropertyInt("Generator.NrDependencies", 50) + ")_" + test + ".xml"));
105                    s.setInitalSolution(new Solution<Activity, Location>(m, assignment));
106                    s.currentSolution().clearBest();
107                    s.start();
108                    try {
109                        s.getSolverThread().join();
110                    } catch (NullPointerException npe) {
111                    }
112
113                    if (s.lastSolution().getBestInfo() == null)
114                        sLogger.error("No solution found :-(");
115                    sLogger.debug("Last solution:" + s.lastSolution().getInfo());
116                    Solution<Activity, Location> best = s.lastSolution();
117                    sLogger.debug("Best solution:" + s.lastSolution().getBestInfo());
118                    best.restoreBest();
119                    int val = 0;
120                    for (Activity var : ((TimetableModel) best.getModel()).assignedVariables(best.getAssignment()))
121                        val += (int) var.getAssignment(best.getAssignment()).toDouble();
122                    if (saveSol)
123                        m.saveAsXML(properties, true, best, best.getAssignment(), new File(properties.getProperty("General.Output") +
124                                File.separator + "SimpleTT(" +
125                                (nrResources < 0 ? properties.getPropertyInt("Generator.NrRooms", 20) : nrResources) + "," +
126                                ((int) (100.0 * (fillFactor < 0.0 ? properties.getPropertyDouble("Generator.FillFactor", 0.8) : fillFactor) + 0.5)) + "," +
127                                properties.getPropertyInt("Generator.NrDependencies", 50) + ")_" + test + "_sol.xml"));
128                    sLogger.debug("Last solution:" + best.getInfo());
129                    logStat.println(sDoubleFormat.format(properties.getPropertyDouble("Generator.FillFactor", 0.0))
130                            + ";"
131                            + sDoubleFormat.format(properties.getPropertyInt("Generator.NrRooms", 0))
132                            + ";"
133                            + test
134                            + ";"
135                            + sDoubleFormat.format(best.getTime())
136                            + ";"
137                            + best.getIteration()
138                            + ";"
139                            + sDoubleFormat.format((best.getIteration()) / best.getTime())
140                            + ";"
141                            + best.getModel().assignedVariables(best.getAssignment()).size()
142                            + ";"
143                            + sDoubleFormat.format(100.0 * best.getModel().assignedVariables(best.getAssignment()).size()
144                                    / best.getModel().variables().size()) + ";" + val);
145                    sLogger.debug("    time:         " + sDoubleFormat.format(best.getTime()) + " s");
146                    sLogger.debug("    iteration:    " + best.getIteration());
147                    sLogger.debug("    speed:        " + sDoubleFormat.format((best.getIteration()) / best.getTime())
148                            + " it/s");
149                    sLogger.debug("    assigned:     "
150                            + best.getModel().assignedVariables(best.getAssignment()).size()
151                            + " ("
152                            + sDoubleFormat.format(100.0 * best.getModel().assignedVariables(best.getAssignment()).size()
153                                    / best.getModel().variables().size()) + "%)");
154                    sLogger.debug("    value:        " + val);
155                    sumTime += best.getTime();
156                    sumTime2 += best.getTime() * best.getTime();
157                    sumIters += best.getIteration();
158                    sumIters2 += best.getIteration() * best.getIteration();
159                    sumAssign += best.getModel().assignedVariables(best.getAssignment()).size();
160                    sumAssign2 += best.getModel().assignedVariables(best.getAssignment()).size()
161                            * best.getModel().assignedVariables(best.getAssignment()).size();
162                    sumVal += val;
163                    sumVal2 += val * val;
164                    sumVar += m.variables().size();
165                    logStat.flush();
166                }
167                logAvgStat.println(sDoubleFormat.format(properties.getPropertyDouble("Generator.FillFactor", 0.0))
168                        + ";" + sDoubleFormat.format(properties.getPropertyInt("Generator.NrRooms", 0)) + ";"
169                        + sDoubleFormat.format(sumTime / nrTests) + ";"
170                        + sDoubleFormat.format(ToolBox.rms(nrTests, sumTime, sumTime2)) + ";"
171                        + sDoubleFormat.format(((double) sumIters) / nrTests) + ";"
172                        + sDoubleFormat.format(ToolBox.rms(nrTests, sumIters, sumIters2)) + ";"
173                        + sDoubleFormat.format((sumIters) / sumTime) + ";"
174                        + sDoubleFormat.format(((double) sumAssign) / nrTests) + ";"
175                        + sDoubleFormat.format(ToolBox.rms(nrTests, sumAssign, sumAssign2)) + ";"
176                        + sDoubleFormat.format(100.0 * (sumAssign) / sumVar) + ";"
177                        + sDoubleFormat.format(((double) sumVal) / nrTests) + ";"
178                        + sDoubleFormat.format(ToolBox.rms(nrTests, sumVal, sumVal2)));
179                logAvgStat.flush();
180            }
181        }
182        logStat.close();
183        logAvgStat.close();
184    }
185
186    public static void test3(DataProperties properties, File xmlFile) throws Exception {
187        int nrTests = properties.getPropertyInt("Test.NrTests", 1);
188        PrintWriter logStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator
189                + "output.csv"));
190        logStat.println("fillFact;nrResources;testNr;time[s];iters;speed[it/s];assigned;assigned[%];value;totalValue");
191
192        boolean saveSol = properties.getPropertyBoolean("General.SaveSolutionXML", true);
193        boolean assign = properties.getPropertyBoolean("General.InitialAssignment", true);
194        int forcedPerturbances = properties.getPropertyInt("General.ForcedPerturbances", 0);
195
196        for (int test = 1; test <= nrTests; test++) {
197            Assignment<Activity, Location> assignment = new DefaultSingleAssignment<Activity, Location>();
198            TimetableModel m = TimetableModel.loadFromXML(xmlFile, assign ? assignment : null);
199
200            if (forcedPerturbances > 0) {
201                List<Activity> initialVariables = new ArrayList<Activity>();
202                for (Activity v : m.variables()) {
203                    if (v.getInitialAssignment() != null)
204                        initialVariables.add(v);
205                }
206                for (int i = 0; i < forcedPerturbances; i++) {
207                    if (initialVariables.isEmpty())
208                        break;
209                    Activity var = ToolBox.random(initialVariables);
210                    initialVariables.remove(var);
211                    var.removeInitialValue();
212                }
213            }
214
215            Solver<Activity, Location> s = new Solver<Activity, Location>(properties);
216            s.setInitalSolution(new Solution<Activity, Location>(m, assignment));
217            s.currentSolution().clearBest();
218            s.start();
219            try {
220                s.getSolverThread().join();
221            } catch (NullPointerException npe) {
222            }
223
224            if (s.lastSolution().getBestInfo() == null)
225                sLogger.error("No solution found :-(");
226            sLogger.debug("Last solution:" + s.lastSolution().getInfo());
227            Solution<Activity, Location> best = s.lastSolution();
228            sLogger.debug("Best solution:" + s.lastSolution().getBestInfo());
229            best.restoreBest();
230            int val = 0;
231            for (Location loc : best.getAssignment().assignedValues())
232                val += (int) loc.toDouble();
233            if (saveSol)
234                m.saveAsXML(properties, false, best, best.getAssignment(), new File(properties.getProperty("General.Output") + File.separator
235                        + "solution_" + test + ".xml"));
236            sLogger.debug("Last solution:" + best.getInfo());
237            logStat.println(sDoubleFormat.format(properties.getPropertyDouble("Generator.FillFactor", 0.0))
238                    + ";"
239                    + sDoubleFormat.format(properties.getPropertyInt("Generator.NrRooms", 0))
240                    + ";"
241                    + test
242                    + ";"
243                    + sDoubleFormat.format(best.getTime())
244                    + ";"
245                    + best.getIteration()
246                    + ";"
247                    + sDoubleFormat.format((best.getIteration()) / best.getTime())
248                    + ";"
249                    + best.getAssignment().nrAssignedVariables()
250                    + ";"
251                    + sDoubleFormat.format(100.0 * best.getAssignment().nrAssignedVariables()
252                            / best.getModel().variables().size()) + ";" + val);
253            sLogger.debug("    time:         " + sDoubleFormat.format(best.getTime()) + " s");
254            sLogger.debug("    iteration:    " + best.getIteration());
255            sLogger
256                    .debug("    speed:        " + sDoubleFormat.format((best.getIteration()) / best.getTime())
257                            + " it/s");
258            sLogger.debug("    assigned:     "
259                    + best.getAssignment().nrAssignedVariables()
260                    + " ("
261                    + sDoubleFormat.format(100.0 * best.getAssignment().nrAssignedVariables()
262                            / best.getModel().variables().size()) + "%)");
263            sLogger.debug("    value:        " + val);
264            logStat.flush();
265        }
266        logStat.close();
267    }
268
269    public static void test(File inputCfg, String name, String include, String regexp, String outDir) throws Exception {
270        if (regexp != null) {
271            String incFile;
272
273            if (regexp.indexOf(';') > 0) {
274                incFile = regexp.substring(0, regexp.indexOf(';'));
275                regexp = regexp.substring(regexp.indexOf(';') + 1);
276            } else {
277                incFile = regexp;
278                regexp = null;
279            }
280            if (incFile.startsWith("[") && incFile.endsWith("]")) {
281                test(inputCfg, name, include, regexp, outDir);
282                incFile = incFile.substring(1, incFile.length() - 1);
283            }
284            if (incFile.indexOf('{') >= 0 && incFile.indexOf('}') >= 0) {
285                String prefix = incFile.substring(0, incFile.indexOf('{'));
286                StringTokenizer middle = new StringTokenizer(incFile.substring(incFile.indexOf('{') + 1, incFile
287                        .indexOf('}')), "|");
288                String sufix = incFile.substring(incFile.indexOf('}') + 1);
289
290                while (middle.hasMoreTokens()) {
291                    String m = middle.nextToken();
292
293                    test(inputCfg, (name == null ? "" : name + "_") + m, (include == null ? "" : include + ";")
294                            + prefix + m + sufix, regexp, outDir);
295                }
296            } else {
297                test(inputCfg, name, (include == null ? "" : include + ";") + incFile, regexp, outDir);
298            }
299        } else {
300            DataProperties properties = ToolBox.loadProperties(inputCfg);
301            StringTokenizer inc = new StringTokenizer(include, ";");
302
303            while (inc.hasMoreTokens()) {
304                String aFile = inc.nextToken();
305
306                System.out.println("  Loading included file '" + aFile + "' ... ");
307                FileInputStream is = null;
308
309                if ((new File(aFile)).exists()) {
310                    is = new FileInputStream(aFile);
311                }
312                if ((new File(inputCfg.getParent() + File.separator + aFile)).exists()) {
313                    is = new FileInputStream(inputCfg.getParent() + File.separator + aFile);
314                }
315                if (is == null) {
316                    System.err.println("Unable to find include file '" + aFile + "'.");
317                }
318                properties.load(is);
319                is.close();
320            }
321            String outDirThisTest = (outDir == null ? properties.getProperty("General.Output", ".") : outDir)
322                    + File.separator + name + File.separator + sDateFormat.format(new Date());
323            properties.setProperty("General.Output", outDirThisTest.toString());
324            System.out.println("Output folder: " + properties.getProperty("General.Output"));
325            (new File(outDirThisTest)).mkdirs();
326            ToolBox.configureLogging(outDirThisTest, null);
327            FileOutputStream fos = new FileOutputStream(outDirThisTest + File.separator + "rcsp.conf");
328
329            properties.store(fos, "Random CSP problem configuration file");
330            fos.flush();
331            fos.close();
332            test2(properties);
333        }
334    }
335
336    public static void main(String[] args) {
337        try {
338            Progress.getInstance().addProgressListener(new ProgressWriter(System.out));
339            if (args.length == 0) {
340                ToolBox.configureLogging();
341                DataProperties config = new DataProperties(System.getProperties());
342                config.setProperty("Termination.StopWhenComplete", "false");
343                config.setProperty("Termination.TimeOut", "60");
344                config.setProperty("General.Output", System.getProperty("user.dir"));
345                test2(config);
346                return;
347            }
348            File inputCfg = new File(args[0]);
349            DataProperties properties = ToolBox.loadProperties(inputCfg);
350            if (args.length == 3) {
351                File xmlFile = new File(args[1]);
352                String outDir = args[2] + File.separator + (sDateFormat.format(new Date()));
353                properties.setProperty("General.Output", outDir.toString());
354                System.out.println("Input file: " + xmlFile);
355                System.out.println("Output folder: " + properties.getProperty("General.Output"));
356                (new File(outDir)).mkdirs();
357                ToolBox.configureLogging(outDir, null);
358                test3(properties, xmlFile);
359            } else if (properties.getProperty("INCLUDE_REGEXP") != null) {
360                test(inputCfg, null, null, properties.getProperty("INCLUDE_REGEXP"), (args.length > 1 ? args[1] : null));
361            } else {
362                String outDir = properties.getProperty("General.Output", ".") + File.separator
363                        + inputCfg.getName().substring(0, inputCfg.getName().lastIndexOf('.')) + File.separator
364                        + sDateFormat.format(new Date());
365                if (args.length > 1)
366                    outDir = args[1] + File.separator + (sDateFormat.format(new Date()));
367                properties.setProperty("General.Output", outDir.toString());
368                System.out.println("Output folder: " + properties.getProperty("General.Output"));
369                (new File(outDir)).mkdirs();
370                ToolBox.configureLogging(outDir, null);
371                test2(properties);
372            }
373        } catch (Exception e) {
374            e.printStackTrace();
375        }
376    }
377}