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