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