    001package net.sf.cpsolver.ifs.example.csp;
    002
    003import java.io.File;
    004import java.io.FileInputStream;
    005import java.io.FileOutputStream;
    006import java.io.FileWriter;
    007import java.io.PrintWriter;
    008import java.util.Date;
    009import java.util.Iterator;
    010import java.util.Locale;
    011import java.util.StringTokenizer;
    012
    013import net.sf.cpsolver.ifs.model.Constraint;
    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 of Structured CSP problems. It takes one argument -- property file with
    023 * all the parameters. It allows to execute given number of tests. It also
    024 * allows to define several configurations which will be executed. For instance
    025 * CSP(20,15,5%..95%,5..95%), 10 runs of each configuration. All such
    026 * configuration are processed in one run of Test class. <br>
    027 * <br>
    028 * In Structured CSP, variables are divided into several kernels (some variables
    029 * may remain ouside kernels). Different constraints (in density and tightnes)
    030 * are generated according to whether variables are from the same kernel or not. <br>
    031 * <br>
    032 * Test's parameters: <br>
    033 * <table border='1'>
    034 * <tr>
    035 * <th>Parameter</th>
    036 * <th>Type</th>
    037 * <th>Comment</th>
    038 * </tr>
    039 * <tr>
    040 * <td>General.MPP</td>
    041 * <td>{@link String}</td>
    042 * <td>Minimal perturbation problem (if true), this mj. means that initial
    043 * assignment will be generated</td>
    044 * </tr>
    045 * <tr>
    046 * <td>CSP.Seed</td>
    047 * <td>{@link Long}</td>
    048 * <td>Random number generator seed, {@link System#currentTimeMillis()} is taken
    049 * if not present</td>
    050 * </tr>
    051 * <tr>
    052 * <td>CSP.ForceSolutionExistance</td>
    053 * <td>{@link Boolean}</td>
    054 * <td>If true, generated problem will always have at least one feasible
    055 * solution</td>
    056 * </tr>
    057 * <tr>
    058 * <td>CPS.NrTests</td>
    059 * <td>{@link Integer}</td>
    060 * <td>Number of tests (for each input configuration)</td>
    061 * </tr>
    062 * <tr>
    063 * <td>CSP.NrVariables</td>
    064 * <td>{@link Integer}</td>
    065 * <td>Number of variables</td>
    066 * </tr>
    067 * <tr>
    068 * <td>CSP.NrVariablesMin<br>
    069 * CSP.NrVariablesMax<br>
    070 * CSP.NrVariablesStep</td>
    071 * <td>{@link Integer}</td>
    072 * <td>Range of the number variables (a set of different configurations will be
    073 * generated)<br>
    074 * Use either CSP.NrVariables or these CSP.NrVariablesMin, CSP.NrVariablesMax,
    075 * CSP.NrVariablesStep</td>
    076 * </tr>
    077 * <tr>
    078 * <td>CSP.DomainSize</td>
    079 * <td>{@link Integer}</td>
    080 * <td>Number of values of every variable</td>
    081 * </tr>
    082 * <tr>
    083 * <td>CSP.DomainSizeRatio</td>
    084 * <td>{@link Double}</td>
    085 * <td>Number of values as a ration of the number of variables. This way we can
    086 * model for instance CSP(N,2N,p1,p2) problems with one configuration.<br>
    087 * Use either CSP.DomainSize or CSP.DomainSizeRatio</td>
    088 * </tr>
    089 * <tr>
    090 * <td>CSP.Tightness</td>
    091 * <td>{@link Double}</td>
    092 * <td>Tightness of constraints outside kernels</td>
    093 * </tr>
    094 * <tr>
    095 * <td>CSP.TightnessMin<br>
    096 * CSP.TightnessMax<br>
    097 * CSP.TightnessStep</td>
    098 * <td>{@link Double}</td>
    099 * <td>Tightness of constraints outside kernels given as a range -> respective
    100 * configurations will be generated and tested</td>
    101 * </tr>
    102 * <tr>
    103 * <td>CSP.Density</td>
    104 * <td>{@link Double}</td>
    105 * <td>Density of constraints outside kernels</td>
    106 * </tr>
    107 * <tr>
    108 * <td>CSP.DensityMin<br>
    109 * CSP.DensityMax<br>
    110 * CSP.DensityStep</td>
    111 * <td>{@link Double}</td>
    112 * <td>Density of constraints outside kernels given as a range -> respective
    113 * configurations will be generated and tested</td>
    114 * </tr>
    115 * <tr>
    116 * <td>CSP.NrKernels</td>
    117 * <td>{@link Integer}</td>
    118 * <td>Number of kernels (Structured CSP, use 0 for "normal" CSP)</td>
    119 * </tr>
    120 * <tr>
    121 * <td>CSP.KernelSize</td>
    122 * <td>{@link Integer}</td>
    123 * <td>Number of variables in each kernel</td>
    124 * </tr>
    125 * <tr>
    126 * <td>CSP.KernelTightness</td>
    127 * <td>{@link Double}</td>
    128 * <td>Tightness of constraints inside a kernel</td>
    129 * </tr>
    130 * <tr>
    131 * <td>CSP.KernelDensity</td>
    132 * <td>{@link Double}</td>
    133 * <td>Density of constraints inside a kernel</td>
    134 * </tr>
    135 * <tr>
    136 * <td>CSP.SameProblemEachStep</td>
    137 * <td>{@link Boolean}</td>
    138 * <td>If true, each configuration will start with the same seed</td>
    139 * </tr>
    140 * <tr>
    141 * <td>CSP.SameProblemEachTest</td>
    142 * <td>{@link Boolean}</td>
    143 * <td>If true, each test of the same configuration will start with the same
    144 * seed</td>
    145 * </tr>
    146 * <tr>
    147 * <td>General.Output</td>
    148 * <td>{@link String}</td>
    149 * <td>Output folder where a log file and tables with results. In order not to
    150 * overwrite the results if executed more than once, a subfolder with the name
    151 * taken from current date and time will be created in this folder and all
    152 * results will go to this subfolder.</td>
    153 * </tr>
    154 * </table>
    155 * <br>
    156 * <br>
    157 * Also, the configuration file can consist only from one parameter (named
    158 * INCLUDE_REGEXP) which is processed as a regular expression of semicolon
    159 * separated list of property files, for instance
    160 * <ul>
    161 * <code>INCLUDE_REGEXP=general.ini;{CSP(50,12,250,p2)|CSP(25,15,198,p2)}.ini;{std|opt}.ini;{10x1min}.ini;{cbs|rw1|tabu20}.ini</code>
    162 * <br>
    163 * </ul>
    164 * where {a|b|c|...} means a selection of a, b, c, .. All possible combinations
    165 * are taken and for each of them an input configuration is combined from the
    166 * relevant files. So, for instance, the above example will result into the
    167 * following configurations:
    168 * <ul>
    169 * <li>general.ini;CSP(50,12,250,p2).ini;std.ini;10x1min.ini;cbs.ini
    170 * <li>general.ini;CSP(50,12,250,p2).ini;std.ini;10x1min.ini;rw1.ini
    171 * <li>general.ini;CSP(50,12,250,p2).ini;std.ini;10x1min.ini;tabu20.ini
    172 * <li>general.ini;CSP(50,12,250,p2).ini;opt.ini;10x1min.ini;cbs.ini
    173 * <li>general.ini;CSP(50,12,250,p2).ini;opt.ini;10x1min.ini;rw1.ini
    174 * <li>general.ini;CSP(50,12,250,p2).ini;opt.ini;10x1min.ini;tabu20.ini
    175 * <li>general.ini;CSP(25,15,198,p2).ini;std.ini;10x1min.ini;cbs.ini
    176 * <li>general.ini;CSP(25,15,198,p2).ini;std.ini;10x1min.ini;rw1.ini
    177 * <li>general.ini;CSP(25,15,198,p2).ini;std.ini;10x1min.ini;tabu20.ini
    178 * <li>general.ini;CSP(25,15,198,p2).ini;opt.ini;10x1min.ini;cbs.ini
    179 * <li>general.ini;CSP(25,15,198,p2).ini;opt.ini;10x1min.ini;rw1.ini
    180 * <li>general.ini;CSP(25,15,198,p2).ini;opt.ini;10x1min.ini;tabu20.ini
    181 * </ul>
    182 * To be able to distinguish such configuration a subfolder in General.Output
    183 * folder is created, its name is combined from the names which are in
    184 * parenthesis. So, for instance the first bunch of tests will output into the
    185 * folder:
    186 * <ul>
    187 * ${General.Output}\CSP(50,12,250,p2)_std_10x1min_csb\25-Feb-05_191136
    188 * </ul>
    189 * If one parameter is defined in more than one configuration files (e.g. in
    190 * general.ini as well as cbs.ini) the one from the file more on the right is
    191 * taken. <br>
    192 * <br>
    193 * An example of the configurations:<br>
    194 * File<b> general.ini</b>
    195 * <ul>
    196 * <code>
    197 * #Default settings common for all configurations<br>
    198 * General.MPP=false<br>
    199 * General.InitialAssignment=false<br>
    200 * General.Output=output\\RandomCSP\\IFS<br>
    201 * <br>
    202 * #Value selection heuristics<br>
    203 * Value.Class=net.sf.cpsolver.ifs.heuristics.GeneralValueSelection<br>
    204 * Value.WeightWeightedConflicts=0.0<br>
    205 * Value.RandomWalkProb=0.0<br>
    206 * Value.WeightConflicts=1.0<br>
    207 * Value.WeightNrAssignments=0.0<br>
    208 * Value.WeightValue=0.0<br>
    209 * Value.Tabu=0<br>
    210 * <br>
    211 * #Variable selection heuristics<br>
    212 * Variable.Class=net.sf.cpsolver.ifs.heuristics.GeneralVariableSelection<br>
    213 * Variable.RandomSelection=true<br>
    214 * <br>
    215 * #Termination condition<br>
    216 * Termination.Class=net.sf.cpsolver.ifs.termination.GeneralTerminationCondition<br>
    217 * Termination.MaxIters=-1<br>
    218 * Termination.TimeOut=-1<br>
    219 * Termination.StopWhenComplete=true<br>
    220 * <br>
    221 * #Solution comparator<br>
    222 * Comparator.Class=net.sf.cpsolver.ifs.solution.GeneralSolutionComparator<br>
    223 * </code>
    224 * </ul>
    225 * <br>
    226 * File<b> CSP(50,12,250,p2).ini</b>
    227 * <ul>
    228 * <code>
    229 * #Sparse problem CSP(50,12,250/1225,p2)<br>
    230 * CSP.NrVariables=50<br>
    231 * CSP.DomainSize=12<br>
    232 * CSP.Density=0.2<br>
    233 * CSP.TightnessMin=0.10<br>
    234 * CSP.TightnessMax=0.95<br>
    235 * CSP.TightnessStep=0.02<br>
    236 * <br>
    237 * CSP.Seed=780921<br>
    238 * <br>
    239 * CSP.ForceSolutionExistance=false<br>
    240 * CSP.SameProblemEachStep=false<br>
    241 * CSP.SameProblemEachTest=false<br>
    242 * <br>
    243 * CSP.NrKernels=0<br>
    244 * </code>
    245 * </ul>
    246 * <br>
    247 * File<b> std.ini</b>
    248 * <ul>
    249 * <code>
    250 * #Standard problem<br>
    251 * CSP.ForceSolutionExistance=false<br>
    252 * </code>
    253 * </ul>
    254 * <br>
    255 * File<b> opt.ini</b>
    256 * <ul>
    257 * <code>
    258 * #Optimization problem (minCSP)<br>
    259 * #Value selection: use weigh of a conflict, but when there are more than one value<br>
    260 * #        with the same number of conflicts, use the one with lower value<br>
    261 * Value.WeightValue=0.0001<br>
    262 * Value.WeightConflicts=1.0<br>
    263 * #Do not stop when a complete solution is found<br>
    264 * Termination.StopWhenComplete=false<br>
    265 * </code>
    266 * </ul>
    267 * <br>
    268 * File<b> 10x1min.ini</b>
    269 * <ul>
    270 * <code>
    271 * #For each configuration, execute 10 tests, each with 1 minute timeout<br>
    272 * CPS.NrTests=10<br>
    273 * Termination.TimeOut=60<br>
    274 * </code>
    275 * </ul>
    276 * <br>
    277 * File<b> cbs.ini</b>
    278 * <ul>
    279 * <code>
    280 * #Use conflict-based statistics<br>
    281 * Extensions.Classes=net.sf.cpsolver.ifs.extension.ConflictStatistics<br>
    282 * Value.WeightWeightedConflicts=1.0<br>
    283 * </code>
    284 * </ul>
    285 * <br>
    286 * File<b> tabu20.ini</b>
    287 * <ul>
    288 * <code>
    289 * #Use tabu-list of the length 20<br>
    290 * Value.Tabu=20<br>
    291 * </code>
    292 * </ul>
    293 * <br>
    294 * File<b> rw1.ini</b>
    295 * <ul>
    296 * <code>
    297 * #Use 1% random walk selection<br>
    298 * Value.RandomWalkProb=0.01<br>
    299 * </code>
    300 * </ul>
    301 * <br>
    302 *
    303 * @see StructuredCSPModel
    304 * @see net.sf.cpsolver.ifs.extension.ConflictStatistics
    305 * @see net.sf.cpsolver.ifs.heuristics.GeneralValueSelection
    306 * @see net.sf.cpsolver.ifs.heuristics.GeneralVariableSelection
    307 * @see net.sf.cpsolver.ifs.termination.GeneralTerminationCondition
    308 * @see net.sf.cpsolver.ifs.solution.GeneralSolutionComparator
    309 *
    310 * @version IFS 1.2 (Iterative Forward Search)<br>
    311 *          Copyright (C) 2006 - 2010 Tomáš Müller<br>
    312 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    313 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    314 * <br>
    315 *          This library is free software; you can redistribute it and/or modify
    316 *          it under the terms of the GNU Lesser General Public License as
    317 *          published by the Free Software Foundation; either version 3 of the
    318 *          License, or (at your option) any later version. <br>
    319 * <br>
    320 *          This library is distributed in the hope that it will be useful, but
    321 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    322 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    323 *          Lesser General Public License for more details. <br>
    324 * <br>
    325 *          You should have received a copy of the GNU Lesser General Public
    326 *          License along with this library; if not see
    327 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    328 */
    329public class Test {
    330    private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.000",
    331            new java.text.DecimalFormatSymbols(Locale.US));
    332    private static java.text.SimpleDateFormat sDateFormat = new java.text.SimpleDateFormat("dd-MMM-yy_HHmmss",
    333            java.util.Locale.US);
    334    private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Test.class);
    335
    336    private static void test(DataProperties properties) throws Exception {
    337        boolean sameProblemStep = properties.getPropertyBoolean("CSP.SameProblemEachStep", false);
    338        boolean sameProblemTest = properties.getPropertyBoolean("CSP.SameProblemEachTest", false);
    339        int nrVars = properties.getPropertyInt("CSP.NrVariables", 20);
    340        int nrKernels = properties.getPropertyInt("CSP.NrKernels", 2);
    341        int nrKernelVariables = properties.getPropertyInt("CSP.KernelSize", 8);
    342        int nrVariablesMin = properties.getPropertyInt("CSP.NrVariablesMin", nrVars);
    343        int nrVariablesMax = properties.getPropertyInt("CSP.NrVariablesMax", nrVars);
    344        int nrVariablesStep = properties.getPropertyInt("CSP.NrVariablesStep", 1);
    345        int nrValues = properties.getPropertyInt("CSP.DomainSize", 10);
    346        double nrValuesRatio = properties.getPropertyDouble("CSP.DomainSizeRatio", -1);
    347        float kernelTightness = properties.getPropertyFloat("CSP.KernelTightness", 0.097f);
    348        float kernelDensity = properties.getPropertyFloat("CSP.KernelDensity", 0.097f);
    349        float tightnessInit = properties.getPropertyFloat("CSP.Tightness", 0.4f);
    350        float tightnessMin = properties.getPropertyFloat("CSP.TightnessMin", tightnessInit);
    351        float tightnessMax = properties.getPropertyFloat("CSP.TightnessMax", tightnessInit) + 1e-6f;
    352        float tightnessStep = properties.getPropertyFloat("CSP.TightnessStep", 0.1f);
    353        float densityInit = properties.getPropertyFloat("CSP.Density", 0.4f);
    354        float densityMin = properties.getPropertyFloat("CSP.DensityMin", densityInit);
    355        float densityMax = properties.getPropertyFloat("CSP.DensityMax", densityInit) + 1e-6f;
    356        float densityStep = properties.getPropertyFloat("CSP.DensityStep", 0.1f);
    357        long seed = properties.getPropertyLong("CSP.Seed", System.currentTimeMillis());
    358        int nrTests = properties.getPropertyInt("CPS.NrTests", 10);
    359        boolean mpp = properties.getPropertyBoolean("General.MPP", false);
    360        PrintWriter logStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator
    361                + "rcsp_" + nrVariablesMin + "_" + nrValues + ".csv"));
    362        PrintWriter logAvgStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output")
    363                + File.separator + "avg_stat.csv"));
    364        PrintWriter log = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator
    365                + "info.txt"));
    366        logStat
    367                .println("testNr;nrVars;nrVals;density[%];tightness[%];time[s];iters;speed[it/s];unassConstr;assigned;assigned[%]"
    368                        + (mpp ? ";perts;perts[%]" : "") + ";value;totalValue");
    369        logAvgStat
    370                .println("nrVars;nrVals;density[%];tightness[%];time[s];RMStime[s];iters;RMSiters;speed[it/s];unassConst;assigned;RMSassigned;assigned[%]"
    371                        + (mpp ? ";perts;RMSperts;perts[%]" : "") + ";value;RMSvalue;totalValue;RMStotalValue");
    372        System.out.println("Number of variables: " + nrVariablesMin + " .. " + nrVariablesMax + "  (step="
    373                + nrVariablesStep + ")");
    374        System.out.println("Density:             " + densityMin + " .. " + densityMax + "  (step=" + densityStep + ")");
    375        System.out.println("Tightness:           " + tightnessMin + " .. " + tightnessMax + "  (step=" + tightnessStep
    376                + ")");
    377        for (int nrVariables = nrVariablesMin; nrVariables <= nrVariablesMax; nrVariables += nrVariablesStep) {
    378            if (nrValuesRatio > 0.0)
    379                nrValues = (int) Math.round(nrValuesRatio * nrVariables);
    380            for (float density = densityMin; density <= densityMax; density += densityStep) {
    381                for (float tightness = tightnessMin; tightness <= tightnessMax; tightness += tightnessStep) {
    382                    log.println("CSP{#Var=" + nrVariables + ", #Val=" + nrValues + ", P(density)="
    383                            + sDoubleFormat.format(100.0 * density) + "%, P(tighness)="
    384                            + sDoubleFormat.format(100.0 * tightness) + ", " + nrKernels + "x Kernel{#Var="
    385                            + nrKernelVariables + ", P(density)=" + sDoubleFormat.format(100.0 * kernelDensity)
    386                            + "%, P(tighness)=" + sDoubleFormat.format(100.0 * kernelTightness) + "%}}");
    387                    double sumTime = 0;
    388                    double sumTime2 = 0;
    389                    int sumIters = 0;
    390                    int sumIters2 = 0;
    391                    int sumConfl = 0;
    392                    int sumAssign = 0;
    393                    int sumAssign2 = 0;
    394                    int sumPert = 0;
    395                    int sumPert2 = 0;
    396                    int sumVal = 0;
    397                    int sumVal2 = 0;
    398                    int sumTotalVal = 0;
    399                    int sumTotalVal2 = 0;
    400                    for (int test = 1; test <= nrTests; test++) {
    401                        log.println("  " + test + ". test");
    402                        log.flush();
    403                        properties.setProperty("CSP.NrVariables", String.valueOf(nrVariables));
    404                        properties.setProperty("CSP.Tightness", String.valueOf(tightness));
    405                        properties.setProperty("CSP.Density", String.valueOf(density));
    406
    407                        long currentSeed = (seed * 1000000L)
    408                                + (1000 * (long) ((sameProblemStep ? densityMin : density) * 1000.0))
    409                                + ((long) ((sameProblemStep ? tightnessMin : tightness) * 1000.0));
    410                        currentSeed = (currentSeed * nrTests) + (sameProblemTest ? 0 : test - 1);
    411
    412                        sLogger.debug("Seed: " + currentSeed);
    413                        StructuredCSPModel csp = new StructuredCSPModel(properties, currentSeed);
    414
    415                        Solver<CSPVariable, CSPValue> s = new Solver<CSPVariable, CSPValue>(properties);
    416                        s.setInitalSolution(csp);
    417                        s.currentSolution().clearBest();
    418                        s.start();
    419
    420                        try {
    421                            s.getSolverThread().join();
    422                        } catch (NullPointerException npe) {
    423                        }
    424
    425                        if (s.lastSolution().getBestInfo() == null)
    426                            sLogger.error("No solution found :-(");
    427                        sLogger.debug("Last solution:" + s.lastSolution().getInfo());
    428                        Solution<CSPVariable, CSPValue> best = s.lastSolution();
    429                        sLogger.debug("Best solution:" + s.lastSolution().getBestInfo());
    430                        best.restoreBest();
    431                        int val = 0;
    432                        for (Iterator<CSPVariable> iv = best.getModel().assignedVariables().iterator(); iv.hasNext();)
    433                            val += (int) iv.next().getAssignment().toDouble();
    434                        int totalVal = val + (best.getModel().unassignedVariables().size() * nrValues);
    435                        sLogger.debug("Last solution:" + best.getInfo());
    436                        logStat.println(test
    437                                + ";"
    438                                + nrVariables
    439                                + ";"
    440                                + nrValues
    441                                + ";"
    442                                + sDoubleFormat.format(density)
    443                                + ";"
    444                                + sDoubleFormat.format(tightness)
    445                                + ";"
    446                                + sDoubleFormat.format(best.getTime())
    447                                + ";"
    448                                + best.getIteration()
    449                                + ";"
    450                                + sDoubleFormat.format((best.getIteration()) / best.getTime())
    451                                + ";"
    452                                + best.getModel().unassignedHardConstraints().size()
    453                                + ";"
    454                                + best.getModel().assignedVariables().size()
    455                                + ";"
    456                                + sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size()
    457                                        / best.getModel().variables().size())
    458                                + (mpp ? ";"
    459                                        + (best.getModel().perturbVariables().size() + best.getModel()
    460                                                .unassignedVariables().size())
    461                                        + ";"
    462                                        + sDoubleFormat.format(100.0
    463                                                * (best.getModel().perturbVariables().size() + best.getModel()
    464                                                        .unassignedVariables().size())
    465                                                / best.getModel().variables().size()) : "") + ";" + val + ";"
    466                                + totalVal);
    467                        log.println("    seed:         " + currentSeed);
    468                        log.println("    constraints:  " + best.getModel().constraints().size());
    469                        for (Iterator<Constraint<CSPVariable, CSPValue>> i = best.getModel().constraints().iterator(); i
    470                                .hasNext();) {
    471                            CSPBinaryConstraint c = (CSPBinaryConstraint) i.next();
    472                            log.println("      " + c.getName() + " (" + c.first().getName() + ","
    473                                    + c.second().getName() + ")");
    474                            for (CSPValue v0 : c.first().values()) {
    475                                log.print("        ");
    476                                for (CSPValue v1 : c.second().values())
    477                                    log.print(c.isConsistent(v0, v1) ? "1 " : "0 ");
    478                            }
    479                            log.println();
    480                        }
    481                        log.println("    time:         " + sDoubleFormat.format(best.getTime()) + " s");
    482                        log.println("    iteration:    " + best.getIteration());
    483                        log.println("    speed:        " + sDoubleFormat.format((best.getIteration()) / best.getTime())
    484                                + " it/s");
    485                        log.println("    assigned:     "
    486                                + best.getModel().assignedVariables().size()
    487                                + " ("
    488                                + sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size()
    489                                        / best.getModel().variables().size()) + "%)");
    490                        log.println("    total value:  " + val);
    491                        if (mpp)
    492                            log.println("    perturbations:"
    493                                    + (best.getModel().perturbVariables().size() + best.getModel()
    494                                            .unassignedVariables().size())
    495                                    + " ("
    496                                    + sDoubleFormat
    497                                            .format(100.0
    498                                                    * (best.getModel().perturbVariables().size() + best.getModel()
    499                                                            .unassignedVariables().size())
    500                                                    / best.getModel().variables().size()) + "%)");
    501                        log.print("    solution:     ");
    502                        for (CSPVariable v : ((CSPModel) best.getModel()).variables()) {
    503                            if (v.getBestAssignment() == null)
    504                                continue;
    505                            log.print(v.getName() + "=" + v.getBestAssignment().getName());
    506                            log.print(", ");
    507                        }
    508                        log.println();
    509                        sumTime += best.getTime();
    510                        sumTime2 += best.getTime() * best.getTime();
    511                        sumIters += best.getIteration();
    512                        sumIters2 += best.getIteration() * best.getIteration();
    513                        sumConfl += best.getModel().unassignedHardConstraints().size();
    514                        sumAssign += best.getModel().assignedVariables().size();
    515                        sumAssign2 += best.getModel().assignedVariables().size()
    516                                * best.getModel().assignedVariables().size();
    517                        sumVal += val;
    518                        sumVal2 += val * val;
    519                        sumTotalVal += totalVal;
    520                        sumTotalVal2 += totalVal * totalVal;
    521                        if (mpp) {
    522                            sumPert += (best.getModel().perturbVariables().size() + best.getModel()
    523                                    .unassignedVariables().size());
    524                            sumPert2 += (best.getModel().perturbVariables().size() + best.getModel()
    525                                    .unassignedVariables().size())
    526                                    * (best.getModel().perturbVariables().size() + best.getModel()
    527                                            .unassignedVariables().size());
    528                        }
    529                        log.flush();
    530                        logStat.flush();
    531                    }
    532                    logAvgStat.println(nrVariables
    533                            + ";"
    534                            + nrValues
    535                            + ";"
    536                            + sDoubleFormat.format(density)
    537                            + ";"
    538                            + sDoubleFormat.format(tightness)
    539                            + ";"
    540                            + sDoubleFormat.format(sumTime / nrTests)
    541                            + ";"
    542                            + sDoubleFormat.format(ToolBox.rms(nrTests, sumTime, sumTime2))
    543                            + ";"
    544                            + sDoubleFormat.format(((double) sumIters) / nrTests)
    545                            + ";"
    546                            + sDoubleFormat.format(ToolBox.rms(nrTests, sumIters, sumIters2))
    547                            + ";"
    548                            + sDoubleFormat.format((sumIters) / sumTime)
    549                            + ";"
    550                            + sDoubleFormat.format(((double) sumConfl) / nrTests)
    551                            + ";"
    552                            + sDoubleFormat.format(((double) sumAssign) / nrTests)
    553                            + ";"
    554                            + sDoubleFormat.format(ToolBox.rms(nrTests, sumAssign, sumAssign2))
    555                            + ";"
    556                            + sDoubleFormat.format(100.0 * (sumAssign) / (nrVariables * nrTests))
    557                            + (mpp ? ";" + sDoubleFormat.format(((double) sumPert) / nrTests) + ";"
    558                                    + sDoubleFormat.format(ToolBox.rms(nrTests, sumPert, sumPert2)) + ";"
    559                                    + sDoubleFormat.format(100.0 * (sumPert) / (nrVariables * nrTests)) : "")
    560                            + ";"
    561                            + sDoubleFormat.format(((double) sumVal) / (nrTests * nrVariables))
    562                            + ";"
    563                            + sDoubleFormat.format(ToolBox.rms(nrTests, (double) sumVal / nrVariables, (double) sumVal2
    564                                    / (nrVariables * nrVariables))) + ";"
    565                            + sDoubleFormat.format(((double) sumTotalVal) / nrTests) + ";"
    566                            + sDoubleFormat.format(ToolBox.rms(nrTests, sumTotalVal, sumTotalVal2)));
    567                    logAvgStat.flush();
    568                }
    569            }
    570        }
    571        log.flush();
    572        log.close();
    573        logStat.flush();
    574        logStat.close();
    575        logAvgStat.flush();
    576        logAvgStat.close();
    577    }
    578
    579    private static void test(File inputCfg, String name, String include, String regexp, String outDir) throws Exception {
    580        if (regexp != null) {
    581            String incFile;
    582
    583            if (regexp.indexOf(';') > 0) {
    584                incFile = regexp.substring(0, regexp.indexOf(';'));
    585                regexp = regexp.substring(regexp.indexOf(';') + 1);
    586            } else {
    587                incFile = regexp;
    588                regexp = null;
    589            }
    590            if (incFile.startsWith("[") && incFile.endsWith("]")) {
    591                test(inputCfg, name, include, regexp, outDir);
    592                incFile = incFile.substring(1, incFile.length() - 1);
    593            }
    594            if (incFile.indexOf('{') >= 0 && incFile.indexOf('}') >= 0) {
    595                String prefix = incFile.substring(0, incFile.indexOf('{'));
    596                StringTokenizer middle = new StringTokenizer(incFile.substring(incFile.indexOf('{') + 1, incFile
    597                        .indexOf('}')), "|");
    598                String sufix = incFile.substring(incFile.indexOf('}') + 1);
    599
    600                while (middle.hasMoreTokens()) {
    601                    String m = middle.nextToken();
    602
    603                    test(inputCfg, (name == null ? "" : name + "_") + m, (include == null ? "" : include + ";")
    604                            + prefix + m + sufix, regexp, outDir);
    605                }
    606            } else {
    607                test(inputCfg, name, (include == null ? "" : include + ";") + incFile, regexp, outDir);
    608            }
    609        } else {
    610            DataProperties properties = ToolBox.loadProperties(inputCfg);
    611            StringTokenizer inc = new StringTokenizer(include, ";");
    612
    613            while (inc.hasMoreTokens()) {
    614                String aFile = inc.nextToken();
    615
    616                System.out.println("  Loading included file '" + aFile + "' ... ");
    617                FileInputStream is = null;
    618
    619                if ((new File(aFile)).exists()) {
    620                    is = new FileInputStream(aFile);
    621                }
    622                if ((new File(inputCfg.getParent() + File.separator + aFile)).exists()) {
    623                    is = new FileInputStream(inputCfg.getParent() + File.separator + aFile);
    624                }
    625                if (is == null) {
    626                    System.err.println("Unable to find include file '" + aFile + "'.");
    627                }
    628                properties.load(is);
    629                is.close();
    630            }
    631            String outDirThisTest = (outDir == null ? properties.getProperty("General.Output", ".") : outDir)
    632                    + File.separator + name + File.separator + sDateFormat.format(new Date());
    633            properties.setProperty("General.Output", outDirThisTest.toString());
    634            System.out.println("Output folder: " + properties.getProperty("General.Output"));
    635            (new File(outDirThisTest)).mkdirs();
    636            ToolBox.configureLogging(outDirThisTest, null);
    637            FileOutputStream fos = new FileOutputStream(outDirThisTest + File.separator + "rcsp.conf");
    638
    639            properties.store(fos, "Random CSP problem configuration file");
    640            fos.flush();
    641            fos.close();
    642            test(properties);
    643        }
    644    }
    645
    646    public static void main(String[] args) {
    647        try {
    648            Progress.getInstance().addProgressListener(new ProgressWriter(System.out));
    649            File inputCfg = new File(args[0]);
    650            DataProperties properties = ToolBox.loadProperties(inputCfg);
    651            if (properties.getProperty("INCLUDE_REGEXP") != null) {
    652                test(inputCfg, null, null, properties.getProperty("INCLUDE_REGEXP"), (args.length > 1 ? args[1] : null));
    653            } else {
    654                String outDir = properties.getProperty("General.Output", ".") + File.separator
    655                        + inputCfg.getName().substring(0, inputCfg.getName().lastIndexOf('.')) + File.separator
    656                        + sDateFormat.format(new Date());
    657                if (args.length > 1)
    658                    outDir = args[1] + File.separator + (sDateFormat.format(new Date()));
    659                properties.setProperty("General.Output", outDir.toString());
    660                System.out.println("Output folder: " + properties.getProperty("General.Output"));
    661                (new File(outDir)).mkdirs();
    662                ToolBox.configureLogging(outDir, null);
    663                test(properties);
    664            }
    665        } catch (Exception e) {
    666            e.printStackTrace();
    667        }
    668    }
    669}