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