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