001package net.sf.cpsolver.ifs.example.tt; 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.Date; 010import java.util.List; 011import java.util.Locale; 012import java.util.StringTokenizer; 013 014import net.sf.cpsolver.ifs.solution.Solution; 015import net.sf.cpsolver.ifs.solver.Solver; 016import net.sf.cpsolver.ifs.util.DataProperties; 017import net.sf.cpsolver.ifs.util.Progress; 018import net.sf.cpsolver.ifs.util.ProgressWriter; 019import net.sf.cpsolver.ifs.util.ToolBox; 020 021/** 022 * Test 023 * 024 * @version IFS 1.2 (Iterative Forward Search)<br> 025 * Copyright (C) 2006 - 2010 Tomáš Müller<br> 026 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 027 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 028 * <br> 029 * This library is free software; you can redistribute it and/or modify 030 * it under the terms of the GNU Lesser General Public License as 031 * published by the Free Software Foundation; either version 3 of the 032 * License, or (at your option) any later version. <br> 033 * <br> 034 * This library is distributed in the hope that it will be useful, but 035 * WITHOUT ANY WARRANTY; without even the implied warranty of 036 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 037 * Lesser General Public License for more details. <br> 038 * <br> 039 * You should have received a copy of the GNU Lesser General Public 040 * License along with this library; if not see 041 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 042 */ 043public class Test { 044 private static java.text.DecimalFormat sDoubleFormat = new java.text.DecimalFormat("0.000", 045 new java.text.DecimalFormatSymbols(Locale.US)); 046 private static java.text.SimpleDateFormat sDateFormat = new java.text.SimpleDateFormat("dd-MMM-yy_HHmmss", 047 java.util.Locale.US); 048 private static org.apache.log4j.Logger sLogger = org.apache.log4j.Logger.getLogger(Test.class); 049 050 public static void test2(DataProperties properties) throws Exception { 051 int nrTests = properties.getPropertyInt("Test.NrTests", 1); 052 PrintWriter logStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator 053 + "output.csv")); 054 PrintWriter logAvgStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") 055 + File.separator + "avg_stat.csv")); 056 logStat.println("fillFact;nrResources;testNr;time[s];iters;speed[it/s];assigned;assigned[%];value;totalValue"); 057 logAvgStat 058 .println("fillFact;nrResources;time[s];RMStime[s];iters;RMSiters;speed[it/s];assigned;RMSassigned;assigned[%];value;RMSvalue"); 059 060 int nrResourcesMin = properties.getPropertyInt("Test.NrResourcesMin", -1); 061 int nrResourcesMax = properties.getPropertyInt("Test.NrResourcesMax", -1); 062 int nrResourcesStep = properties.getPropertyInt("Test.NrResourcesStep", 1); 063 double fillFactorMin = properties.getPropertyDouble("Test.FillFactorMin", -1.0); 064 double fillFactorMax = properties.getPropertyDouble("Test.FillFactorMax", -1.0); 065 double fillFactorStep = properties.getPropertyDouble("Test.FillFactorStep", 0.01); 066 067 boolean saveInit = properties.getPropertyBoolean("General.SaveInitialXML", true); 068 boolean saveSol = properties.getPropertyBoolean("General.SaveSolutionXML", true); 069 070 for (int nrResources = nrResourcesMin; nrResources <= nrResourcesMax; nrResources += nrResourcesStep) { 071 for (double fillFactor = fillFactorMin; fillFactor <= fillFactorMax; fillFactor += fillFactorStep) { 072 double sumTime = 0; 073 double sumTime2 = 0; 074 int sumIters = 0; 075 int sumIters2 = 0; 076 int sumAssign = 0; 077 int sumAssign2 = 0; 078 int sumVal = 0; 079 int sumVal2 = 0; 080 int sumVar = 0; 081 for (int test = 1; test <= nrTests; test++) { 082 if (nrResources >= 0) { 083 properties.setProperty("Generator.NrRooms", String.valueOf(nrResources)); 084 properties.setProperty("Generator.NrClasses", String.valueOf(nrResources)); 085 properties.setProperty("Generator.NrInstructors", String.valueOf(nrResources)); 086 } 087 if (fillFactor >= 0.0) { 088 properties.setProperty("Generator.FillFactor", String.valueOf(fillFactor)); 089 } 090 TimetableModel m = TimetableModel.generate(properties); 091 092 Solver<Activity, Location> s = new Solver<Activity, Location>(properties); 093 if (saveInit) 094 m.saveAsXML(properties, true, null, new File(properties.getProperty("General.Output") 095 + File.separator 096 + "SimpleTT(" 097 + (nrResources < 0 ? properties.getPropertyInt("Generator.NrRooms", 20) : nrResources) 098 + "," 099 + ((int) (100.0 * (fillFactor < 0.0 ? properties.getPropertyDouble( 100 "Generator.FillFactor", 0.8) : fillFactor) + 0.5)) + "," 101 + properties.getPropertyInt("Generator.NrDependencies", 50) + ")_" + test + ".xml")); 102 s.setInitalSolution(m); 103 s.currentSolution().clearBest(); 104 s.start(); 105 try { 106 s.getSolverThread().join(); 107 } catch (NullPointerException npe) { 108 } 109 110 if (s.lastSolution().getBestInfo() == null) 111 sLogger.error("No solution found :-("); 112 sLogger.debug("Last solution:" + s.lastSolution().getInfo()); 113 Solution<Activity, Location> best = s.lastSolution(); 114 sLogger.debug("Best solution:" + s.lastSolution().getBestInfo()); 115 best.restoreBest(); 116 int val = 0; 117 for (Activity var : ((TimetableModel) best.getModel()).assignedVariables()) 118 val += (int) var.getAssignment().toDouble(); 119 if (saveSol) 120 m 121 .saveAsXML(properties, true, best, new File(properties.getProperty("General.Output") 122 + File.separator 123 + "SimpleTT(" 124 + (nrResources < 0 ? properties.getPropertyInt("Generator.NrRooms", 20) 125 : nrResources) 126 + "," 127 + ((int) (100.0 * (fillFactor < 0.0 ? properties.getPropertyDouble( 128 "Generator.FillFactor", 0.8) : fillFactor) + 0.5)) + "," 129 + properties.getPropertyInt("Generator.NrDependencies", 50) + ")_" + test 130 + "_sol.xml")); 131 sLogger.debug("Last solution:" + best.getInfo()); 132 logStat.println(sDoubleFormat.format(properties.getPropertyDouble("Generator.FillFactor", 0.0)) 133 + ";" 134 + sDoubleFormat.format(properties.getPropertyInt("Generator.NrRooms", 0)) 135 + ";" 136 + test 137 + ";" 138 + sDoubleFormat.format(best.getTime()) 139 + ";" 140 + best.getIteration() 141 + ";" 142 + sDoubleFormat.format((best.getIteration()) / best.getTime()) 143 + ";" 144 + best.getModel().assignedVariables().size() 145 + ";" 146 + sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size() 147 / best.getModel().variables().size()) + ";" + val); 148 sLogger.debug(" time: " + sDoubleFormat.format(best.getTime()) + " s"); 149 sLogger.debug(" iteration: " + best.getIteration()); 150 sLogger.debug(" speed: " + sDoubleFormat.format((best.getIteration()) / best.getTime()) 151 + " it/s"); 152 sLogger.debug(" assigned: " 153 + best.getModel().assignedVariables().size() 154 + " (" 155 + sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size() 156 / best.getModel().variables().size()) + "%)"); 157 sLogger.debug(" value: " + val); 158 sumTime += best.getTime(); 159 sumTime2 += best.getTime() * best.getTime(); 160 sumIters += best.getIteration(); 161 sumIters2 += best.getIteration() * best.getIteration(); 162 sumAssign += best.getModel().assignedVariables().size(); 163 sumAssign2 += best.getModel().assignedVariables().size() 164 * best.getModel().assignedVariables().size(); 165 sumVal += val; 166 sumVal2 += val * val; 167 sumVar += m.variables().size(); 168 logStat.flush(); 169 } 170 logAvgStat.println(sDoubleFormat.format(properties.getPropertyDouble("Generator.FillFactor", 0.0)) 171 + ";" + sDoubleFormat.format(properties.getPropertyInt("Generator.NrRooms", 0)) + ";" 172 + sDoubleFormat.format(sumTime / nrTests) + ";" 173 + sDoubleFormat.format(ToolBox.rms(nrTests, sumTime, sumTime2)) + ";" 174 + sDoubleFormat.format(((double) sumIters) / nrTests) + ";" 175 + sDoubleFormat.format(ToolBox.rms(nrTests, sumIters, sumIters2)) + ";" 176 + sDoubleFormat.format((sumIters) / sumTime) + ";" 177 + sDoubleFormat.format(((double) sumAssign) / nrTests) + ";" 178 + sDoubleFormat.format(ToolBox.rms(nrTests, sumAssign, sumAssign2)) + ";" 179 + sDoubleFormat.format(100.0 * (sumAssign) / sumVar) + ";" 180 + sDoubleFormat.format(((double) sumVal) / nrTests) + ";" 181 + sDoubleFormat.format(ToolBox.rms(nrTests, sumVal, sumVal2))); 182 logAvgStat.flush(); 183 } 184 } 185 logStat.close(); 186 logAvgStat.close(); 187 } 188 189 public static void test3(DataProperties properties, File xmlFile) throws Exception { 190 int nrTests = properties.getPropertyInt("Test.NrTests", 1); 191 PrintWriter logStat = new PrintWriter(new FileWriter(properties.getProperty("General.Output") + File.separator 192 + "output.csv")); 193 logStat.println("fillFact;nrResources;testNr;time[s];iters;speed[it/s];assigned;assigned[%];value;totalValue"); 194 195 boolean saveSol = properties.getPropertyBoolean("General.SaveSolutionXML", true); 196 boolean assign = properties.getPropertyBoolean("General.InitialAssignment", true); 197 int forcedPerturbances = properties.getPropertyInt("General.ForcedPerturbances", 0); 198 199 for (int test = 1; test <= nrTests; test++) { 200 TimetableModel m = TimetableModel.loadFromXML(xmlFile, assign); 201 202 if (forcedPerturbances > 0) { 203 List<Activity> initialVariables = new ArrayList<Activity>(); 204 for (Activity v : m.variables()) { 205 if (v.getInitialAssignment() != null) 206 initialVariables.add(v); 207 } 208 for (int i = 0; i < forcedPerturbances; i++) { 209 if (initialVariables.isEmpty()) 210 break; 211 Activity var = ToolBox.random(initialVariables); 212 initialVariables.remove(var); 213 var.removeInitialValue(); 214 } 215 } 216 217 Solver<Activity, Location> s = new Solver<Activity, Location>(properties); 218 s.setInitalSolution(m); 219 s.currentSolution().clearBest(); 220 s.start(); 221 try { 222 s.getSolverThread().join(); 223 } catch (NullPointerException npe) { 224 } 225 226 if (s.lastSolution().getBestInfo() == null) 227 sLogger.error("No solution found :-("); 228 sLogger.debug("Last solution:" + s.lastSolution().getInfo()); 229 Solution<Activity, Location> best = s.lastSolution(); 230 sLogger.debug("Best solution:" + s.lastSolution().getBestInfo()); 231 best.restoreBest(); 232 int val = 0; 233 for (Activity var : ((TimetableModel) best.getModel()).assignedVariables()) 234 val += (int) var.getAssignment().toDouble(); 235 if (saveSol) 236 m.saveAsXML(properties, false, best, new File(properties.getProperty("General.Output") + File.separator 237 + "solution_" + test + ".xml")); 238 sLogger.debug("Last solution:" + best.getInfo()); 239 logStat.println(sDoubleFormat.format(properties.getPropertyDouble("Generator.FillFactor", 0.0)) 240 + ";" 241 + sDoubleFormat.format(properties.getPropertyInt("Generator.NrRooms", 0)) 242 + ";" 243 + test 244 + ";" 245 + sDoubleFormat.format(best.getTime()) 246 + ";" 247 + best.getIteration() 248 + ";" 249 + sDoubleFormat.format((best.getIteration()) / best.getTime()) 250 + ";" 251 + best.getModel().assignedVariables().size() 252 + ";" 253 + sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size() 254 / best.getModel().variables().size()) + ";" + val); 255 sLogger.debug(" time: " + sDoubleFormat.format(best.getTime()) + " s"); 256 sLogger.debug(" iteration: " + best.getIteration()); 257 sLogger 258 .debug(" speed: " + sDoubleFormat.format((best.getIteration()) / best.getTime()) 259 + " it/s"); 260 sLogger.debug(" assigned: " 261 + best.getModel().assignedVariables().size() 262 + " (" 263 + sDoubleFormat.format(100.0 * best.getModel().assignedVariables().size() 264 / best.getModel().variables().size()) + "%)"); 265 sLogger.debug(" value: " + val); 266 logStat.flush(); 267 } 268 logStat.close(); 269 } 270 271 public static void test(File inputCfg, String name, String include, String regexp, String outDir) throws Exception { 272 if (regexp != null) { 273 String incFile; 274 275 if (regexp.indexOf(';') > 0) { 276 incFile = regexp.substring(0, regexp.indexOf(';')); 277 regexp = regexp.substring(regexp.indexOf(';') + 1); 278 } else { 279 incFile = regexp; 280 regexp = null; 281 } 282 if (incFile.startsWith("[") && incFile.endsWith("]")) { 283 test(inputCfg, name, include, regexp, outDir); 284 incFile = incFile.substring(1, incFile.length() - 1); 285 } 286 if (incFile.indexOf('{') >= 0 && incFile.indexOf('}') >= 0) { 287 String prefix = incFile.substring(0, incFile.indexOf('{')); 288 StringTokenizer middle = new StringTokenizer(incFile.substring(incFile.indexOf('{') + 1, incFile 289 .indexOf('}')), "|"); 290 String sufix = incFile.substring(incFile.indexOf('}') + 1); 291 292 while (middle.hasMoreTokens()) { 293 String m = middle.nextToken(); 294 295 test(inputCfg, (name == null ? "" : name + "_") + m, (include == null ? "" : include + ";") 296 + prefix + m + sufix, regexp, outDir); 297 } 298 } else { 299 test(inputCfg, name, (include == null ? "" : include + ";") + incFile, regexp, outDir); 300 } 301 } else { 302 DataProperties properties = ToolBox.loadProperties(inputCfg); 303 StringTokenizer inc = new StringTokenizer(include, ";"); 304 305 while (inc.hasMoreTokens()) { 306 String aFile = inc.nextToken(); 307 308 System.out.println(" Loading included file '" + aFile + "' ... "); 309 FileInputStream is = null; 310 311 if ((new File(aFile)).exists()) { 312 is = new FileInputStream(aFile); 313 } 314 if ((new File(inputCfg.getParent() + File.separator + aFile)).exists()) { 315 is = new FileInputStream(inputCfg.getParent() + File.separator + aFile); 316 } 317 if (is == null) { 318 System.err.println("Unable to find include file '" + aFile + "'."); 319 } 320 properties.load(is); 321 is.close(); 322 } 323 String outDirThisTest = (outDir == null ? properties.getProperty("General.Output", ".") : outDir) 324 + File.separator + name + File.separator + sDateFormat.format(new Date()); 325 properties.setProperty("General.Output", outDirThisTest.toString()); 326 System.out.println("Output folder: " + properties.getProperty("General.Output")); 327 (new File(outDirThisTest)).mkdirs(); 328 ToolBox.configureLogging(outDirThisTest, null); 329 FileOutputStream fos = new FileOutputStream(outDirThisTest + File.separator + "rcsp.conf"); 330 331 properties.store(fos, "Random CSP problem configuration file"); 332 fos.flush(); 333 fos.close(); 334 test2(properties); 335 } 336 } 337 338 public static void main(String[] args) { 339 try { 340 Progress.getInstance().addProgressListener(new ProgressWriter(System.out)); 341 File inputCfg = new File(args[0]); 342 DataProperties properties = ToolBox.loadProperties(inputCfg); 343 if (args.length == 3) { 344 File xmlFile = new File(args[1]); 345 String outDir = args[2] + File.separator + (sDateFormat.format(new Date())); 346 properties.setProperty("General.Output", outDir.toString()); 347 System.out.println("Input file: " + xmlFile); 348 System.out.println("Output folder: " + properties.getProperty("General.Output")); 349 (new File(outDir)).mkdirs(); 350 ToolBox.configureLogging(outDir, null); 351 test3(properties, xmlFile); 352 } else if (properties.getProperty("INCLUDE_REGEXP") != null) { 353 test(inputCfg, null, null, properties.getProperty("INCLUDE_REGEXP"), (args.length > 1 ? args[1] : null)); 354 } else { 355 String outDir = properties.getProperty("General.Output", ".") + File.separator 356 + inputCfg.getName().substring(0, inputCfg.getName().lastIndexOf('.')) + File.separator 357 + sDateFormat.format(new Date()); 358 if (args.length > 1) 359 outDir = args[1] + File.separator + (sDateFormat.format(new Date())); 360 properties.setProperty("General.Output", outDir.toString()); 361 System.out.println("Output folder: " + properties.getProperty("General.Output")); 362 (new File(outDir)).mkdirs(); 363 ToolBox.configureLogging(outDir, null); 364 test2(properties); 365 } 366 } catch (Exception e) { 367 e.printStackTrace(); 368 } 369 } 370}