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