001package net.sf.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 net.sf.cpsolver.ifs.solution.Solution;
015import net.sf.cpsolver.ifs.solver.Solver;
016import net.sf.cpsolver.ifs.util.DataProperties;
017import net.sf.cpsolver.ifs.util.Progress;
018import net.sf.cpsolver.ifs.util.ProgressWriter;
019import 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 Tomáš Müller<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 */
043public 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}