No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Main.java 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package jobshop;
  2. import java.io.PrintStream;
  3. import java.nio.file.Path;
  4. import java.nio.file.Paths;
  5. import java.util.ArrayList;
  6. import java.util.Arrays;
  7. import java.util.List;
  8. import java.util.stream.Collectors;
  9. import jobshop.encodings.Schedule;
  10. import jobshop.solvers.*;
  11. import net.sourceforge.argparse4j.ArgumentParsers;
  12. import net.sourceforge.argparse4j.inf.ArgumentParser;
  13. import net.sourceforge.argparse4j.inf.ArgumentParserException;
  14. import net.sourceforge.argparse4j.inf.Namespace;
  15. /**
  16. * This class is the main entry point for doing comparative performance tests of solvers.
  17. */
  18. public class Main {
  19. public static void main(String[] args) {
  20. // configure the argument parser
  21. ArgumentParser parser = ArgumentParsers.newFor("jsp-solver").build()
  22. .defaultHelp(true)
  23. .description("Solves jobshop problems.");
  24. parser.addArgument("-t", "--timeout")
  25. .setDefault(1L)
  26. .type(Long.class)
  27. .help("Solver timeout in seconds for each instance. Default is 1 second.");
  28. parser.addArgument("--solver")
  29. .nargs("+")
  30. .required(true)
  31. .help("Solver(s) to use (space separated if more than one)");
  32. parser.addArgument("--instance")
  33. .nargs("+")
  34. .required(true)
  35. .help("Instance(s) to solve (space separated if more than one). All instances starting with the given " +
  36. "string will be selected. (e.g. \"ft\" will select the instances ft06, ft10 and ft20.");
  37. // parse command line arguments
  38. Namespace ns = null;
  39. try {
  40. ns = parser.parseArgs(args);
  41. } catch (ArgumentParserException e) {
  42. // error while parsing arguments, provide helpful error message and exit.
  43. System.err.println("Invalid arguments provided to the program.\n");
  44. System.err.println("In IntelliJ, you can provide arguments to the program by opening the dialog,");
  45. System.err.println("\"Run > Edit Configurations\" and filling in the \"program arguments\" box.");
  46. System.err.println("See the README for a documentation of the expected arguments.");
  47. System.err.println();
  48. parser.handleError(e);
  49. System.exit(0);
  50. }
  51. PrintStream output = System.out;
  52. // convert the timeout from seconds to milliseconds.
  53. long solveTimeMs = ns.getLong("timeout") * 1000;
  54. // Get the list of solvers that we should benchmark.
  55. // We also check that we have a solver available for the given name and print an error message otherwise.
  56. List<String> solversToTest = ns.getList("solver");
  57. List<Solver> solvers = solversToTest.stream().map(Solver::getSolver).collect(Collectors.toList());
  58. // retrieve all instances on which we should run the solvers.
  59. List<String> instances = new ArrayList<>();
  60. List<String> instancePrefixes = ns.getList("instance");
  61. for(String instancePrefix : instancePrefixes) {
  62. List<String> matches = BestKnownResults.instancesMatching(instancePrefix);
  63. if(matches.isEmpty()) {
  64. System.err.println("ERROR: instance prefix \"" + instancePrefix + "\" does not match any instance.");
  65. System.err.println(" available instances: " + Arrays.toString(BestKnownResults.instances));
  66. System.exit(1);
  67. }
  68. instances.addAll(matches);
  69. }
  70. // average runtime of each solver
  71. float[] avg_runtimes = new float[solversToTest.size()];
  72. // average distance to best known result for each solver
  73. float[] avg_distances = new float[solversToTest.size()];
  74. float[] avg_voisins = new float[solversToTest.size()];
  75. try {
  76. // header of the result table :
  77. // - solver names (first line)
  78. // - name of each column (second line)
  79. output.print( " ");
  80. for(String s : solversToTest)
  81. output.printf("%-38s", s);
  82. output.println();
  83. output.print("instance size best ");
  84. for(String s : solversToTest) {
  85. output.print("runtime makespan ecart voisins ");
  86. }
  87. output.println();
  88. // for all instances, load it from f
  89. for(String instanceName : instances) {
  90. // get the best known result for this instance
  91. int bestKnown = BestKnownResults.of(instanceName);
  92. // load instance from file.
  93. Path path = Paths.get("instances/", instanceName);
  94. Instance instance = Instance.fromFile(path);
  95. // print some general statistics on the instance
  96. output.printf("%-8s %-5s %4d ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown);
  97. // run all selected solvers on the instance and print the results
  98. for(int solverId = 0 ; solverId < solvers.size() ; solverId++) {
  99. // Select the next solver to run. Given the solver name passed on the command line,
  100. // we lookup the `Main.solvers` hash map to get the solver object with the given name.
  101. Solver solver = solvers.get(solverId);
  102. // start chronometer and compute deadline for the solver to provide a result.
  103. long start = System.currentTimeMillis();
  104. long deadline = System.currentTimeMillis() + solveTimeMs;
  105. // run the solver on the current instance
  106. Result result = solver.solve(instance, deadline);
  107. // measure elapsed time (in milliseconds)
  108. long runtime = System.currentTimeMillis() - start;
  109. // check that the solver returned a valid solution
  110. if(result.schedule.isEmpty() || !result.schedule.get().isValid()) {
  111. System.err.println("ERROR: solver returned an invalid schedule");
  112. System.exit(1); // bug in implementation, bail out
  113. }
  114. // we have a valid schedule
  115. Schedule schedule = result.schedule.get();
  116. // compute some statistics on the solution and print them.
  117. int makespan = schedule.makespan();
  118. float dist = 100f * (makespan - bestKnown) / (float) bestKnown;
  119. avg_runtimes[solverId] += (float) runtime / (float) instances.size();
  120. avg_distances[solverId] += dist / (float) instances.size();
  121. avg_voisins[solverId] += (float) result.getVoisinsVisites() / (float) instances.size();
  122. output.printf("%7d %8s %5.1f %7d ", runtime, makespan, dist, result.getVoisinsVisites());
  123. output.flush();
  124. }
  125. output.println();
  126. }
  127. // we have finished all benchmarks, compute the average solve time and distance of each solver.
  128. output.printf("%-8s %-5s %4s ", "AVG", "-", "-");
  129. for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) {
  130. output.printf("%7.1f %8s %5.1f %7.1f ", avg_runtimes[solverId], "-", avg_distances[solverId], avg_voisins[solverId]);
  131. }
  132. } catch (Exception e) {
  133. // there was uncaught exception, print the stack trace and exit with error.
  134. e.printStackTrace();
  135. System.exit(1);
  136. }
  137. }
  138. }