diff --git a/src/main/java/jobshop/Main.java b/src/main/java/jobshop/Main.java index f1800b5..f0f9663 100644 --- a/src/main/java/jobshop/Main.java +++ b/src/main/java/jobshop/Main.java @@ -17,14 +17,10 @@ import net.sourceforge.argparse4j.inf.ArgumentParserException; import net.sourceforge.argparse4j.inf.Namespace; /** - * This class is the main entry point for testing solver on instances. - * It provides + * This class is the main entry point for doing comparative performance tests of solvers. */ public class Main { - - - public static void main(String[] args) { // configure the argument parser ArgumentParser parser = ArgumentParsers.newFor("jsp-solver").build() diff --git a/src/main/java/jobshop/DebuggingMain.java b/src/main/java/jobshop/MainTest.java similarity index 75% rename from src/main/java/jobshop/DebuggingMain.java rename to src/main/java/jobshop/MainTest.java index bb1404a..96298d6 100644 --- a/src/main/java/jobshop/DebuggingMain.java +++ b/src/main/java/jobshop/MainTest.java @@ -1,13 +1,15 @@ package jobshop; import jobshop.encodings.JobNumbers; +import jobshop.encodings.ResourceOrder; import jobshop.encodings.Schedule; +import jobshop.encodings.Task; import jobshop.solvers.GreedySolver; import java.io.IOException; import java.nio.file.Paths; -public class DebuggingMain { +public class MainTest { public static void main(String[] args) { try { @@ -25,12 +27,18 @@ public class DebuggingMain { System.out.println("\nENCODING: " + enc); + // convert to a schedule and display Schedule schedule = enc.toSchedule(); System.out.println("VALID: " + schedule.isValid()); System.out.println("MAKESPAN: " + schedule.makespan()); System.out.println("SCHEDULE: " + schedule.toString()); System.out.println("GANTT: " + schedule.asciiGantt()); + Schedule manualSchedule = new Schedule(instance); + // TODO: encode the same solution + + ResourceOrder manualRO = new ResourceOrder(instance); + // TODO: encode the same solution } catch (IOException e) { e.printStackTrace(); System.exit(1); diff --git a/src/main/java/jobshop/Result.java b/src/main/java/jobshop/Result.java index dc149cc..cb16cfd 100644 --- a/src/main/java/jobshop/Result.java +++ b/src/main/java/jobshop/Result.java @@ -2,6 +2,7 @@ package jobshop; import jobshop.encodings.Schedule; +/** Class representing the result of a solver. */ public class Result { public Result(Instance instance, Schedule schedule, ExitCause cause) { @@ -10,12 +11,23 @@ public class Result { this.cause = cause; } + /** Documents the reason why a solver returned the solution. */ public enum ExitCause { - Timeout, ProvedOptimal, Blocked + /** The solver ran out of time and had to exit. */ + Timeout, + /** The solution has been proved optimal and thus can no longer be improved. */ + ProvedOptimal, + /** The solver was not able to further improve the solution (e.g. blocked in a local minima. */ + Blocked } + /** Instance that was solved. */ public final Instance instance; + + /** A schedule of the solution or null if no solution was found. */ public final Schedule schedule; + + /** Reason why the solver exited with this solution. */ public final ExitCause cause; diff --git a/src/main/java/jobshop/encodings/Encoding.java b/src/main/java/jobshop/encodings/Encoding.java index 99f19da..b1d0243 100644 --- a/src/main/java/jobshop/encodings/Encoding.java +++ b/src/main/java/jobshop/encodings/Encoding.java @@ -2,13 +2,19 @@ package jobshop.encodings; import jobshop.Instance; +/** Common class for all encodings. + * + * The only requirement for this class is to provide a conversion from the encoding into a Schedule. + */ public abstract class Encoding { + /** Problem instance of which this is the solution. */ public final Instance instance; public Encoding(Instance instance) { this.instance = instance; } + /** Convert into a schedule. */ public abstract Schedule toSchedule(); } diff --git a/src/main/java/jobshop/encodings/JobNumbers.java b/src/main/java/jobshop/encodings/JobNumbers.java index 26ee64b..d29df37 100644 --- a/src/main/java/jobshop/encodings/JobNumbers.java +++ b/src/main/java/jobshop/encodings/JobNumbers.java @@ -24,7 +24,7 @@ public class JobNumbers extends Encoding { } public JobNumbers(Schedule schedule) { - super(schedule.pb); + super(schedule.instance); this.jobs = new int[instance.numJobs * instance.numTasks]; diff --git a/src/main/java/jobshop/encodings/ResourceOrder.java b/src/main/java/jobshop/encodings/ResourceOrder.java index 9ff5621..f13a84c 100644 --- a/src/main/java/jobshop/encodings/ResourceOrder.java +++ b/src/main/java/jobshop/encodings/ResourceOrder.java @@ -30,13 +30,13 @@ public class ResourceOrder extends Encoding { /** Creates a resource order from a schedule. */ public ResourceOrder(Schedule schedule) { - super(schedule.pb); - Instance pb = schedule.pb; + super(schedule.instance); + Instance pb = schedule.instance; this.tasksByMachine = new Task[pb.numMachines][]; this.nextFreeSlot = new int[instance.numMachines]; - for(int m = 0 ; m startTime(j, t)) + for(int j = 0; j startTime(j, t)) return false; } - for(int t = 0 ; t path) { if(startTime(path.get(0)) != 0) { @@ -108,8 +113,8 @@ public class Schedule { */ public List criticalPath() { // select task with greatest end time - Task ldd = IntStream.range(0, pb.numJobs) - .mapToObj(j -> new Task(j, pb.numTasks-1)) + Task ldd = IntStream.range(0, instance.numJobs) + .mapToObj(j -> new Task(j, instance.numTasks-1)) .max(Comparator.comparing(this::endTime)) .get(); assert endTime(ldd) == makespan(); @@ -124,7 +129,7 @@ public class Schedule { // starts a time 0 while(startTime(path.getFirst()) != 0) { Task cur = path.getFirst(); - int machine = pb.machine(cur.job, cur.task); + int machine = instance.machine(cur.job, cur.task); // will contain the task that was delaying the start // of our current task @@ -140,8 +145,8 @@ public class Schedule { } if(latestPredecessor.isEmpty()) { // no latest predecessor found yet, look among tasks executing on the same machine - latestPredecessor = IntStream.range(0, pb.numJobs) - .mapToObj(j -> new Task(j, pb.task_with_machine(j, machine))) + latestPredecessor = IntStream.range(0, instance.numJobs) + .mapToObj(j -> new Task(j, instance.task_with_machine(j, machine))) .filter(t -> endTime(t) == startTime(cur)) .findFirst(); } @@ -158,11 +163,11 @@ public class Schedule { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("\nStart times of all tasks:\n"); - for(int job=0; job IntStream.range(0, pb.numTasks).map(task -> pb.duration(job, task))).min().getAsInt(); + int minTaskDur = IntStream.range(0, instance.numJobs).flatMap(job -> IntStream.range(0, instance.numTasks).map(task -> instance.duration(job, task))).min().getAsInt(); // time units by character int charsPerTimeUnit = minTaskDur >= 5 ? 1 : (5 / minTaskDur) +1; StringBuilder sb = new StringBuilder(); sb.append("\nGantt Chart\n"); - for(int job=0; job