diff --git a/src/main/java/jobshop/encodings/ResourceOrder.java b/src/main/java/jobshop/encodings/ResourceOrder.java index cbc2a61..02b8983 100644 --- a/src/main/java/jobshop/encodings/ResourceOrder.java +++ b/src/main/java/jobshop/encodings/ResourceOrder.java @@ -72,6 +72,22 @@ public final class ResourceOrder extends Encoding { return tasksByMachine[machine][taskIndex]; } + /** Returns the index of a particular task scheduled on a particular machine. + * + * @param machine Machine on which the task to retrieve is scheduled. + * @param task Task in the queue for this machine. + * @return The index of the task scheduled on a machine. + */ + public int getIndexOfTaskOnMachine(int machine, Task task) { + int i = 0; + boolean found = false; + while (i bestNeighbor; + + while (!ended) { + schedule = resourceOrder.toSchedule().get(); + bestMakespan = schedule.makespan(); + bestNeighbor = null; + List> generatedNeighbors = neighborhood.generateNeighbors(resourceOrder); + Iterator> iter = generatedNeighbors.iterator(); + while (iter.hasNext()) { + Neighbor neighbor = iter.next(); + neighbor.applyOn(resourceOrder); + try { + Schedule currentSchedule = resourceOrder.toSchedule().get(); + int currentMakespan = currentSchedule.makespan(); + if (currentMakespan < bestMakespan) { + bestMakespan = currentMakespan; + bestNeighbor = neighbor; + } + } catch (Exception e) { + } + neighbor.undoApplyOn(resourceOrder); + } + if (bestNeighbor == null) { + ended = true; + } else { + bestNeighbor.applyOn(resourceOrder); + } + } + return new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.ProvedOptimal); } } diff --git a/src/main/java/jobshop/solvers/GreedySolver.java b/src/main/java/jobshop/solvers/GreedySolver.java index 7382205..aea875c 100644 --- a/src/main/java/jobshop/solvers/GreedySolver.java +++ b/src/main/java/jobshop/solvers/GreedySolver.java @@ -23,6 +23,9 @@ public class GreedySolver implements Solver { final Priority priority; final ArrayList tachesRestantes; + int[] machineFreeDate; + int[] jobFreeDate; + /** Creates a new greedy solver that will use the given priority. */ @@ -31,8 +34,12 @@ public class GreedySolver implements Solver { this.tachesRestantes = new ArrayList<>(); } + private int getEarliestDate(Instance instance, Task task) { + return Math.max(machineFreeDate[instance.machine(task)], jobFreeDate[task.job]); + } + /** return true if t1 est plus prioritaire que t1 **/ - private boolean prioritaire(Instance instance, Task t1, Task t2) throws Exception { + private boolean prioritaire(Instance instance, Task t1, Task t2) { boolean rt = false; switch(priority) { case SPT: @@ -65,51 +72,107 @@ public class GreedySolver implements Solver { rt = sigmaT1 >= sigmaT2; break; case EST_SPT: - throw new Exception("UNKNOWN PRIORITY"); - //break; + if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) { + rt = true; + } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) { + rt = false; + } else { + rt = instance.duration(t1) <= instance.duration(t2); + } + break; case EST_LPT: - throw new Exception("UNKNOWN PRIORITY"); - //break; + if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) { + rt = true; + } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) { + rt = false; + } else { + rt = instance.duration(t1) >= instance.duration(t2); + } + break; case EST_SRPT: - throw new Exception("UNKNOWN PRIORITY"); - //break; + if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) { + rt = true; + } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) { + rt = false; + } else { + sigmaT1 = 0; + sigmaT2 = 0; + for (i=t1.task; i getEarliestDate(instance, t2)) { + rt = false; + } else { + sigmaT1 = 0; + sigmaT2 = 0; + for (i=t1.task; i= sigmaT2; + } + break; } return rt; } - private void addTask(Instance instance, Task task) throws Exception { - Iterator iter = this.tachesRestantes.iterator(); - int index = 0; - boolean trouve = false; - while (iter.hasNext() && !trouve) { - Task current = iter.next(); - if (this.prioritaire(instance, task, current)) { - trouve = true; - } else { - index++; + private void addTask(Instance instance, Task task) { + if (priority == Priority.SPT || priority == Priority.LPT || priority == Priority.SRPT || priority == Priority.LRPT) { + Iterator iter = this.tachesRestantes.iterator(); + int index = 0; + boolean trouve = false; + while (iter.hasNext() && !trouve) { + Task current = iter.next(); + if (this.prioritaire(instance, task, current)) { + trouve = true; + } else { + index++; + } } + this.tachesRestantes.add(index, task); + } else { + this.tachesRestantes.add(task); } - this.tachesRestantes.add(index, task); } - private Task getTask() { - return this.tachesRestantes.remove(0); + private Task getTask(Instance instance) { + if (priority == Priority.SPT || priority == Priority.LPT || priority == Priority.SRPT || priority == Priority.LRPT) { + return this.tachesRestantes.remove(0); + } else { + int indexBest = 0; + int indexChallenger; + for (indexChallenger = 1; indexChallenger < tachesRestantes.size(); indexChallenger++) { + if (prioritaire(instance, tachesRestantes.get(indexChallenger), tachesRestantes.get(indexBest))) { + indexBest = indexChallenger; + } + } + return this.tachesRestantes.remove(indexBest); + } } @Override public Result solve(Instance instance, long deadline) { //Initialisation + jobFreeDate = new int[instance.numJobs]; + machineFreeDate = new int[instance.numMachines]; int i; for (i=0; i { /** Apply this swap on the given ResourceOrder, transforming it into a new solution. */ @Override public void applyOn(ResourceOrder current) { - throw new UnsupportedOperationException(); + current.swapTasks(machine, t1, t2); } /** Unapply this swap on the neighbor, transforming it back into the original solution. */ @Override public void undoApplyOn(ResourceOrder current) { - throw new UnsupportedOperationException(); + current.swapTasks(machine, t1, t2); } } @@ -109,13 +111,50 @@ public class Nowicki extends Neighborhood { /** Returns a list of all the blocks of the critical path. */ List blocksOfCriticalPath(ResourceOrder order) { - throw new UnsupportedOperationException(); + ArrayList results = new ArrayList<>(); + + List criticalPath = order.toSchedule().get().criticalPath(); + int currentMachine = -1; + int currentFirstIndex = -1; + int currentLastIndex = -1; + + Iterator iter = criticalPath.iterator(); + Task currentTask; + if (iter.hasNext()) { + currentTask = iter.next(); + currentMachine = order.instance.machine(currentTask); + currentFirstIndex = order.getIndexOfTaskOnMachine(currentMachine, currentTask); + currentLastIndex = currentFirstIndex; + } + while (iter.hasNext()) { + currentTask = iter.next(); + if (currentMachine == order.instance.machine(currentTask)) { + currentLastIndex = order.getIndexOfTaskOnMachine(currentMachine, currentTask); + } else { + if (currentLastIndex > currentFirstIndex) { + results.add(new Block(currentMachine, currentFirstIndex, currentLastIndex)); + } + currentMachine = order.instance.machine(currentTask); + currentFirstIndex = order.getIndexOfTaskOnMachine(currentMachine, currentTask); + currentLastIndex = currentFirstIndex; + } + } + if (currentLastIndex > currentFirstIndex) { + results.add(new Block(currentMachine, currentFirstIndex, currentLastIndex)); + } + + return results; } /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */ List neighbors(Block block) { - throw new UnsupportedOperationException(); - + ArrayList swaps = new ArrayList<>(); + if (block.lastTask - block.firstTask == 1) { + swaps.add(new Swap(block.machine, block.firstTask, block.lastTask)); + } else { + swaps.add(new Swap(block.machine, block.firstTask, block.firstTask + 1)); + swaps.add(new Swap(block.machine, block.lastTask - 1, block.lastTask)); + } + return swaps; } - } diff --git a/src/test/java/jobshop/solvers/GreedySolverTest.java b/src/test/java/jobshop/solvers/GreedySolverTest.java index 917f591..4075bc2 100644 --- a/src/test/java/jobshop/solvers/GreedySolverTest.java +++ b/src/test/java/jobshop/solvers/GreedySolverTest.java @@ -116,4 +116,121 @@ public class GreedySolverTest { } } } + + @Test + public void testEST_SPT() { + List instancesNames = BestKnownResults.instancesMatching("la"); + instancesNames.addAll(BestKnownResults.instancesMatching("ft")); + + List instances = instancesNames.stream().map(name -> { + Instance instance = null; + try { + instance = Instance.fromFile(Paths.get("instances/", name)); + } catch (IOException e) { + e.printStackTrace(); + } + return instance; + }).collect(Collectors.toList()); + + GreedySolver solver = new GreedySolver(EST_SPT); + Result result; + for (int i = 0; i < instances.size(); i++) { + result = solver.solve(instances.get(i), 100000); + assert result.schedule.get().isValid(); + if (BestKnownResults.isKnown(instancesNames.get(i))) { + assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i)); + } + } + } + + @Test + public void testEST_LPT() throws IOException { + List instancesNames = BestKnownResults.instancesMatching("la"); + instancesNames.addAll(BestKnownResults.instancesMatching("ft")); + + List instances = instancesNames.stream().map(name -> { + Instance instance = null; + try { + instance = Instance.fromFile(Paths.get("instances/", name)); + } catch (IOException e) { + e.printStackTrace(); + } + return instance; + }).collect(Collectors.toList()); + + GreedySolver solver = new GreedySolver(EST_LPT); + Result result; + for (int i = 0; i < instances.size(); i++) { + result = solver.solve(instances.get(i), 100000); + assert result.schedule.get().isValid(); + if (BestKnownResults.isKnown(instancesNames.get(i))) { + assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i)); + } + } + } + + @Test + public void testEST_SRPT() throws IOException { + List instancesNames = BestKnownResults.instancesMatching("la"); + instancesNames.addAll(BestKnownResults.instancesMatching("ft")); + + List instances = instancesNames.stream().map(name -> { + Instance instance = null; + try { + instance = Instance.fromFile(Paths.get("instances/", name)); + } catch (IOException e) { + e.printStackTrace(); + } + return instance; + }).collect(Collectors.toList()); + + GreedySolver solver = new GreedySolver(EST_SRPT); + Result result; + for (int i = 0; i < instances.size(); i++) { + result = solver.solve(instances.get(i), 100000); + assert result.schedule.get().isValid(); + if (BestKnownResults.isKnown(instancesNames.get(i))) { + assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i)); + } + } + } + + @Test + public void testEST_LRPT() throws IOException { + List instancesNames = BestKnownResults.instancesMatching("la"); + instancesNames.addAll(BestKnownResults.instancesMatching("ft")); + + List instances = instancesNames.stream().map(name -> { + Instance instance = null; + try { + instance = Instance.fromFile(Paths.get("instances/", name)); + } catch (IOException e) { + e.printStackTrace(); + } + return instance; + }).collect(Collectors.toList()); + + GreedySolver solver = new GreedySolver(EST_LRPT); + Result result; + for (int i = 0; i < instances.size(); i++) { + result = solver.solve(instances.get(i), 100000); + assert result.schedule.get().isValid(); + if (BestKnownResults.isKnown(instancesNames.get(i))) { + assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i)); + } + } + } + + @Test + public void testSusucre() throws IOException { + + Instance instance = Instance.fromFile(Paths.get("instances/aaa3")); + + GreedySolver solver = new GreedySolver(EST_LRPT); + Result result = solver.solve(instance, 100000); + System.out.println("SCHEDULE EST_LRPT: " + result.schedule.get().toString()); + solver = new GreedySolver(EST_SPT); + result = solver.solve(instance, 100000); + System.out.println("SCHEDULE EST_SPT: " + result.schedule.get().toString()); + } }