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