001    package net.sf.cpsolver.ifs.example.rpp;
002    
003    import java.io.*;
004    import java.util.*;
005    
006    import net.sf.cpsolver.ifs.model.*;
007    import net.sf.cpsolver.ifs.solution.*;
008    import net.sf.cpsolver.ifs.solver.*;
009    import net.sf.cpsolver.ifs.util.*;
010    
011    /**
012     * RPP test.  It takes one argument -- property file with all the parameters.
013     * It allows to execute given number of tests. The problem is loaded from prolog-based text files.
014     * For description of RPP problem see {@link RPPModel}.
015     * <br><br>
016     * Description of the input problem files can be found at <a href='http://www.fi.muni.cz/~hanka/rpp/instances.html'>http://www.fi.muni.cz/~hanka/rpp/instances.html</a>. Each input problem (e.g., gen22.pl) has the following structure:<ul><code>
017     * objects([<br>
018     * &nbsp;&nbsp;object(<br>
019     * &nbsp;&nbsp;&nbsp;&nbsp;name( rect1 ),<br>
020     * &nbsp;&nbsp;&nbsp;&nbsp;size( [ 2, 1 ] ),<br>
021     * &nbsp;&nbsp;&nbsp;&nbsp;valid_positions( [ 0-38, 0-13 ] )<br>
022     * &nbsp;&nbsp;),<br>
023     * &nbsp;&nbsp;object(<br>
024     * &nbsp;&nbsp;&nbsp;&nbsp;name( rect2 ),<br>
025     * &nbsp;&nbsp;&nbsp;&nbsp;size( [ 2, 1 ] ),<br>
026     * &nbsp;&nbsp;&nbsp;&nbsp;valid_positions( [ 0-38, 0-13 ] )<br>
027     * &nbsp;&nbsp;), <br>
028     * ... <br>
029     * &nbsp;&nbsp;object(<br>
030     * &nbsp;&nbsp;&nbsp;&nbsp;name( rect200 ),<br>
031     * &nbsp;&nbsp;&nbsp;&nbsp;size( [ 2, 1 ] ),<br>
032     * &nbsp;&nbsp;&nbsp;&nbsp;valid_positions( [ 0-38, 7-13 ] )<br>
033     * &nbsp;&nbsp;)<br>
034     * ] ). <br>
035     * </code></ul>
036     * Stating that the first rectangle (named rect1) has size 2x1 and its valid position are with x between 0 and 38, y between 0 and 13, and so on.
037     * <br>
038     * MPP instances contain an extra file with the solution (e.g., gen22.solution), with the following structure<ul><code>
039     * assigned([[rect1X,[17]], [rect1Y,[5]], [rect2X,[24]], [rect2Y,[4]], ... [rect200X,[37]], [rect200Y,[10]]]).
040     * </code></ul>
041     * Which means that the first rectangle (named rect1) is to be placed at [17,5], second at [24,4] and so on.
042     * <br>
043     * There is also a file (e.g., gen22.mpp) describing which input placements are to be prohibited (not that if the input placement is prohibited, it means that also all values with the same X or Y coordinate are prohibited). It has the following structure:<ul><code>
044     * perturbation( 1, 0, [] ).<br>
045     * perturbation( 2, 0, [] ).<br> 
046     * ...<br>
047     * perturbation( 1, 2, [44,127] ).<br>
048     * perturbation( 2, 2, [80,153] ).<br>
049     * ...<br>
050     * perturbation( 1, 4, [44,80,127,153] ).<br>
051     * perturbation( 2, 4, [48,67,138,170] ). <br>
052     * ...<br>
053     * </code></ul>
054     * Stating that for instance in the first test with 4 perturbations the rectangles rect44, rect80, rect127 and rect153 will have their initial value prohibited.
055     * <br><br>
056     * Test's parameters:
057     * <br>
058     * <table border='1'><tr><th>Parameter</th><th>Type</th><th>Comment</th></tr>
059     * <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>
060     * <tr><td>RPP.NrTests</td><td>{@link Integer}</td><td>Number of tests to be executed for each input instance</td></tr>
061     * <tr><td>Rpp.Min<br>Rpp.Max<br>Rpp.Step</td><td>{@link Integer}</td><td>In case of MPP: minimal, maximal number and increment of input perturbations. An instance is loaded and tested for each given number of input perturbations.</td></tr>
062     * <tr><td>Rpp.Min<br>Rpp.Max</td><td>{@link Integer}</td><td>In case of initial problem: minimal and maximal number of the input problem. An instance is loaded and tested for each given number from RPP.Min to RPP.Max.</td></tr>
063     * <tr><td>Rpp.ProblemWidth<br>Rpp.ProblemHeight</td><td>{@link Integer}</td><td>Width and height of the placement area.</td></tr>
064     * <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>
065     * </table>
066     * <br><br>
067     * 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>
068     * <code>INCLUDE_REGEXP=general.ini;{rpp85|rpp90|rpp95|mpp22}.ini;{5min}.ini;{cbs|rw1|tabu20}.ini</code><br>
069     * </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>
070     * <li>general.ini;rpp85.ini;5min.ini;cbs.ini
071     * <li>general.ini;rpp85.ini;5min.ini;rw1.ini
072     * <li>general.ini;rpp85.ini;5min.ini;tabu20.ini
073     * <li>general.ini;rpp90.ini;5min.ini;cbs.ini
074     * <li>general.ini;rpp90.ini;5min.ini;rw1.ini
075     * <li>general.ini;rpp90.ini;5min.ini;tabu20.ini
076     * <li>general.ini;rpp95.ini;5min.ini;cbs.ini
077     * <li>general.ini;rpp95.ini;5min.ini;rw1.ini
078     * <li>general.ini;rpp95.ini;5min.ini;tabu20.ini
079     * <li>general.ini;mpp22.ini;5min.ini;cbs.ini
080     * <li>general.ini;mpp22.ini;5min.ini;rw1.ini
081     * <li>general.ini;mpp22.ini;5min.ini;tabu20.ini
082     * </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.
083     * So, for instance the first bunch of tests will output into the folder:<ul>
084     * ${General.Output}\rpp85_5min_csb\25-Feb-05_191136
085     * </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.
086     * <br><br>
087     * An example of the configurations:<br>
088     * File<b> general.ini</b><ul><code>
089     * #Default settings common for all configurations<br>
090     * General.MPP=false<br>
091     * General.InitialAssignment=false<br>
092     * General.Output=output\\RPP\\IFS<br>
093     * <br>
094     * #Value selection heuristics<br>
095     * Value.Class=net.sf.cpsolver.ifs.heuristics.GeneralValueSelection<br>
096     * Value.WeightWeightedConflicts=0.0<br>
097     * Value.RandomWalkProb=0.0<br>
098     * Value.WeightConflicts=1.0<br>
099     * Value.WeightNrAssignments=0.0<br>
100     * Value.WeightValue=0.0<br>
101     * Value.Tabu=0<br>
102     * <br>
103     * #Variable selection heuristics<br>
104     * Variable.Class=net.sf.cpsolver.ifs.heuristics.GeneralVariableSelection<br>
105     * Variable.RandomSelection=true<br>
106     * <br>
107     * #Termination condition<br>
108     * Termination.Class=net.sf.cpsolver.ifs.termination.GeneralTerminationCondition<br>
109     * Termination.MaxIters=-1<br>
110     * Termination.TimeOut=-1<br>
111     * Termination.StopWhenComplete=true<br>
112     * <br>
113     * #Solution comparator<br>
114     * Comparator.Class=net.sf.cpsolver.ifs.solution.GeneralSolutionComparator<br>
115     * </code></ul><br>
116     * File<b> rpp80.ini</b><ul><code>
117     * #RPP instances with 200 objects and the placement area filled to 80% in average<br>
118     * General.Input=input\\rpp\\80<br>
119     * Rpp.ProblemWidth=40<br>
120     * Rpp.ProblemHeight=14<br>
121     * #Use 10 problem instances (this means problem files gen1.pl, gen2.pl,... gen10.pl will be taken), each run 10 times<br>
122     * Rpp.Min=1<br>
123     * Rpp.Max=10<br>
124     * Rpp.NrTests=10<br>
125     * </code></ul><br>
126     * File<b> mpp22.ini</b><ul><code>
127     * #RPP MPP instance 22 (with 200 objects and the placement area filled to 80% in average)<br>
128     * #  files gen22.pl (input problem), gen22.solution (initial solution) and gen22.mpp (input perturbations) are to be taken<br>
129     * General.Input=input\\rpp-mpp\\gen22<br>
130     * Rpp.ProblemWidth=40<br>
131     * Rpp.ProblemHeight=14<br>
132     * # 0, 4, 8, .. 200 input perturbations to be used<br>
133     * Rpp.Min=0<br>
134     * Rpp.Max=200<br>
135     * Rpp.Step=4<br>
136     * </code></ul><br>
137     * File<b> 5min.ini</b><ul><code>
138     * #5 minute time limit for each run<br>
139     * Termination.TimeOut=300<br>
140     * </code></ul><br>
141     * File<b> cbs.ini</b><ul><code>
142     * #Use conflict-based statistics<br>
143     * Extensions.Classes=net.sf.cpsolver.ifs.extension.ConflictStatistics<br>
144     * Value.WeightWeightedConflicts=1.0<br>
145     * </code></ul><br>
146     * File<b> tabu20.ini</b><ul><code>
147     * #Use tabu-list of the length 20<br>
148     * Value.Tabu=20<br>
149     * </code></ul><br>
150     * File<b> rw1.ini</b><ul><code>
151     * #Use 1% random walk selection<br>
152     * Value.RandomWalkProb=0.01<br>
153     * </code></ul><br>
154     *
155     * @see RPPModel
156     * @see net.sf.cpsolver.ifs.extension.ConflictStatistics
157     * @see net.sf.cpsolver.ifs.heuristics.GeneralValueSelection
158     * @see net.sf.cpsolver.ifs.heuristics.GeneralVariableSelection
159     * @see net.sf.cpsolver.ifs.termination.GeneralTerminationCondition
160     * @see net.sf.cpsolver.ifs.solution.GeneralSolutionComparator
161     *
162     * @version
163     * IFS 1.1 (Iterative Forward Search)<br>
164     * Copyright (C) 2006 Tomáš Müller<br>
165     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
166     * Lazenska 391, 76314 Zlin, Czech Republic<br>
167     * <br>
168     * This library is free software; you can redistribute it and/or
169     * modify it under the terms of the GNU Lesser General Public
170     * License as published by the Free Software Foundation; either
171     * version 2.1 of the License, or (at your option) any later version.
172     * <br><br>
173     * This library is distributed in the hope that it will be useful,
174     * but WITHOUT ANY WARRANTY; without even the implied warranty of
175     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
176     * Lesser General Public License for more details.
177     * <br><br>
178     * You should have received a copy of the GNU Lesser General Public
179     * License along with this library; if not, write to the Free Software
180     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
181     */
182    public class Test {
183        private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.00", new java.text.DecimalFormatSymbols(Locale.US));
184        private static java.text.SimpleDateFormat sDateFormat = new java.text.SimpleDateFormat("dd-MMM-yy_HHmmss", java.util.Locale.US);
185        private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Test.class);
186        
187        private static Model loadModel(int mWidth, int mHeight, Vector objects, Vector assigned, Vector perturbations, int perb, int test) {
188            try {
189                sLogger.debug("Loading model " + perb + "." + test + " ...");
190                double startTime = JProf.currentTimeSec();
191                RPPModel m = new RPPModel();
192                ResourceConstraint c = new ResourceConstraint(mWidth, mHeight);
193                m.addConstraint(c);
194                for (Enumeration e = ((PrologFile.Term) ((PrologFile.Term)objects.elementAt(0)).getContent().elementAt(0)).getContent().elements(); e.hasMoreElements();) {
195                    PrologFile.Term object = (PrologFile.Term)e.nextElement();
196                    String name = object.elementAt(0).elementAt(0).getText();
197                    int width = object.elementAt(1).elementAt(0).elementAt(0).toInt();
198                    int height = object.elementAt(1).elementAt(0).elementAt(1).toInt();
199                    String xpos = object.elementAt(2).elementAt(0).elementAt(0).getText();
200                    String ypos = object.elementAt(2).elementAt(0).elementAt(1).getText();
201                    int xmin = Integer.parseInt(xpos.substring(0, xpos.indexOf('-')));
202                    int xmax = Integer.parseInt(xpos.substring(xpos.indexOf('-') + 1));
203                    int ymin = Integer.parseInt(ypos.substring(0, ypos.indexOf('-')));
204                    int ymax = Integer.parseInt(ypos.substring(ypos.indexOf('-') + 1));
205                    Rectangle r = new Rectangle(name, width, height, xmin, xmax, ymin, ymax, null);
206                    m.addVariable(r);
207                    c.addVariable(r);
208                }
209                for (Enumeration e = ((PrologFile.Term) ((PrologFile.Term)assigned.elementAt(0)).elementAt(0)).getContent().elements(); e.hasMoreElements();) {
210                    PrologFile.Term assignment = (PrologFile.Term)e.nextElement();
211                    String name = assignment.elementAt(0).getText();
212                    name = name.substring(0, name.length() - 1);
213                    int x = assignment.elementAt(1).elementAt(0).toInt();
214                    assignment = (PrologFile.Term)e.nextElement();
215                    int y = assignment.elementAt(1).elementAt(0).toInt();
216                    m.getRectangle(name).setInitialAssignment(new Location(m.getRectangle(name), x, y));
217                }
218                for (Enumeration e = perturbations.elements(); e.hasMoreElements();) {
219                    PrologFile.Term pert = (PrologFile.Term)e.nextElement();
220                    if (test == pert.elementAt(0).toInt() && perb == pert.elementAt(1).toInt() && perb > 0) {
221                        for (Enumeration x = pert.elementAt(2).getContent().elements(); x.hasMoreElements();) {
222                            int rec = ((PrologFile.Term)x.nextElement()).toInt();
223                            m.getRectangle("rect" + rec).setProhibited();
224                        }
225                    }
226                }
227                sLogger.debug("Loaded in " + sDoubleFormat.format(JProf.currentTimeSec() - startTime) + " sec.");
228                return m;
229            }
230            catch (Exception e) {
231                e.printStackTrace();
232                return null;
233            }
234        }
235        
236        private static Model loadModel(int mWidth, int mHeight, Vector objects) {
237            try {
238                sLogger.debug("Loading model ...");
239                double startTime = JProf.currentTimeSec();
240                RPPModel m = new RPPModel();
241                ResourceConstraint c = new ResourceConstraint(mWidth, mHeight);
242                m.addConstraint(c);
243                for (Enumeration e = ((PrologFile.Term) ((PrologFile.Term)objects.elementAt(0)).getContent().elementAt(0)).getContent().elements(); e.hasMoreElements();) {
244                    PrologFile.Term object = (PrologFile.Term)e.nextElement();
245                    String name = object.elementAt(0).elementAt(0).getText();
246                    int width =object.elementAt(1).elementAt(0).elementAt(0).toInt();
247                    int height = object.elementAt(1).elementAt(0).elementAt(1).toInt();
248                    String xpos = object.elementAt(2).elementAt(0).elementAt(0).getText();
249                    String ypos = object.elementAt(2).elementAt(0).elementAt(1).getText();
250                    int xmin = Integer.parseInt(xpos.substring(0, xpos.indexOf('-')));
251                    int xmax = Integer.parseInt(xpos.substring(xpos.indexOf('-') + 1));
252                    int ymin = Integer.parseInt(ypos.substring(0, ypos.indexOf('-')));
253                    int ymax = Integer.parseInt(ypos.substring(ypos.indexOf('-') + 1));
254                    Rectangle r = new Rectangle(name, width, height, xmin, xmax, ymin, ymax, null);
255                    m.addVariable(r);
256                    c.addVariable(r);
257                }
258                sLogger.debug("Loaded in " + sDoubleFormat.format(JProf.currentTimeSec() - startTime) + " sec.");
259                return m;
260            }
261            catch (Exception e) {
262                e.printStackTrace();
263                return null;
264            }
265        }
266        
267        private static void testMPP(DataProperties properties) {
268            try {
269                FileInputStream fis = new FileInputStream(properties.getProperty("General.Input") + ".pl");
270                Vector v1 = PrologFile.readTermsFromStream(fis, "objects");
271                fis.close();
272                fis = new FileInputStream(properties.getProperty("General.Input") + ".solution");
273                Vector v2 = PrologFile.readTermsFromStream(fis, "assigned");
274                fis.close();
275                fis = new FileInputStream(properties.getProperty("General.Input") + ".mpp");
276                Vector v3 = PrologFile.readTermsFromStream(fis, "perturbation");
277                fis.close();
278                
279                PrintWriter res = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "result.pl"));
280                PrintWriter stat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "stat.pl"));
281                PrintWriter txt = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "stat.csv"));
282                txt.println("pert;time[s];timeRMS;assigned;assignedRMS;perturbations;perturbationsRMS;iters;itersRMS");
283                java.text.DecimalFormat nf = new java.text.DecimalFormat("0.000", new java.text.DecimalFormatSymbols(Locale.US));
284                int size = -1; //gen80_22_initial().getRectangles().size();
285                int tests = properties.getPropertyInt("Rpp.NrTests", 10);
286                int step = properties.getPropertyInt("Rpp.Step", 4);
287                int min = properties.getPropertyInt("Rpp.Min", 0);
288                int max = properties.getPropertyInt("Rpp.Max", -1);
289                for (int i = min; size == -1 || i <= (max > 0 ? Math.min(max, size) : size); i += step) {
290                    double time = 0;
291                    long assigned = 0;
292                    long perturbation = 0;
293                    long iters = 0;
294                    double time2 = 0;
295                    long assigned2 = 0;
296                    long perturbation2 = 0;
297                    long iters2 = 0;
298                    for (int t = 1; t <= tests; t++) {
299                        Model m = loadModel(properties.getPropertyInt("Rpp.ProblemWidth", 40), properties.getPropertyInt("Rpp.ProblemHeight", 14), v1, v2, v3, i, t);
300                        if (size < 0) size = m.variables().size();
301                        Solver s = new Solver(properties);
302                        s.setInitalSolution(m);
303                        s.start();
304                        s.getSolverThread().join();
305                        Solution best = s.currentSolution();
306                        best.restoreBest();
307                        res.println("result(" + t + "," + i + "," + nf.format(best.getBestTime()) + "," + (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables()) + "," + best.getBestIteration() + ",");
308                        EnumerableCollection notPlaced = best.getModel().bestUnassignedVariables();
309                        if (notPlaced == null)
310                            notPlaced = new FastVector();
311                        res.print("  unassigned(" + (2 * notPlaced.size()) + "/[");
312                        for (Enumeration it = notPlaced.elements(); it.hasMoreElements();) {
313                            Rectangle rect = (Rectangle)it.nextElement();
314                            res.print(rect.getName() + "X," + rect.getName() + "Y" + (it.hasMoreElements() ? "," : ""));
315                        }
316                        res.println("]),");
317                        StringBuffer sb = new StringBuffer();
318                        int perts = 0;
319                        for (Enumeration it = best.getModel().variables().elements(); it.hasMoreElements();) {
320                            Rectangle rect = (Rectangle)it.nextElement();
321                            if (rect.getBestAssignment() != null && (rect.getInitialAssignment() == null || !rect.getBestAssignment().equals(
322                            rect.getInitialAssignment()))) {
323                                sb.append(sb.length() == 0 ? "" : ",");
324                                sb.append(rect.getName() + "X-" + ((Location)rect.getBestAssignment()).getX());
325                                sb.append(sb.length() == 0 ? "" : ",");
326                                sb.append(rect.getName() + "Y-" + ((Location)rect.getBestAssignment()).getY());
327                                perts++;
328                            }
329                            if (rect.getBestAssignment() == null) {
330                                perts++;
331                            }
332                        }
333                        res.println("  perturbations(" + (2 * perts) + "/[" + sb + "])");
334                        res.println(").");
335                        res.flush();
336                        iters += best.getBestIteration();
337                        iters2 += (best.getBestIteration() * best.getBestIteration());
338                        time += best.getBestTime();
339                        time2 += (best.getBestTime() * best.getBestTime());
340                        assigned += (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables());
341                        assigned2 += (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables()) * (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables());
342                        perturbation += perts;
343                        perturbation2 += perts * perts;
344                    }
345                    txt.println(i + ";" + nf.format(time / tests) + ";" + nf.format(ToolBox.rms(tests, time, time2)) + ";" + nf.format(((double)assigned) / tests) + ";" + 
346                        nf.format(ToolBox.rms(tests, (double)assigned, (double)assigned2)) + ";" + 
347                        nf.format(((double)perturbation) / tests) + ";" + 
348                        nf.format(ToolBox.rms(tests, (double)perturbation, (double)perturbation2)) + ";" +
349                        nf.format(((double)iters) / tests) + ";" + 
350                        nf.format(ToolBox.rms(tests, (double)iters, (double)iters2)));
351                    txt.flush();
352                    stat.println("averages( initperturbations( " + i + " ), time( " +  nf.format(time / tests)+ " ), assigned( " + 
353                        nf.format(((double)assigned) / tests) + " ), perturbations( " + nf.format(((double)perturbation) / tests) + " ) ).");
354                    stat.println("deviations( initperturbations( " + i + " ), time( " + 
355                        nf.format(ToolBox.rms(tests, (double)time, (double)time2)) + " ), assigned( " + 
356                        nf.format(ToolBox.rms(tests, (double)assigned, (double)assigned2)) + " ), perturbations( " + 
357                        nf.format(ToolBox.rms(tests, (double)perturbation, (double)perturbation2)) + " ) ).");
358                    stat.flush();
359                }
360                res.close();
361                txt.close();
362                stat.close();
363            }
364            catch (Exception e) {
365                e.printStackTrace();
366            }
367        }
368        
369        private static void test(DataProperties properties) {
370            try {
371                int tests = properties.getPropertyInt("Rpp.NrTests", 10);
372                int min = properties.getPropertyInt("Rpp.Min", 0);
373                int max = properties.getPropertyInt("Rpp.Max", -1);
374                PrintWriter res = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "result.pl"));
375                PrintWriter stat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "stat.pl"));
376                PrintWriter txt = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator + "stat.csv"));
377                txt.println("gen;time[s];timeRMS;assigned;assignedRMS;iters;itersRMS");
378                java.text.DecimalFormat nf = new java.text.DecimalFormat("0.000", new java.text.DecimalFormatSymbols(Locale.US));
379                for (int genNr = min; genNr <= max; genNr++) {
380                    FileInputStream fis = new FileInputStream(properties.getProperty("General.Input") + File.separator + "gen" + genNr + ".pl");
381                    Vector v1 = PrologFile.readTermsFromStream(fis, "objects");
382                    fis.close();
383                    double time = 0;
384                    long assigned = 0;
385                    long iters = 0;
386                    double time2 = 0;
387                    long assigned2 = 0;
388                    long iters2 = 0;
389                    for (int t = 1; t <= tests; t++) {
390                        Model m = loadModel(properties.getPropertyInt("Rpp.ProblemWidth", 40), properties.getPropertyInt("Rpp.ProblemHeight", 14), v1);
391                        Solver s = new Solver(properties);
392                        s.setInitalSolution(m);
393                        s.start();
394                        s.getSolverThread().join();
395                        Solution best = s.currentSolution();
396                        best.restoreBest();
397                        iters += best.getBestIteration();
398                        iters2 += (best.getBestIteration() * best.getBestIteration());
399                        time += best.getBestTime();
400                        time2 += (best.getBestTime() * best.getBestTime());
401                        assigned += (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables());
402                        assigned2 += (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables()) * (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables());
403                        res.println("result(" + genNr + ","+t+"," + nf.format(best.getBestTime()) + "," + (best.getModel().variables().size() - best.getModel().getBestUnassignedVariables()) + "," + best.getBestIteration() + ",");
404                        EnumerableCollection notPlaced = best.getModel().bestUnassignedVariables();
405                        if (notPlaced == null)
406                            notPlaced = new FastVector();
407                        res.print("  unassigned(" + (2 * notPlaced.size()) + "/[");
408                        for (Enumeration it = notPlaced.elements(); it.hasMoreElements();) {
409                            Rectangle rect = (Rectangle)it.nextElement();
410                            res.print(rect.getName() + "X," + rect.getName() + "Y" + (it.hasMoreElements() ? "," : ""));
411                        }
412                        res.println("]),");
413                        int perts = 0;
414                        StringBuffer sb = new StringBuffer();
415                        for (Enumeration it = best.getModel().variables().elements(); it.hasMoreElements();) {
416                            Rectangle rect = (Rectangle)it.nextElement();
417                            if (rect.getBestAssignment() != null) {
418                                sb.append(sb.length() == 0 ? "" : ",");
419                                sb.append(rect.getName() + "X-" + ((Location)rect.getBestAssignment()).getX());
420                                sb.append(sb.length() == 0 ? "" : ",");
421                                sb.append(rect.getName() + "Y-" + ((Location)rect.getBestAssignment()).getY());
422                                perts++;
423                            }
424                        }
425                        res.println("  assigned(" + (2 * perts) + "/[" + sb + "])");
426                        res.println(").");
427                        res.flush();
428                    }
429                    txt.println(genNr + ";" + nf.format(time / tests) + ";" + nf.format(ToolBox.rms(tests, time, time2)) + ";" + nf.format(((double)assigned) / tests) + ";" + 
430                        nf.format(ToolBox.rms(tests, (double)assigned, (double)assigned2)) + ";" + 
431                        nf.format(((double)iters) / tests) + ";" + 
432                        nf.format(ToolBox.rms(tests, (double)iters, (double)iters2)));
433                    txt.flush();
434                    stat.println("averages( problem( " + genNr + " ), time( " +  nf.format(time / tests)+ " ), assigned( " + 
435                        nf.format(((double)assigned) / tests) + " ) ).");
436                    stat.println("deviations( problem( " + genNr + " ), time( " + 
437                        nf.format(ToolBox.rms(tests, (double)time, (double)time2)) + " ), assigned( " + 
438                        nf.format(ToolBox.rms(tests, (double)assigned, (double)assigned2)) + " ) ).");
439                    stat.flush();                    
440                }
441                res.close();
442                txt.close();
443                stat.close();
444            }
445            catch (Exception e) {
446                e.printStackTrace();
447            }
448        }
449        
450        private static void test(File inputCfg, String name, String include, String regexp, String outDir) throws Exception {
451            if (regexp != null) {
452                String incFile;
453                if (regexp.indexOf(';') > 0) {
454                    incFile = regexp.substring(0, regexp.indexOf(';'));
455                    regexp = regexp.substring(regexp.indexOf(';') + 1);
456                }
457                else {
458                    incFile = regexp;
459                    regexp = null;
460                }
461                if (incFile.startsWith("[") && incFile.endsWith("]")) {
462                    test(inputCfg, name, include, regexp, outDir);
463                    incFile = incFile.substring(1, incFile.length() - 1);
464                }
465                if (incFile.indexOf('{') >= 0 && incFile.indexOf('}') >= 0) {
466                    String prefix = incFile.substring(0, incFile.indexOf('{'));
467                    StringTokenizer middle =
468                    new StringTokenizer(incFile.substring( incFile.indexOf('{') + 1, incFile.indexOf('}')), "|");
469                    String sufix = incFile.substring(incFile.indexOf('}') + 1);
470                    while (middle.hasMoreTokens()) {
471                        String m = middle.nextToken();
472                        test(inputCfg, (name == null ? "" : name + "_") + m, (include == null ? "" : include + ";") + prefix + m + sufix, regexp, outDir);
473                    }
474                }
475                else {
476                    test(inputCfg, name, (include == null ? "" : include + ";") + incFile, regexp, outDir);
477                }
478            }
479            else {
480                DataProperties properties = ToolBox.loadProperties(inputCfg);
481                StringTokenizer inc = new StringTokenizer(include, ";");
482                while (inc.hasMoreTokens()) {
483                    String aFile = inc.nextToken();
484                    System.out.println("  Loading included file '" + aFile + "' ... ");
485                    FileInputStream is = null;
486                    if ((new File(aFile)).exists())
487                        is = new FileInputStream(aFile);
488                    if ((new File(inputCfg.getParent() + File.separator + aFile)).exists())
489                        is = new FileInputStream(inputCfg.getParent() + File.separator + aFile);
490                    if (is == null)
491                        System.err.println("Unable to find include file '" + aFile + "'.");
492                    properties.load(is);
493                    is.close();
494                }
495                String outDirTisTest = (outDir==null?properties.getProperty("General.Output", "."):outDir) + File.separator + name + File.separator + sDateFormat.format(new Date());
496                properties.setProperty("General.Output", outDirTisTest.toString());
497                System.out.println("Output folder: "+properties.getProperty("General.Output"));
498                (new File(outDirTisTest)).mkdirs();
499                ToolBox.configureLogging(outDirTisTest, null);
500                FileOutputStream fos = new FileOutputStream(outDirTisTest + File.separator + "rcsp.conf");
501                properties.store(fos, "Random CSP problem configuration file");
502                fos.flush();
503                fos.close();
504                boolean mpp = properties.getPropertyBoolean("General.MPP", true);
505                if (mpp)
506                    testMPP(properties);
507                else
508                    test(properties);
509            }
510        }
511        
512        /**
513         * RPP test.
514         * @param args the command line arguments
515         */
516        public static void main(String[] args) {
517            try {
518                Progress.getInstance().addProgressListener(
519                new ProgressWriter(System.out));
520                
521                File inputCfg = new File(args[0]);
522                DataProperties properties = ToolBox.loadProperties(inputCfg);
523                if (properties.getProperty("INCLUDE_REGEXP") != null) {
524                    if (args.length>1)
525                        properties.setProperty("General.Output", args[1]);
526                    test(inputCfg, null, null, properties.getProperty("INCLUDE_REGEXP"), (args.length>1?args[1]:null));
527                } else {
528                    String outDir = properties.getProperty("General.Output", ".") + File.separator + inputCfg.getName().substring(0, inputCfg.getName().lastIndexOf('.')) + File.separator + sDateFormat.format(new Date());
529                    if (args.length>1)
530                        outDir = args[1]+File.separator+(sDateFormat.format(new Date()));
531                    (new File(outDir)).mkdirs();
532                    properties.setProperty("General.Output", outDir.toString());
533                    System.out.println("Output folder: "+properties.getProperty("General.Output"));
534                    ToolBox.configureLogging(outDir, null);
535                    boolean mpp = properties.getPropertyBoolean("General.MPP", false);
536                    if (mpp)
537                        testMPP(properties);
538                    else
539                        test(properties);
540                }
541                
542            }
543            catch (Exception e) {
544                e.printStackTrace();
545            }
546        }
547    }