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