Provide ResourceOrder implementation + minor additions.
This commit is contained in:
		
							parent
							
								
									8cc959a766
								
							
						
					
					
						commit
						ec04f02ed3
					
				
					 6 changed files with 307 additions and 38 deletions
				
			
		|  | @ -2,6 +2,8 @@ package jobshop; | ||||||
| 
 | 
 | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| public class BestKnownResult { | public class BestKnownResult { | ||||||
| 
 | 
 | ||||||
|  | @ -9,6 +11,13 @@ public class BestKnownResult { | ||||||
|         return bests.containsKey(instanceName); |         return bests.containsKey(instanceName); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public static List<String> instancesMatching(String namePrefix) { | ||||||
|  |         return Arrays.stream(instances) | ||||||
|  |                 .filter(i -> i.startsWith(namePrefix)) | ||||||
|  |                 .sorted() | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public static int of(String instanceName) { |     public static int of(String instanceName) { | ||||||
|         if(!bests.containsKey(instanceName)) { |         if(!bests.containsKey(instanceName)) { | ||||||
|             throw new RuntimeException("Unknown best result for "+instanceName); |             throw new RuntimeException("Unknown best result for "+instanceName); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| package jobshop; | package jobshop; | ||||||
| 
 | 
 | ||||||
|  | import jobshop.encodings.Task; | ||||||
|  | 
 | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.nio.file.Files; | import java.nio.file.Files; | ||||||
| import java.nio.file.Path; | import java.nio.file.Path; | ||||||
|  | @ -24,9 +26,15 @@ public class Instance { | ||||||
|     public int duration(int job, int task) { |     public int duration(int job, int task) { | ||||||
|         return durations[job][task]; |         return durations[job][task]; | ||||||
|     } |     } | ||||||
|  |     public int duration(Task t) { | ||||||
|  |         return duration(t.job, t.task); | ||||||
|  |     } | ||||||
|     public int machine(int job, int task) { |     public int machine(int job, int task) { | ||||||
|         return machines[job][task]; |         return machines[job][task]; | ||||||
|     } |     } | ||||||
|  |     public int machine(Task t) { | ||||||
|  |         return this.machine(t.job, t.task); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     /** among the tasks of the given job, returns the task index that uses the given machine. */ |     /** among the tasks of the given job, returns the task index that uses the given machine. */ | ||||||
|     public int task_with_machine(int job, int wanted_machine) { |     public int task_with_machine(int job, int wanted_machine) { | ||||||
|  | @ -46,6 +54,7 @@ public class Instance { | ||||||
|         machines = new int[numJobs][numTasks]; |         machines = new int[numJobs][numTasks]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** Parses a instance from a file. */ | ||||||
|     public static Instance fromFile(Path path) throws IOException { |     public static Instance fromFile(Path path) throws IOException { | ||||||
|         Iterator<String> lines = Files.readAllLines(path).stream() |         Iterator<String> lines = Files.readAllLines(path).stream() | ||||||
|                 .filter(l -> !l.startsWith("#")) |                 .filter(l -> !l.startsWith("#")) | ||||||
|  |  | ||||||
|  | @ -3,13 +3,13 @@ package jobshop; | ||||||
| import java.io.PrintStream; | import java.io.PrintStream; | ||||||
| import java.nio.file.Path; | import java.nio.file.Path; | ||||||
| import java.nio.file.Paths; | import java.nio.file.Paths; | ||||||
|  | import java.util.ArrayList; | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
| import java.util.HashMap; | import java.util.HashMap; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| import jobshop.solvers.BasicSolver; | import jobshop.solvers.*; | ||||||
| import jobshop.solvers.RandomSolver; |  | ||||||
| import net.sourceforge.argparse4j.ArgumentParsers; | import net.sourceforge.argparse4j.ArgumentParsers; | ||||||
| import net.sourceforge.argparse4j.inf.ArgumentParser; | import net.sourceforge.argparse4j.inf.ArgumentParser; | ||||||
| import net.sourceforge.argparse4j.inf.ArgumentParserException; | import net.sourceforge.argparse4j.inf.ArgumentParserException; | ||||||
|  | @ -68,20 +68,23 @@ public class Main { | ||||||
|                 System.exit(1); |                 System.exit(1); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         List<String> instances = ns.<String>getList("instance"); |         List<String> instancePrefixes = ns.getList("instance"); | ||||||
|         for(String instanceName : instances) { |         List<String> instances = new ArrayList<>(); | ||||||
|             if(!BestKnownResult.isKnown(instanceName)) { |         for(String instancePrefix : instancePrefixes) { | ||||||
|                 System.err.println("ERROR: instance \"" + instanceName + "\" is not avalaible."); |             List<String> matches = BestKnownResult.instancesMatching(instancePrefix); | ||||||
|  |             if(matches.isEmpty()) { | ||||||
|  |                 System.err.println("ERROR: instance prefix \"" + instancePrefix + "\" does not match any instance."); | ||||||
|                 System.err.println("       available instances: " + Arrays.toString(BestKnownResult.instances)); |                 System.err.println("       available instances: " + Arrays.toString(BestKnownResult.instances)); | ||||||
|                 System.exit(1); |                 System.exit(1); | ||||||
|             } |             } | ||||||
|  |             instances.addAll(matches); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         float[] runtimes = new float[solversToTest.size()]; |         float[] runtimes = new float[solversToTest.size()]; | ||||||
|         float[] distances = new float[solversToTest.size()]; |         float[] distances = new float[solversToTest.size()]; | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             output.print(  "                         ");; |             output.print(  "                         "); | ||||||
|             for(String s : solversToTest) |             for(String s : solversToTest) | ||||||
|                 output.printf("%-30s", s); |                 output.printf("%-30s", s); | ||||||
|             output.println(); |             output.println(); | ||||||
|  | @ -92,46 +95,46 @@ public class Main { | ||||||
|             output.println(); |             output.println(); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         for(String instanceName : instances) { |             for(String instanceName : instances) { | ||||||
|             int bestKnown = BestKnownResult.of(instanceName); |                 int bestKnown = BestKnownResult.of(instanceName); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|             Path path = Paths.get("instances/", instanceName); |                 Path path = Paths.get("instances/", instanceName); | ||||||
|             Instance instance = Instance.fromFile(path); |                 Instance instance = Instance.fromFile(path); | ||||||
| 
 | 
 | ||||||
|             output.printf("%-8s %-5s %4d      ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown); |                 output.printf("%-8s %-5s %4d      ",instanceName, instance.numJobs +"x"+instance.numTasks, bestKnown); | ||||||
| 
 | 
 | ||||||
|             for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { |                 for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { | ||||||
|                 String solverName = solversToTest.get(solverId); |                     String solverName = solversToTest.get(solverId); | ||||||
|                 Solver solver = solvers.get(solverName); |                     Solver solver = solvers.get(solverName); | ||||||
|                 long start = System.currentTimeMillis(); |                     long start = System.currentTimeMillis(); | ||||||
|                 long deadline = System.currentTimeMillis() + solveTimeMs; |                     long deadline = System.currentTimeMillis() + solveTimeMs; | ||||||
|                 Result result = solver.solve(instance, deadline); |                     Result result = solver.solve(instance, deadline); | ||||||
|                 long runtime = System.currentTimeMillis() - start; |                     long runtime = System.currentTimeMillis() - start; | ||||||
| 
 | 
 | ||||||
|                 if(!result.schedule.isValid()) { |                     if(!result.schedule.isValid()) { | ||||||
|                     System.err.println("ERROR: solver returned an invalid schedule"); |                         System.err.println("ERROR: solver returned an invalid schedule"); | ||||||
|                     System.exit(1); |                         System.exit(1); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     assert result.schedule.isValid(); | ||||||
|  |                     int makespan = result.schedule.makespan(); | ||||||
|  |                     float dist = 100f * (makespan - bestKnown) / (float) bestKnown; | ||||||
|  |                     runtimes[solverId] += (float) runtime / (float) instances.size(); | ||||||
|  |                     distances[solverId] += dist / (float) instances.size(); | ||||||
|  | 
 | ||||||
|  |                     output.printf("%7d %8s %5.1f        ", runtime, makespan, dist); | ||||||
|  |                     output.flush(); | ||||||
|                 } |                 } | ||||||
|  |                 output.println(); | ||||||
| 
 | 
 | ||||||
|                 assert result.schedule.isValid(); |  | ||||||
|                 int makespan = result.schedule.makespan(); |  | ||||||
|                 float dist = 100f * (makespan - bestKnown) / (float) bestKnown; |  | ||||||
|                 runtimes[solverId] += (float) runtime / (float) instances.size(); |  | ||||||
|                 distances[solverId] += dist / (float) instances.size(); |  | ||||||
| 
 |  | ||||||
|                 output.printf("%7d %8s %5.1f        ", runtime, makespan, dist); |  | ||||||
|                 output.flush(); |  | ||||||
|             } |             } | ||||||
|             output.println(); |  | ||||||
| 
 |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         output.printf("%-8s %-5s %4s      ", "AVG", "-", "-"); |             output.printf("%-8s %-5s %4s      ", "AVG", "-", "-"); | ||||||
|         for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { |             for(int solverId = 0 ; solverId < solversToTest.size() ; solverId++) { | ||||||
|             output.printf("%7.1f %8s %5.1f        ", runtimes[solverId], "-", distances[solverId]); |                 output.printf("%7.1f %8s %5.1f        ", runtimes[solverId], "-", distances[solverId]); | ||||||
|         } |             } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ import jobshop.Instance; | ||||||
| import jobshop.Schedule; | import jobshop.Schedule; | ||||||
| 
 | 
 | ||||||
| import java.util.Arrays; | import java.util.Arrays; | ||||||
|  | import java.util.Comparator; | ||||||
|  | import java.util.stream.IntStream; | ||||||
| 
 | 
 | ||||||
| /** Représentation par numéro de job. */ | /** Représentation par numéro de job. */ | ||||||
| public class JobNumbers extends Encoding { | public class JobNumbers extends Encoding { | ||||||
|  | @ -12,7 +14,7 @@ public class JobNumbers extends Encoding { | ||||||
|     /** A numJobs * numTasks array containing the representation by job numbers. */ |     /** A numJobs * numTasks array containing the representation by job numbers. */ | ||||||
|     public final int[] jobs; |     public final int[] jobs; | ||||||
| 
 | 
 | ||||||
|     /** In case the encoding is only partially filled, indicates the index of first |     /** In case the encoding is only partially filled, indicates the index of the first | ||||||
|      * element of `jobs` that has not been set yet. */ |      * element of `jobs` that has not been set yet. */ | ||||||
|     public int nextToSet = 0; |     public int nextToSet = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -23,6 +25,31 @@ public class JobNumbers extends Encoding { | ||||||
|         Arrays.fill(jobs, -1); |         Arrays.fill(jobs, -1); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public JobNumbers(Schedule schedule) { | ||||||
|  |         super(schedule.pb); | ||||||
|  | 
 | ||||||
|  |         this.jobs = new int[instance.numJobs * instance.numTasks]; | ||||||
|  | 
 | ||||||
|  |         // for each job indicates which is the next task to be scheduled | ||||||
|  |         int[] nextOnJob = new int[instance.numJobs]; | ||||||
|  | 
 | ||||||
|  |         while(Arrays.stream(nextOnJob).anyMatch(t -> t < instance.numTasks)) { | ||||||
|  |             Task next = IntStream | ||||||
|  |                     // for all jobs numbers | ||||||
|  |                     .range(0, instance.numJobs) | ||||||
|  |                     // build the next task for this job | ||||||
|  |                     .mapToObj(j -> new Task(j, nextOnJob[j])) | ||||||
|  |                     // only keep valid tasks (some jobs have no task left to be executed) | ||||||
|  |                     .filter(t -> t.task < instance.numTasks) | ||||||
|  |                     // select the task with the earliest execution time | ||||||
|  |                     .min(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) | ||||||
|  |                     .get(); | ||||||
|  | 
 | ||||||
|  |             this.jobs[nextToSet++] = next.job; | ||||||
|  |             nextOnJob[next.job] += 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public Schedule toSchedule() { |     public Schedule toSchedule() { | ||||||
|         // time at which each machine is going to be freed |         // time at which each machine is going to be freed | ||||||
|  |  | ||||||
							
								
								
									
										131
									
								
								src/main/java/jobshop/encodings/ResourceOrder.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/main/java/jobshop/encodings/ResourceOrder.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,131 @@ | ||||||
|  | package jobshop.encodings; | ||||||
|  | 
 | ||||||
|  | import jobshop.Encoding; | ||||||
|  | import jobshop.Instance; | ||||||
|  | import jobshop.Schedule; | ||||||
|  | 
 | ||||||
|  | import java.util.Comparator; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.stream.IntStream; | ||||||
|  | 
 | ||||||
|  | public class ResourceOrder extends Encoding { | ||||||
|  | 
 | ||||||
|  |     // for each machine m, taskByMachine[m] is an array of tasks to be | ||||||
|  |     // executed on this machine in the same order | ||||||
|  |     public final Task[][] tasksByMachine; | ||||||
|  | 
 | ||||||
|  |     // for each machine, indicate on many tasks have been initialized | ||||||
|  |     public final int[] nextFreeSlot; | ||||||
|  | 
 | ||||||
|  |     /** Creates a new empty resource order. */ | ||||||
|  |     public ResourceOrder(Instance instance) | ||||||
|  |     { | ||||||
|  |         super(instance); | ||||||
|  | 
 | ||||||
|  |         // matrix of null elements (null is the default value of objects) | ||||||
|  |         tasksByMachine = new Task[instance.numMachines][instance.numJobs]; | ||||||
|  | 
 | ||||||
|  |         // no task scheduled on any machine (0 is the default value) | ||||||
|  |         nextFreeSlot = new int[instance.numMachines]; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** Creates a resource order from a schedule. */ | ||||||
|  |     public ResourceOrder(Schedule schedule) | ||||||
|  |     { | ||||||
|  |         super(schedule.pb); | ||||||
|  |         Instance pb = schedule.pb; | ||||||
|  | 
 | ||||||
|  |         this.tasksByMachine = new Task[pb.numMachines][]; | ||||||
|  |         this.nextFreeSlot = new int[instance.numMachines]; | ||||||
|  | 
 | ||||||
|  |         for(int m = 0 ; m<schedule.pb.numMachines ; m++) { | ||||||
|  |             final int machine = m; | ||||||
|  | 
 | ||||||
|  |             // for thi machine, find all tasks that are executed on it and sort them by their start time | ||||||
|  |             tasksByMachine[m] = | ||||||
|  |                     IntStream.range(0, pb.numJobs) // all job numbers | ||||||
|  |                             .mapToObj(j -> new Task(j, pb.task_with_machine(j, machine))) // all tasks on this machine (one per job) | ||||||
|  |                             .sorted(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) // sorted by start time | ||||||
|  |                             .toArray(Task[]::new); // as new array and store in tasksByMachine | ||||||
|  | 
 | ||||||
|  |             // indicate that all tasks have been initialized for machine m | ||||||
|  |             nextFreeSlot[m] = instance.numJobs; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public Schedule toSchedule() { | ||||||
|  |         // indicate for each task that have been scheduled, its start time | ||||||
|  |         int [][] startTimes = new int [instance.numJobs][instance.numTasks]; | ||||||
|  | 
 | ||||||
|  |         // for each job, how many tasks have been scheduled (0 initially) | ||||||
|  |         int[] nextToScheduleByJob = new int[instance.numJobs]; | ||||||
|  | 
 | ||||||
|  |         // for each machine, how many tasks have been scheduled (0 initially) | ||||||
|  |         int[] nextToScheduleByMachine = new int[instance.numMachines]; | ||||||
|  | 
 | ||||||
|  |         // for each machine, earliest time at which the machine can be used | ||||||
|  |         int[] releaseTimeOfMachine = new int[instance.numMachines]; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         // loop while there remains a job that has unscheduled tasks | ||||||
|  |         while(IntStream.range(0, instance.numJobs).anyMatch(m -> nextToScheduleByJob[m] < instance.numTasks)) { | ||||||
|  | 
 | ||||||
|  |             // selects a task that has noun scheduled predecessor on its job and machine : | ||||||
|  |             //  - it is the next to be schedule on a machine | ||||||
|  |             //  - it is the next to be scheduled on its job | ||||||
|  |             // if there is no such task, we have cyclic dependency and the solution is invalid | ||||||
|  |             Optional<Task> schedulable = | ||||||
|  |                     IntStream.range(0, instance.numMachines) // all machines ... | ||||||
|  |                     .filter(m -> nextToScheduleByMachine[m] < instance.numJobs) // ... with unscheduled jobs | ||||||
|  |                     .mapToObj(m -> this.tasksByMachine[m][nextToScheduleByMachine[m]]) // tasks that are next to schedule on a machine ... | ||||||
|  |                     .filter(task -> task.task == nextToScheduleByJob[task.job])  // ... and on their job | ||||||
|  |                     .findFirst(); // select the first one if any | ||||||
|  | 
 | ||||||
|  |             if(schedulable.isPresent()) { | ||||||
|  |                 // we found a schedulable task, lets call it t | ||||||
|  |                 Task t = schedulable.get(); | ||||||
|  |                 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); | ||||||
|  |                 est = Math.max(est, releaseTimeOfMachine[instance.machine(t)]); | ||||||
|  |                 startTimes[t.job][t.task] = est; | ||||||
|  | 
 | ||||||
|  |                 // mark the task as scheduled | ||||||
|  |                 nextToScheduleByJob[t.job]++; | ||||||
|  |                 nextToScheduleByMachine[machine]++; | ||||||
|  |                 // increase the release time of the machine | ||||||
|  |                 releaseTimeOfMachine[machine] = est + instance.duration(t.job, t.task); | ||||||
|  |             } else { | ||||||
|  |                 // no tasks are schedulable, there is no solution for this resource ordering | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         // we exited the loop : all tasks have been scheduled successfully | ||||||
|  |         return new Schedule(instance, startTimes); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** Creates an exact copy of this resource order. */ | ||||||
|  |     public ResourceOrder copy() { | ||||||
|  |         return new ResourceOrder(this.toSchedule()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String toString() | ||||||
|  |     { | ||||||
|  |         StringBuilder s = new StringBuilder(); | ||||||
|  |         for(int m=0; m < instance.numMachines; m++) | ||||||
|  |         { | ||||||
|  |             s.append("Machine ").append(m).append(" : "); | ||||||
|  |             for(int j=0; j<instance.numJobs; j++) | ||||||
|  |             { | ||||||
|  |                 s.append(tasksByMachine[m][j]).append(" ; "); | ||||||
|  |             } | ||||||
|  |             s.append("\n"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return s.toString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										90
									
								
								src/main/java/jobshop/solvers/DescentSolver.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/main/java/jobshop/solvers/DescentSolver.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | ||||||
|  | package jobshop.solvers; | ||||||
|  | 
 | ||||||
|  | import jobshop.Instance; | ||||||
|  | import jobshop.Result; | ||||||
|  | import jobshop.Solver; | ||||||
|  | import jobshop.encodings.ResourceOrder; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | public class DescentSolver implements Solver { | ||||||
|  | 
 | ||||||
|  |     /** 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 swam 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<Block> blocksOfCriticalPath(ResourceOrder order) { | ||||||
|  |         throw new UnsupportedOperationException(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */ | ||||||
|  |     List<Swap> neighbors(Block block) { | ||||||
|  |         throw new UnsupportedOperationException(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
		Loading…
	
		Reference in a new issue