001    package ifs.example.csp;
002    
003    
004    import ifs.model.*;
005    import ifs.solution.*;
006    import ifs.solver.*;
007    import ifs.util.*;
008    import java.io.*;
009    import java.util.*;
010    
011    /**
012     * Test of Structured CSP problems. It takes one argument -- property file with all the parameters.
013     * It allows to execute given number of tests. It also allows to define several configurations which will be executed. For instance CSP(20,15,5%..95%,5..95%), 10 runs of each configuration. All such configuration are processed in one run of Test class.
014     * <br><br>
015     * In Structured CSP, variables are divided into several kernels (some variables may remain ouside kernels). 
016     * Different constraints (in density and tightnes) are generated according to whether variables are from the same kernel or not.
017     * <br><br>
018     * Test's parameters:
019     * <br>
020     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
021     * <tr><td>General.MPP</td><td>{@link String}</td><td>Minimal perturbation problem (if true), this mj. means that initial assignment will be generated</td></tr>
022     * <tr><td>CSP.Seed</td><td>{@link Long}</td><td>Random number generator seed, {@link System#currentTimeMillis()} is taken if not present</td></tr>
023     * <tr><td>CSP.ForceSolutionExistance</td><td>{@link Boolean}</td><td>If true, generated problem will always have at least one feasible solution</td></tr>
024     * <tr><td>CPS.NrTests</td><td>{@link Integer}</td><td>Number of tests (for each input configuration)</td></tr>
025     * <tr><td>CSP.NrVariables</td><td>{@link Integer}</td><td>Number of variables</td></tr>
026     * <tr><td>CSP.NrVariablesMin<br>CSP.NrVariablesMax<br>CSP.NrVariablesStep</td><td>{@link Integer}</td><td>Range of the number variables (a set of different configurations will be generated)<br>Use either CSP.NrVariables or these CSP.NrVariablesMin, CSP.NrVariablesMax, CSP.NrVariablesStep</td></tr>
027     * <tr><td>CSP.DomainSize</td><td>{@link Integer}</td><td>Number of values of every variable</td></tr>
028     * <tr><td>CSP.DomainSizeRatio</td><td>{@link Double}</td><td>Number of values as a ration of the number of variables. This way we can model for instance CSP(N,2N,p1,p2) problems with one configuration.<br>Use either CSP.DomainSize or CSP.DomainSizeRatio</td></tr>
029     * <tr><td>CSP.Tightness</td><td>{@link Double}</td><td>Tightness of constraints outside kernels</td></tr>
030     * <tr><td>CSP.TightnessMin<br>CSP.TightnessMax<br>CSP.TightnessStep</td><td>{@link Double}</td><td>Tightness of constraints outside kernels given as a range -> respective configurations will be generated and tested</td></tr>
031     * <tr><td>CSP.Density</td><td>{@link Double}</td><td>Density of constraints outside kernels</td></tr>
032     * <tr><td>CSP.DensityMin<br>CSP.DensityMax<br>CSP.DensityStep</td><td>{@link Double}</td><td>Density of constraints outside kernels given as a range -> respective configurations will be generated and tested</td></tr>
033     * <tr><td>CSP.NrKernels</td><td>{@link Integer}</td><td>Number of kernels (Structured CSP, use 0 for "normal" CSP)</td></tr>
034     * <tr><td>CSP.KernelSize</td><td>{@link Integer}</td><td>Number of variables in each kernel</td></tr>
035     * <tr><td>CSP.KernelTightness</td><td>{@link Double}</td><td>Tightness of constraints inside a kernel</td></tr>
036     * <tr><td>CSP.KernelDensity</td><td>{@link Double}</td><td>Density of constraints inside a kernel</td></tr>
037     * <tr><td>CSP.SameProblemEachStep</td><td>{@link Boolean}</td><td>If true, each configuration will start with the same seed</td></tr>
038     * <tr><td>CSP.SameProblemEachTest</td><td>{@link Boolean}</td><td>If true, each test of the same configuration will start with the same seed</td></tr>
039     * <tr><td>General.Output</td><td>{@link String}</td><td>Output folder where a log file and tables with results. In order not to overwrite the results if executed more than once, a subfolder with the name taken from current date and time will be created in this folder and all results will go to this subfolder.</td></tr>
040     * </table>
041     * <br><br>
042     * Also, the configuration file can consist only from one parameter (named INCLUDE_REGEXP) which is processed as a regular expression of semicolon separated list of property files, for instance<ul>
043     * <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><br>
044     * </ul>where {a|b|c|...} means a selection of a, b, c, .. All possible combinations are taken and for each of them an input configuration is combined from the relevant files. So, for instance, the above example will result into the following configurations:<ul>
045     * <li>general.ini;CSP(50,12,250,p2).ini;std.ini;10x1min.ini;cbs.ini
046     * <li>general.ini;CSP(50,12,250,p2).ini;std.ini;10x1min.ini;rw1.ini
047     * <li>general.ini;CSP(50,12,250,p2).ini;std.ini;10x1min.ini;tabu20.ini
048     * <li>general.ini;CSP(50,12,250,p2).ini;opt.ini;10x1min.ini;cbs.ini
049     * <li>general.ini;CSP(50,12,250,p2).ini;opt.ini;10x1min.ini;rw1.ini
050     * <li>general.ini;CSP(50,12,250,p2).ini;opt.ini;10x1min.ini;tabu20.ini
051     * <li>general.ini;CSP(25,15,198,p2).ini;std.ini;10x1min.ini;cbs.ini
052     * <li>general.ini;CSP(25,15,198,p2).ini;std.ini;10x1min.ini;rw1.ini
053     * <li>general.ini;CSP(25,15,198,p2).ini;std.ini;10x1min.ini;tabu20.ini
054     * <li>general.ini;CSP(25,15,198,p2).ini;opt.ini;10x1min.ini;cbs.ini
055     * <li>general.ini;CSP(25,15,198,p2).ini;opt.ini;10x1min.ini;rw1.ini
056     * <li>general.ini;CSP(25,15,198,p2).ini;opt.ini;10x1min.ini;tabu20.ini
057     * </ul>To be able to distinguish such configuration a subfolder in General.Output folder is created, its name is combined from the names which are in parenthesis.
058     * So, for instance the first bunch of tests will output into the folder:<ul>
059     * ${General.Output}\CSP(50,12,250,p2)_std_10x1min_csb\25-Feb-05_191136
060     * </ul>If one parameter is defined in more than one configuration files (e.g. in general.ini as well as cbs.ini) the one from the file more on the right is taken.
061     * <br><br>
062     * An example of the configurations:<br>
063     * File<b> general.ini</b><ul><code>
064     * #Default settings common for all configurations<br>
065     * General.MPP=false<br>
066     * General.InitialAssignment=false<br>
067     * General.Output=output\\RandomCSP\\IFS<br>
068     * <br>
069     * #Value selection heuristics<br>
070     * Value.Class=ifs.heuristics.GeneralValueSelection<br>
071     * Value.WeightWeightedConflicts=0.0<br>
072     * Value.RandomWalkProb=0.0<br>
073     * Value.WeightConflicts=1.0<br>
074     * Value.WeightNrAssignments=0.0<br>
075     * Value.WeightValue=0.0<br>
076     * Value.Tabu=0<br>
077     * <br>
078     * #Variable selection heuristics<br>
079     * Variable.Class=ifs.heuristics.GeneralVariableSelection<br>
080     * Variable.RandomSelection=true<br>
081     * <br>
082     * #Termination condition<br>
083     * Termination.Class=ifs.termination.GeneralTerminationCondition<br>
084     * Termination.MaxIters=-1<br>
085     * Termination.TimeOut=-1<br>
086     * Termination.StopWhenComplete=true<br>
087     * <br>
088     * #Solution comparator<br>
089     * Comparator.Class=ifs.solution.GeneralSolutionComparator<br>
090     * </code></ul><br>
091     * File<b> CSP(50,12,250,p2).ini</b><ul><code>
092     * #Sparse problem CSP(50,12,250/1225,p2)<br>
093     * CSP.NrVariables=50<br>
094     * CSP.DomainSize=12<br>
095     * CSP.Density=0.2<br>
096     * CSP.TightnessMin=0.10<br>
097     * CSP.TightnessMax=0.95<br>
098     * CSP.TightnessStep=0.02<br>
099     * <br> 
100     * CSP.Seed=780921<br>
101     * <br>
102     * CSP.ForceSolutionExistance=false<br>
103     * CSP.SameProblemEachStep=false<br>
104     * CSP.SameProblemEachTest=false<br>
105     * <br>
106     * CSP.NrKernels=0<br>
107     * </code></ul><br>
108     * File<b> std.ini</b><ul><code>
109     * #Standard problem<br>
110     * CSP.ForceSolutionExistance=false<br>
111     * </code></ul><br>
112     * File<b> opt.ini</b><ul><code>
113     * #Optimization problem (minCSP)<br>
114     * #Value selection: use weigh of a conflict, but when there are more than one value<br>
115     * #        with the same number of conflicts, use the one with lower value<br>
116     * Value.WeightValue=0.0001<br>
117     * Value.WeightConflicts=1.0<br>
118     * #Do not stop when a complete solution is found<br>
119     * Termination.StopWhenComplete=false<br>
120     * </code></ul><br>
121     * File<b> 10x1min.ini</b><ul><code>
122     * #For each configuration, execute 10 tests, each with 1 minute timeout<br>
123     * CPS.NrTests=10<br>
124     * Termination.TimeOut=60<br>
125     * </code></ul><br>
126     * File<b> cbs.ini</b><ul><code>
127     * #Use conflict-based statistics<br>
128     * Extensions.Classes=ifs.extension.ConflictStatistics<br>
129     * Value.WeightWeightedConflicts=1.0<br>
130     * </code></ul><br>
131     * File<b> tabu20.ini</b><ul><code>
132     * #Use tabu-list of the length 20<br>
133     * Value.Tabu=20<br>
134     * </code></ul><br>
135     * File<b> rw1.ini</b><ul><code>
136     * #Use 1% random walk selection<br>
137     * Value.RandomWalkProb=0.01<br>
138     * </code></ul><br>
139     *
140     * @see StructuredCSPModel
141     * @see ifs.extension.ConflictStatistics
142     * @see ifs.heuristics.GeneralValueSelection
143     * @see ifs.heuristics.GeneralVariableSelection
144     * @see ifs.termination.GeneralTerminationCondition
145     * @see ifs.solution.GeneralSolutionComparator
146     *
147     * @author <a href="mailto:muller@ktiml.mff.cuni.cz">Tomáš Müller</a>
148     * @version 1.0
149     */
150    public class Test {
151        private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.000", new java.text.DecimalFormatSymbols(Locale.US));
152        private static java.text.SimpleDateFormat sDateFormat = new java.text.SimpleDateFormat("dd-MMM-yy_HHmmss", java.util.Locale.US);
153        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Test.class);
154        
155        private static void test(DataProperties properties) throws Exception {
156            boolean sameProblemStep = properties.getPropertyBoolean("CSP.SameProblemEachStep", false);
157            boolean sameProblemTest = properties.getPropertyBoolean("CSP.SameProblemEachTest", false);
158            int nrVars = properties.getPropertyInt("CSP.NrVariables",20);
159            int nrKernels = properties.getPropertyInt("CSP.NrKernels", 2);
160            int nrKernelVariables = properties.getPropertyInt("CSP.KernelSize", 8);
161            int nrVariablesMin = properties.getPropertyInt("CSP.NrVariablesMin",nrVars);
162            int nrVariablesMax = properties.getPropertyInt("CSP.NrVariablesMax",nrVars);
163            int nrVariablesStep = properties.getPropertyInt("CSP.NrVariablesStep",1);
164            int nrValues = properties.getPropertyInt("CSP.DomainSize",10);
165            double nrValuesRatio = properties.getPropertyDouble("CSP.DomainSizeRatio",-1);
166            float kernelTightness = properties.getPropertyFloat("CSP.KernelTightness", 0.097f);
167            float kernelDensity = properties.getPropertyFloat("CSP.KernelDensity", 0.097f);
168            float tightnessInit = properties.getPropertyFloat( "CSP.Tightness", 0.4f);
169            float tightnessMin = properties.getPropertyFloat( "CSP.TightnessMin", tightnessInit);
170            float tightnessMax = properties.getPropertyFloat( "CSP.TightnessMax", tightnessInit)+1e-6f;
171            float tightnessStep = properties.getPropertyFloat( "CSP.TightnessStep", 0.1f);
172            float densityInit = properties.getPropertyFloat( "CSP.Density", 0.4f);
173            float densityMin = properties.getPropertyFloat( "CSP.DensityMin", densityInit);
174            float densityMax = properties.getPropertyFloat( "CSP.DensityMax", densityInit)+1e-6f;
175            float densityStep = properties.getPropertyFloat( "CSP.DensityStep", 0.1f);
176            long seed = properties.getPropertyLong( "CSP.Seed", System.currentTimeMillis());
177            int nrTests = properties.getPropertyInt("CPS.NrTests",10);
178            boolean mpp = properties.getPropertyBoolean("General.MPP", false);
179            boolean forceSolutionExistance = properties.getPropertyBoolean( "CSP.ForceSolutionExistance", false);
180            PrintWriter logStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output")+File.separator+"rcsp_"+nrVariablesMin+"_"+nrValues+".csv"));
181            PrintWriter logAvgStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output")+File.separator+"avg_stat.csv"));
182            PrintWriter log = new PrintWriter(new FileWriter(properties.getProperty("General.Output")+File.separator+"info.txt"));
183            logStat.println("testNr;nrVars;nrVals;density[%];tightness[%];time[s];iters;speed[it/s];unassConstr;assigned;assigned[%]"+(mpp?";perts;perts[%]":"")+";value;totalValue");
184            logAvgStat.println("nrVars;nrVals;density[%];tightness[%];time[s];RMStime[s];iters;RMSiters;speed[it/s];unassConst;assigned;RMSassigned;assigned[%]"+(mpp?";perts;RMSperts;perts[%]":"")+";value;RMSvalue;totalValue;RMStotalValue");
185            System.out.println("Number of variables: "+nrVariablesMin+" .. "+nrVariablesMax+"  (step="+nrVariablesStep+")");
186            System.out.println("Density:             "+densityMin+" .. "+densityMax+"  (step="+densityStep+")");
187            System.out.println("Tightness:           "+tightnessMin+" .. "+tightnessMax+"  (step="+tightnessStep+")");
188            for (int nrVariables=nrVariablesMin;nrVariables<=nrVariablesMax;nrVariables+=nrVariablesStep) {
189                if (nrValuesRatio>0.0) nrValues = (int)Math.round(nrValuesRatio*nrVariables);
190                for (float density=densityMin;density<=densityMax;density+=densityStep) {
191                    for (float tightness=tightnessMin;tightness<=tightnessMax;tightness+=tightnessStep) {
192                        log.println("CSP{#Var="+nrVariables+", #Val="+nrValues+", P(density)="+sDoubleFormat.format(100.0*density)+"%, P(tighness)="+sDoubleFormat.format(100.0*tightness)+", "+nrKernels+"x Kernel{#Var="+nrKernelVariables+", P(density)="+sDoubleFormat.format(100.0*kernelDensity)+"%, P(tighness)="+sDoubleFormat.format(100.0*kernelTightness)+"%}}");
193                        double sumTime = 0;
194                        double sumTime2 = 0;
195                        int sumIters = 0;
196                        int sumIters2 = 0;
197                        int sumConfl = 0;
198                        int sumAssign = 0;
199                        int sumAssign2 = 0;
200                        int sumPert = 0;
201                        int sumPert2 = 0;
202                        int sumVal = 0;
203                        int sumVal2 = 0;
204                        int sumTotalVal = 0;
205                        int sumTotalVal2 = 0;
206                        double sumAssignPer = 0;
207                        double sumPertPer = 0;
208                        for (int test=1;test<=nrTests;test++) {
209                            log.println("  "+test+". test");
210                            log.flush();
211                            properties.setProperty("CSP.NrVariables", String.valueOf(nrVariables));
212                            properties.setProperty("CSP.Tightness", String.valueOf(tightness));
213                            properties.setProperty("CSP.Density", String.valueOf(density));
214                            
215                            long currentSeed = (seed*1000000L) + (1000 * (long)((sameProblemStep?densityMin:density)*1000.0)) + ((long)((sameProblemStep?tightnessMin:tightness)*1000.0));
216                            currentSeed = (currentSeed*nrTests) + (sameProblemTest?0:test-1);
217    
218                            sLogger.debug("Seed: "+currentSeed);
219                            StructuredCSPModel csp = new StructuredCSPModel(properties, currentSeed);
220                            
221                            Solver s = new Solver(properties);
222                            s.setInitalSolution(csp);
223                            s.currentSolution().clearBest();
224                            s.start();
225    
226                            try {
227                                s.getSolverThread().join();
228                            } catch (NullPointerException npe) {}
229                            
230                            if (s.lastSolution().getBestInfo()==null) sLogger.error("No solution found :-(");
231                            sLogger.debug("Last solution:"+s.lastSolution().getInfo());
232                            Solution best = s.lastSolution();
233                            sLogger.debug("Best solution:"+s.lastSolution().getBestInfo());
234                            best.restoreBest();
235                            int val = 0;
236                            for (Enumeration iv = best.getModel().assignedVariables().elements(); iv.hasMoreElements();)
237                                val += ((Variable)iv.nextElement()).getAssignment().toInt();
238                            int totalVal = val + (best.getModel().unassignedVariables().size()*nrValues);
239                            sLogger.debug("Last solution:"+best.getInfo());
240                            logStat.println(test+";"+nrVariables+";"+nrValues+";"+sDoubleFormat.format(density)+";"+sDoubleFormat.format(tightness)+";"+ sDoubleFormat.format(best.getTime())+";"+best.getIteration()+";"+sDoubleFormat.format(((double)best.getIteration())/best.getTime())+";"+best.getModel().unassignedHardConstraints().size()+";"+best.getModel().assignedVariables().size()+";"+sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size() / best.getModel().variables().size())+ (mpp?";"+(best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size())+";"+sDoubleFormat.format(100.0 * (best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size()) / best.getModel().variables().size()):"")+";"+val+";"+totalVal);
241                            log.println("    seed:         "+currentSeed);
242                            log.println("    constraints:  "+best.getModel().constraints().size());
243                            for (Enumeration i=best.getModel().constraints().elements();i.hasMoreElements();) {
244                                CSPBinaryConstraint c = (CSPBinaryConstraint)i.nextElement();
245                                log.println("      "+c.getName()+" ("+c.first().getName()+","+c.second().getName()+")");
246                                for (Enumeration a=c.first().values().elements();a.hasMoreElements();) {
247                                    Value v0 = (Value)a.nextElement();
248                                    log.print("        ");
249                                    for (Enumeration b=c.second().values().elements();b.hasMoreElements();) {
250                                        Value v1 = (Value)b.nextElement();
251                                        log.print(c.isConsistent(v0,v1)?"1 ":"0 ");
252                                    }
253                                    log.println();
254                                }
255                            }
256                            log.println("    time:         "+sDoubleFormat.format(best.getTime())+" s");
257                            log.println("    iteration:    "+best.getIteration());
258                            log.println("    speed:        "+sDoubleFormat.format(((double)best.getIteration())/best.getTime())+" it/s");
259                            log.println("    assigned:     "+best.getModel().assignedVariables().size()+" ("+sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size() / best.getModel().variables().size())+"%)");
260                            log.println("    total value:  "+val);
261                            if (mpp) log.println("    perturbations:"+(best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size())+" ("+sDoubleFormat.format(100.0 * (best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size()) / best.getModel().variables().size())+"%)");
262                            log.print("    solution:     ");
263                            for (Enumeration i=best.getModel().variables().elements();i.hasMoreElements();) {
264                                CSPVariable v = (CSPVariable)i.nextElement();
265                                if (v.getBestAssignment()==null) continue;
266                                log.print(v.getName()+"="+v.getBestAssignment().getName());
267                                if (i.hasMoreElements()) log.print(", ");
268                            }
269                            log.println();
270                            sumTime += best.getTime();
271                            sumTime2 += best.getTime()*best.getTime();
272                            sumIters += best.getIteration();
273                            sumIters2 += best.getIteration()*best.getIteration();
274                            sumConfl += best.getModel().unassignedHardConstraints().size();
275                            sumAssign += best.getModel().assignedVariables().size();
276                            sumAssign2 += best.getModel().assignedVariables().size()*best.getModel().assignedVariables().size();
277                            sumAssignPer += 100.0*((double)best.getModel().assignedVariables().size()/((double)best.getModel().variables().size()));
278                            sumVal += val;
279                            sumVal2 += val * val;
280                            sumTotalVal += totalVal;
281                            sumTotalVal2 += totalVal * totalVal;
282                            if (mpp) {
283                                sumPert += (best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size());
284                                sumPert2 += (best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size())*(best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size());
285                                sumPertPer += 100.0 * (best.getModel().perturbVariables().size()+best.getModel().unassignedVariables().size()) / best.getModel().variables().size();
286                            }
287                            log.flush();
288                            logStat.flush();
289                        }
290                        logAvgStat.println(nrVariables+";"+nrValues+";"+sDoubleFormat.format(density)+";"+sDoubleFormat.format(tightness)+";"+
291                        sDoubleFormat.format(sumTime/nrTests)+";"+
292                        sDoubleFormat.format(ToolBox.rms(nrTests,sumTime,sumTime2))+";"+
293                        sDoubleFormat.format(((double)sumIters)/nrTests)+";"+
294                        sDoubleFormat.format(ToolBox.rms(nrTests,(double)sumIters,(double)sumIters2))+";"+
295                        sDoubleFormat.format(((double)sumIters)/sumTime)+";"+
296                        sDoubleFormat.format(((double)sumConfl)/nrTests)+";"+
297                        sDoubleFormat.format(((double)sumAssign)/nrTests)+";"+
298                        sDoubleFormat.format(ToolBox.rms(nrTests,(double)sumAssign,(double)sumAssign2))+";"+
299                        sDoubleFormat.format(100.0*((double)sumAssign)/(nrVariables*nrTests))+
300                        (mpp?";"+
301                        sDoubleFormat.format(((double)sumPert)/nrTests)+";"+
302                        sDoubleFormat.format(ToolBox.rms(nrTests,(double)sumPert,(double)sumPert2))+";"+
303                        sDoubleFormat.format(100.0*((double)sumPert)/(nrVariables*nrTests))
304                        :"")+";"+
305                        sDoubleFormat.format(((double)sumVal)/(nrTests*nrVariables))+";"+
306                        sDoubleFormat.format(ToolBox.rms(nrTests,(double)sumVal/nrVariables,(double)sumVal2/(nrVariables*nrVariables)))+";"+
307                        sDoubleFormat.format(((double)sumTotalVal)/nrTests)+";"+
308                        sDoubleFormat.format(ToolBox.rms(nrTests,(double)sumTotalVal,(double)sumTotalVal2)));
309                        logAvgStat.flush();
310                    }
311                }
312            }
313            log.flush();
314            log.close();
315            logStat.flush();
316            logStat.close();
317            logAvgStat.flush();
318            logAvgStat.close();
319        }
320    
321        private static void test(File inputCfg, String name, String include, String regexp, String outDir) throws Exception {
322            if (regexp != null) {
323                String incFile;
324    
325                if (regexp.indexOf(';') > 0) {
326                    incFile = regexp.substring(0, regexp.indexOf(';'));
327                    regexp = regexp.substring(regexp.indexOf(';') + 1);
328                } else {
329                    incFile = regexp;
330                    regexp = null;
331                }
332                if (incFile.startsWith("[") && incFile.endsWith("]")) {
333                    test(inputCfg, name, include, regexp, outDir);
334                    incFile = incFile.substring(1, incFile.length() - 1);
335                }
336                if (incFile.indexOf('{') >= 0 && incFile.indexOf('}') >= 0) {
337                    String prefix = incFile.substring(0, incFile.indexOf('{'));
338                    StringTokenizer middle = new StringTokenizer(incFile.substring(incFile.indexOf('{')+1,incFile.indexOf('}')),"|");
339                    String sufix = incFile.substring(incFile.indexOf('}') + 1);
340    
341                    while (middle.hasMoreTokens()) {
342                        String m = middle.nextToken();
343    
344                        test(inputCfg, (name==null?"":name+"_")+m, (include==null?"":include+";")+prefix+m+sufix, regexp, outDir);
345                    }
346                } else {
347                    test(inputCfg, name, (include == null ? "" : include + ";") + incFile, regexp, outDir);
348                }
349            } else {
350                DataProperties properties = ToolBox.loadProperties(inputCfg);
351                StringTokenizer inc = new StringTokenizer(include, ";");
352    
353                while (inc.hasMoreTokens()) {
354                    String aFile = inc.nextToken();
355    
356                    System.out.println("  Loading included file '" + aFile+ "' ... ");
357                    FileInputStream is = null;
358    
359                    if ((new File(aFile)).exists()) {
360                        is = new FileInputStream(aFile);
361                    }
362                    if ((new File(inputCfg.getParent() + File.separator + aFile)).exists()) {
363                        is = new FileInputStream(inputCfg.getParent() + File.separator + aFile);
364                    }
365                    if (is == null) {
366                        System.err.println("Unable to find include file '" + aFile + "'.");
367                    }
368                    properties.load(is);
369                    is.close();
370                }
371                String outDirThisTest = (outDir==null?properties.getProperty("General.Output","."):outDir)+File.separator + name+File.separator+sDateFormat.format(new Date());
372                properties.setProperty("General.Output", outDirThisTest.toString());
373                System.out.println("Output folder: "+properties.getProperty("General.Output"));
374                (new File(outDirThisTest)).mkdirs();
375                ToolBox.configureLogging(outDirThisTest, null);
376                FileOutputStream fos = new FileOutputStream(outDirThisTest + File.separator + "rcsp.conf");
377    
378                properties.store(fos, "Random CSP problem configuration file");
379                fos.flush(); fos.close();
380                test(properties);
381            }
382        }
383        
384        public static void main(String[] args) {
385            try {
386                Progress.getInstance().addProgressListener(new ProgressWriter(System.out));
387                File inputCfg = new File(args[0]);
388                DataProperties properties = ToolBox.loadProperties(inputCfg);
389                if (properties.getProperty("INCLUDE_REGEXP") != null) {
390                    test(inputCfg, null, null, properties.getProperty("INCLUDE_REGEXP"), (args.length>1?args[1]:null));
391                } else {
392                    String outDir = properties.getProperty("General.Output", ".") + File.separator + inputCfg.getName().substring(0, inputCfg.getName().lastIndexOf('.')) + File.separator + sDateFormat.format(new Date());
393                    if (args.length>1)
394                        outDir = args[1]+File.separator+(sDateFormat.format(new Date()));
395                    properties.setProperty("General.Output", outDir.toString());
396                    System.out.println("Output folder: "+properties.getProperty("General.Output"));
397                    (new File(outDir)).mkdirs();
398                    ToolBox.configureLogging(outDir, null);
399                    test(properties);
400                }
401            } catch (Exception e) {
402                e.printStackTrace();
403            }
404        }
405    }