    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'><caption>Related Solver Parameters</caption>
    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 * @author  Tomáš Müller
    277 * @version IFS 1.3 (Iterative Forward Search)<br>
    278 *          Copyright (C) 2006 - 2014 Tomáš Müller<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 */
    296public 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.logging.log4j.Logger sLogger = org.apache.logging.log4j.LogManager.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(best.getAssignment());
    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(best.getAssignment());
    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}