From 1d4883388b2812f013cb0957ce21c2d2f0e7cb5b Mon Sep 17 00:00:00 2001 From: Arthur Bit-Monnot Date: Thu, 8 Apr 2021 17:14:12 +0200 Subject: [PATCH] Improvments for year 2020-2021 --- build.gradle | 2 +- instances/aaa2 | 11 ++ instances/aaa3 | 20 +++ src/main/java/jobshop/BestKnownResults.java | 2 + src/main/java/jobshop/DebuggingMain.java | 29 ++--- src/main/java/jobshop/Main.java | 27 +--- src/main/java/jobshop/Result.java | 2 +- src/main/java/jobshop/Solver.java | 7 - .../jobshop/{ => encodings}/Encoding.java | 4 +- .../java/jobshop/encodings/JobNumbers.java | 16 ++- .../java/jobshop/encodings/ResourceOrder.java | 21 ++- .../jobshop/{ => encodings}/Schedule.java | 120 ++++++++++++++++-- src/main/java/jobshop/encodings/Task.java | 2 +- .../java/jobshop/solvers/BasicSolver.java | 1 - .../java/jobshop/solvers/DescentSolver.java | 79 +----------- .../java/jobshop/solvers/GreedySolver.java | 21 +++ .../java/jobshop/solvers/RandomSolver.java | 2 +- src/main/java/jobshop/solvers/Solver.java | 21 +++ .../solvers/neighborhood/Neighbor.java | 8 ++ .../solvers/neighborhood/Neighborhood.java | 9 ++ .../jobshop/solvers/neighborhood/Nowicki.java | 102 +++++++++++++++ .../java/jobshop/encodings/EncodingTests.java | 3 +- 22 files changed, 362 insertions(+), 147 deletions(-) create mode 100644 instances/aaa2 create mode 100644 instances/aaa3 delete mode 100644 src/main/java/jobshop/Solver.java rename src/main/java/jobshop/{ => encodings}/Encoding.java (78%) rename src/main/java/jobshop/{ => encodings}/Schedule.java (50%) create mode 100644 src/main/java/jobshop/solvers/GreedySolver.java create mode 100644 src/main/java/jobshop/solvers/Solver.java create mode 100644 src/main/java/jobshop/solvers/neighborhood/Neighbor.java create mode 100644 src/main/java/jobshop/solvers/neighborhood/Neighborhood.java create mode 100644 src/main/java/jobshop/solvers/neighborhood/Nowicki.java diff --git a/build.gradle b/build.gradle index b20ed5f..18831ab 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { group 'jobshop' //version '0.1' -sourceCompatibility = 8 +sourceCompatibility = 11 application { diff --git a/instances/aaa2 b/instances/aaa2 new file mode 100644 index 0000000..f8dd3c7 --- /dev/null +++ b/instances/aaa2 @@ -0,0 +1,11 @@ +# Example 2 +# This is the example used as a support for exercises during classes (year 2020-2021) +4 3 # num-jobs num-tasks +0 1 1 3 2 2 +1 8 0 5 2 10 +0 5 2 4 1 8 +2 4 0 10 1 6 + + + + diff --git a/instances/aaa3 b/instances/aaa3 new file mode 100644 index 0000000..c5938cb --- /dev/null +++ b/instances/aaa3 @@ -0,0 +1,20 @@ +# Example 3 +# This problem has deterministic results for all greedy solver variants. +# Makespan for each variant: +# - SPT: 53 +# - LPT: 92 +# - SRPT: 78 +# - LRPT: 54 +# - EST_SPT: 48 +# - EST_LPT: 56 +# - EST_SRPT: 53 +# - EST_LRPT: 56 +4 3 # num-jobs num-tasks +0 1 1 2 2 15 +1 4 0 5 2 11 +0 7 2 8 1 13 +2 3 0 18 1 6 + + + + diff --git a/src/main/java/jobshop/BestKnownResults.java b/src/main/java/jobshop/BestKnownResults.java index c1641f6..31949a5 100644 --- a/src/main/java/jobshop/BestKnownResults.java +++ b/src/main/java/jobshop/BestKnownResults.java @@ -55,6 +55,8 @@ public class BestKnownResults { static { bests = new HashMap<>(); bests.put("aaa1", 11); + bests.put("aaa2", 29); + bests.put("aaa3", 41); bests.put("abz5", 1234); bests.put("abz6", 943); bests.put("abz7", 656); diff --git a/src/main/java/jobshop/DebuggingMain.java b/src/main/java/jobshop/DebuggingMain.java index 4487e68..bb1404a 100644 --- a/src/main/java/jobshop/DebuggingMain.java +++ b/src/main/java/jobshop/DebuggingMain.java @@ -1,6 +1,8 @@ package jobshop; import jobshop.encodings.JobNumbers; +import jobshop.encodings.Schedule; +import jobshop.solvers.GreedySolver; import java.io.IOException; import java.nio.file.Paths; @@ -12,25 +14,22 @@ public class DebuggingMain { // load the aaa1 instance Instance instance = Instance.fromFile(Paths.get("instances/aaa1")); - // construit une solution dans la représentation par - // numéro de jobs : [0 1 1 0 0 1] - // Note : cette solution a aussi été vue dans les exercices (section 3.3) - // mais on commençait à compter à 1 ce qui donnait [1 2 2 1 1 2] + // builds a solution in the job-numbers encoding [0 1 1 0 0 1] JobNumbers enc = new JobNumbers(instance); - enc.jobs[enc.nextToSet++] = 0; - enc.jobs[enc.nextToSet++] = 1; - enc.jobs[enc.nextToSet++] = 1; - enc.jobs[enc.nextToSet++] = 0; - enc.jobs[enc.nextToSet++] = 0; - enc.jobs[enc.nextToSet++] = 1; + enc.addTask(0); + enc.addTask(1); + enc.addTask(1); + enc.addTask(0); + enc.addTask(0); + enc.addTask(1); System.out.println("\nENCODING: " + enc); - Schedule sched = enc.toSchedule(); - // TODO: make it print something meaningful by implementing the Schedule.toString() method - System.out.println("SCHEDULE: " + sched); - System.out.println("VALID: " + sched.isValid()); - System.out.println("MAKESPAN: " + sched.makespan()); + 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()); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/jobshop/Main.java b/src/main/java/jobshop/Main.java index bf57dd3..f1800b5 100644 --- a/src/main/java/jobshop/Main.java +++ b/src/main/java/jobshop/Main.java @@ -7,8 +7,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.stream.Collectors; import jobshop.solvers.*; +import jobshop.solvers.neighborhood.Nowicki; import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.ArgumentParserException; @@ -20,14 +22,7 @@ import net.sourceforge.argparse4j.inf.Namespace; */ public class Main { - /** All solvers available in this program */ - private static final HashMap solvers; - static { - solvers = new HashMap<>(); - solvers.put("basic", new BasicSolver()); - solvers.put("random", new RandomSolver()); - // TODO: add new solvers here - } + public static void main(String[] args) { @@ -72,14 +67,7 @@ public class Main { // Get the list of solvers that we should benchmark. // We also check that we have a solver available for the given name and print an error message otherwise. List solversToTest = ns.getList("solver"); - for(String solverName : solversToTest) { - if(!solvers.containsKey(solverName)) { - System.err.println("ERROR: Solver \"" + solverName + "\" is not avalaible."); - System.err.println(" Available solvers: " + solvers.keySet().toString()); - System.err.println(" You can provide your own solvers by adding them to the `Main.solvers` HashMap."); - System.exit(0); - } - } + List solvers = solversToTest.stream().map(Solver::getSolver).collect(Collectors.toList()); // retrieve all instances on which we should run the solvers. List instances = new ArrayList<>(); @@ -126,11 +114,10 @@ public class Main { output.printf("%-8s %-5s %4d ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown); // run all selected solvers on the instance and print the results - for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { + for(int solverId = 0 ; solverId < solvers.size() ; solverId++) { // Select the next solver to run. Given the solver name passed on the command line, // we lookup the `Main.solvers` hash map to get the solver object with the given name. - String solverName = solversToTest.get(solverId); - Solver solver = solvers.get(solverName); + Solver solver = solvers.get(solverId); // start chronometer and compute deadline for the solver to provide a result. long start = System.currentTimeMillis(); @@ -168,7 +155,7 @@ public class Main { } catch (Exception e) { - // there was uncought exception, print the stack trace and exit with error. + // there was uncaught exception, print the stack trace and exit with error. e.printStackTrace(); System.exit(1); } diff --git a/src/main/java/jobshop/Result.java b/src/main/java/jobshop/Result.java index fa9d4c3..dc149cc 100644 --- a/src/main/java/jobshop/Result.java +++ b/src/main/java/jobshop/Result.java @@ -1,6 +1,6 @@ package jobshop; -import java.util.Optional; +import jobshop.encodings.Schedule; public class Result { diff --git a/src/main/java/jobshop/Solver.java b/src/main/java/jobshop/Solver.java deleted file mode 100644 index 20ab271..0000000 --- a/src/main/java/jobshop/Solver.java +++ /dev/null @@ -1,7 +0,0 @@ -package jobshop; - -public interface Solver { - - Result solve(Instance instance, long deadline); - -} diff --git a/src/main/java/jobshop/Encoding.java b/src/main/java/jobshop/encodings/Encoding.java similarity index 78% rename from src/main/java/jobshop/Encoding.java rename to src/main/java/jobshop/encodings/Encoding.java index d6f0245..99f19da 100644 --- a/src/main/java/jobshop/Encoding.java +++ b/src/main/java/jobshop/encodings/Encoding.java @@ -1,4 +1,6 @@ -package jobshop; +package jobshop.encodings; + +import jobshop.Instance; public abstract class Encoding { diff --git a/src/main/java/jobshop/encodings/JobNumbers.java b/src/main/java/jobshop/encodings/JobNumbers.java index 3e70366..26ee64b 100644 --- a/src/main/java/jobshop/encodings/JobNumbers.java +++ b/src/main/java/jobshop/encodings/JobNumbers.java @@ -1,8 +1,6 @@ package jobshop.encodings; -import jobshop.Encoding; import jobshop.Instance; -import jobshop.Schedule; import java.util.Arrays; import java.util.Comparator; @@ -45,11 +43,15 @@ public class JobNumbers extends Encoding { .min(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) .get(); - this.jobs[nextToSet++] = next.job; + this.addTask(next.job); nextOnJob[next.job] += 1; } } + public void addTask(int jobNumber) { + this.jobs[nextToSet++] = jobNumber; + } + @Override public Schedule toSchedule() { // time at which each machine is going to be freed @@ -59,22 +61,22 @@ public class JobNumbers extends Encoding { int[] nextTask = new int[instance.numJobs]; // for each task, its start time - int[][] startTimes = new int[instance.numJobs][instance.numTasks]; + Schedule schedule = new Schedule(instance); // compute the earliest start time for every task of every job for(int job : jobs) { int task = nextTask[job]; int machine = instance.machine(job, task); // earliest start time for this task - int est = task == 0 ? 0 : startTimes[job][task-1] + instance.duration(job, task-1); + int est = task == 0 ? 0 : schedule.endTime(job, task-1); est = Math.max(est, nextFreeTimeResource[machine]); - startTimes[job][task] = est; + schedule.setStartTime(job, task, est); nextFreeTimeResource[machine] = est + instance.duration(job, task); nextTask[job] = task + 1; } - return new Schedule(instance, startTimes); + return schedule; } @Override diff --git a/src/main/java/jobshop/encodings/ResourceOrder.java b/src/main/java/jobshop/encodings/ResourceOrder.java index a57435f..9ff5621 100644 --- a/src/main/java/jobshop/encodings/ResourceOrder.java +++ b/src/main/java/jobshop/encodings/ResourceOrder.java @@ -1,8 +1,6 @@ package jobshop.encodings; -import jobshop.Encoding; import jobshop.Instance; -import jobshop.Schedule; import java.util.Comparator; import java.util.Optional; @@ -53,10 +51,21 @@ public class ResourceOrder extends Encoding { } } + public void addTaskToMachine(int machine, Task task) { + tasksByMachine[machine][nextFreeSlot[machine]] = task; + nextFreeSlot[machine] += 1; + } + + public void swapTasks(int machine, int indexFirstTask, int indexSecondTask) { + Task tmp = tasksByMachine[machine][indexFirstTask]; + tasksByMachine[machine][indexFirstTask] = tasksByMachine[machine][indexSecondTask]; + tasksByMachine[machine][indexSecondTask] = tmp; + } + @Override public Schedule toSchedule() { // indicate for each task that have been scheduled, its start time - int [][] startTimes = new int [instance.numJobs][instance.numTasks]; + Schedule schedule = new Schedule(instance); // for each job, how many tasks have been scheduled (0 initially) int[] nextToScheduleByJob = new int[instance.numJobs]; @@ -88,9 +97,9 @@ public class ResourceOrder extends Encoding { int machine = instance.machine(t.job, t.task); // compute the earliest start time (est) of the task - int est = t.task == 0 ? 0 : startTimes[t.job][t.task-1] + instance.duration(t.job, t.task-1); + int est = t.task == 0 ? 0 : schedule.endTime(t.job, t.task-1); est = Math.max(est, releaseTimeOfMachine[instance.machine(t)]); - startTimes[t.job][t.task] = est; + schedule.setStartTime(t.job, t.task, est); // mark the task as scheduled nextToScheduleByJob[t.job]++; @@ -103,7 +112,7 @@ public class ResourceOrder extends Encoding { } } // we exited the loop : all tasks have been scheduled successfully - return new Schedule(instance, startTimes); + return schedule; } /** Creates an exact copy of this resource order. */ diff --git a/src/main/java/jobshop/Schedule.java b/src/main/java/jobshop/encodings/Schedule.java similarity index 50% rename from src/main/java/jobshop/Schedule.java rename to src/main/java/jobshop/encodings/Schedule.java index b3bae5c..c05784b 100644 --- a/src/main/java/jobshop/Schedule.java +++ b/src/main/java/jobshop/encodings/Schedule.java @@ -1,7 +1,6 @@ -package jobshop; +package jobshop.encodings; - -import jobshop.encodings.Task; +import jobshop.Instance; import java.util.*; import java.util.stream.IntStream; @@ -12,16 +11,18 @@ public class Schedule { // times[j][i] is the start time of task (j,i) : i^th task of the j^th job final int[][] times; - public Schedule(Instance pb, int[][] times) { + /** Creates a new schedule for the given instance where all start times are uninitialized. */ + public Schedule(Instance pb) { this.pb = pb; this.times = new int[pb.numJobs][]; for(int j = 0 ; j < pb.numJobs ; j++) { - this.times[j] = Arrays.copyOf(times[j], pb.numTasks); + this.times[j] = new int[pb.numTasks]; } } - public int startTime(int job, int task) { - return times[job][task]; + /** Sets the start time of the given task. */ + public void setStartTime(int job, int task, int startTime) { + times[job][task] = startTime; } /** Returns true if this schedule is valid (no constraint is violated) */ @@ -55,22 +56,38 @@ public class Schedule { return true; } + /** Makespan of the solution. + * The makespan is the end time of the latest finishing task. + */ public int makespan() { int max = -1; for(int j = 0 ; j path) { if(startTime(path.get(0)) != 0) { return false; @@ -85,6 +102,10 @@ public class Schedule { return true; } + /** Computes a critical path of the schedule. + * + * @return A sequence of task along a critical path. + */ public List criticalPath() { // select task with greatest end time Task ldd = IntStream.range(0, pb.numJobs) @@ -117,7 +138,7 @@ public class Schedule { if(endTime(predOnJob) == startTime(cur)) latestPredecessor = Optional.of(predOnJob); } - if(!latestPredecessor.isPresent()) { + 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))) @@ -132,4 +153,81 @@ public class Schedule { assert isCriticalPath(path); return path; } + + @Override + 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(); + // 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 neighborhood; + final Solver baseSolver; - Block(int machine, int firstTask, int lastTask) { - this.machine = machine; - this.firstTask = firstTask; - this.lastTask = lastTask; - } + public DescentSolver(Neighborhood neighborhood, Solver baseSolver) { + this.neighborhood = neighborhood; + this.baseSolver = baseSolver; } - /** - * Represents a swap of two tasks on the same machine in a ResourceOrder encoding. - * - * Consider the solution in ResourceOrder representation - * machine 0 : (0,1) (1,2) (2,2) - * machine 1 : (0,2) (2,1) (1,1) - * machine 2 : ... - * - * The swap with : machine = 1, t1= 0 and t2 = 1 - * Represent inversion of the two tasks : (0,2) and (2,1) - * Applying this swap on the above resource order should result in the following one : - * machine 0 : (0,1) (1,2) (2,2) - * machine 1 : (2,1) (0,2) (1,1) - * machine 2 : ... - */ - static class Swap { - // machine on which to perform the swap - final int machine; - // index of one task to be swapped - final int t1; - // index of the other task to be swapped - final int t2; - - Swap(int machine, int t1, int t2) { - this.machine = machine; - this.t1 = t1; - this.t2 = t2; - } - - /** Apply this swap on the given resource order, transforming it into a new solution. */ - public void applyOn(ResourceOrder order) { - throw new UnsupportedOperationException(); - } - } - - @Override public Result solve(Instance instance, long deadline) { throw new UnsupportedOperationException(); } - /** Returns a list of all blocks of the critical path. */ - List blocksOfCriticalPath(ResourceOrder order) { - throw new UnsupportedOperationException(); - } - - /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */ - List neighbors(Block block) { - throw new UnsupportedOperationException(); - } - } diff --git a/src/main/java/jobshop/solvers/GreedySolver.java b/src/main/java/jobshop/solvers/GreedySolver.java new file mode 100644 index 0000000..21fdd2a --- /dev/null +++ b/src/main/java/jobshop/solvers/GreedySolver.java @@ -0,0 +1,21 @@ +package jobshop.solvers; + +import jobshop.Instance; +import jobshop.Result; + +public class GreedySolver implements Solver { + + public enum Priority { + SPT, LPT, SRPT, LRPT, EST_SPT, EST_LPT, EST_SRPT, EST_LRPT + } + + final Priority priority; + public GreedySolver(Priority p) { + this.priority = p; + } + + @Override + public Result solve(Instance instance, long deadline) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/jobshop/solvers/RandomSolver.java b/src/main/java/jobshop/solvers/RandomSolver.java index 17e2b87..8fc2100 100644 --- a/src/main/java/jobshop/solvers/RandomSolver.java +++ b/src/main/java/jobshop/solvers/RandomSolver.java @@ -2,8 +2,8 @@ package jobshop.solvers; import jobshop.*; import jobshop.encodings.JobNumbers; +import jobshop.encodings.Schedule; -import java.util.Optional; import java.util.Random; public class RandomSolver implements Solver { diff --git a/src/main/java/jobshop/solvers/Solver.java b/src/main/java/jobshop/solvers/Solver.java new file mode 100644 index 0000000..ba41013 --- /dev/null +++ b/src/main/java/jobshop/solvers/Solver.java @@ -0,0 +1,21 @@ +package jobshop.solvers; + +import jobshop.Instance; +import jobshop.Result; + +public interface Solver { + + Result solve(Instance instance, long deadline); + + /** Static factory method to create a new solver based on its name. */ + static Solver getSolver(String name) { + switch (name) { + case "basic": return new BasicSolver(); + case "random": return new RandomSolver(); + case "spt": return new GreedySolver(GreedySolver.Priority.SPT); + // TODO: add new solvers + default: throw new RuntimeException("Unknown solver: "+ name); + } + } + +} diff --git a/src/main/java/jobshop/solvers/neighborhood/Neighbor.java b/src/main/java/jobshop/solvers/neighborhood/Neighbor.java new file mode 100644 index 0000000..9380ab0 --- /dev/null +++ b/src/main/java/jobshop/solvers/neighborhood/Neighbor.java @@ -0,0 +1,8 @@ +package jobshop.solvers.neighborhood; + +public abstract class Neighbor { + + public abstract void applyOn(Encoding current); + public abstract void undoApplyOn(Encoding current); + +} diff --git a/src/main/java/jobshop/solvers/neighborhood/Neighborhood.java b/src/main/java/jobshop/solvers/neighborhood/Neighborhood.java new file mode 100644 index 0000000..cb9f562 --- /dev/null +++ b/src/main/java/jobshop/solvers/neighborhood/Neighborhood.java @@ -0,0 +1,9 @@ +package jobshop.solvers.neighborhood; + +import java.util.List; + +public abstract class Neighborhood { + + public abstract List> generateNeighbors(Encoding current); + +} diff --git a/src/main/java/jobshop/solvers/neighborhood/Nowicki.java b/src/main/java/jobshop/solvers/neighborhood/Nowicki.java new file mode 100644 index 0000000..0aafb98 --- /dev/null +++ b/src/main/java/jobshop/solvers/neighborhood/Nowicki.java @@ -0,0 +1,102 @@ +package jobshop.solvers.neighborhood; + +import jobshop.encodings.ResourceOrder; + +import java.util.ArrayList; +import java.util.List; + +public class Nowicki extends Neighborhood { + + /** A block represents a subsequence of the critical path such that all tasks in it execute on the same machine. + * This class identifies a block in a ResourceOrder representation. + * + * Consider the solution in ResourceOrder representation + * machine 0 : (0,1) (1,2) (2,2) + * machine 1 : (0,2) (2,1) (1,1) + * machine 2 : ... + * + * The block with : machine = 1, firstTask= 0 and lastTask = 1 + * Represent the task sequence : [(0,2) (2,1)] + * + * */ + static class Block { + /** machine on which the block is identified */ + final int machine; + /** index of the first task of the block */ + final int firstTask; + /** index of the last task of the block */ + final int lastTask; + + Block(int machine, int firstTask, int lastTask) { + this.machine = machine; + this.firstTask = firstTask; + this.lastTask = lastTask; + } + } + + /** + * Represents a swap of two tasks on the same machine in a ResourceOrder encoding. + * + * Consider the solution in ResourceOrder representation + * machine 0 : (0,1) (1,2) (2,2) + * machine 1 : (0,2) (2,1) (1,1) + * machine 2 : ... + * + * The swap with : machine = 1, t1= 0 and t2 = 1 + * Represent inversion of the two tasks : (0,2) and (2,1) + * Applying this swap on the above resource order should result in the following one : + * machine 0 : (0,1) (1,2) (2,2) + * machine 1 : (2,1) (0,2) (1,1) + * machine 2 : ... + */ + static class Swap extends Neighbor { + // machine on which to perform the swap + final int machine; + // index of one task to be swapped + final int t1; + // index of the other task to be swapped + final int t2; + + Swap(int machine, int t1, int t2) { + this.machine = machine; + this.t1 = t1; + this.t2 = t2; + } + + + /** Apply this swap on the given resource order, transforming it into a new solution. */ + @Override + public void applyOn(ResourceOrder current) { + throw new UnsupportedOperationException(); + } + + @Override + public void undoApplyOn(ResourceOrder current) { + throw new UnsupportedOperationException(); + } + } + + + @Override + public List> generateNeighbors(ResourceOrder current) { + List> neighbors = new ArrayList<>(); + // iterate over all blocks of the critical + for(var block : blocksOfCriticalPath(current)) { + // for this block, compute all neighbors and add them to the list of neighbors + neighbors.addAll(neighbors(block)); + } + return neighbors; + } + + /** Returns a list of all the blocks of the critical path. */ + List blocksOfCriticalPath(ResourceOrder order) { + throw new UnsupportedOperationException(); + } + + /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */ + List neighbors(Block block) { + throw new UnsupportedOperationException(); + + } + +} diff --git a/src/test/java/jobshop/encodings/EncodingTests.java b/src/test/java/jobshop/encodings/EncodingTests.java index 029fc71..ef23be0 100644 --- a/src/test/java/jobshop/encodings/EncodingTests.java +++ b/src/test/java/jobshop/encodings/EncodingTests.java @@ -2,8 +2,7 @@ package jobshop.encodings; import jobshop.Instance; import jobshop.Result; -import jobshop.Schedule; -import jobshop.Solver; +import jobshop.solvers.Solver; import jobshop.solvers.BasicSolver; import org.junit.Test;