Descente OK
This commit is contained in:
parent
d97d8141a1
commit
2824abf3a5
6 changed files with 327 additions and 42 deletions
|
@ -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<instance.numJobs && !found) {
|
||||
found = getTaskOfMachine(machine, i).equals(task);
|
||||
i++;
|
||||
}
|
||||
return i - 1;
|
||||
}
|
||||
|
||||
/** Exchange the order of two tasks that are scheduled on a given machine.
|
||||
*
|
||||
* @param machine Machine on which the two tasks appear (line on which to perform the exchange)
|
||||
|
|
|
@ -3,7 +3,17 @@ package jobshop.solvers;
|
|||
import jobshop.Instance;
|
||||
import jobshop.Result;
|
||||
import jobshop.encodings.ResourceOrder;
|
||||
import jobshop.encodings.Schedule;
|
||||
import jobshop.solvers.neighborhood.Neighbor;
|
||||
import jobshop.solvers.neighborhood.Neighborhood;
|
||||
import jobshop.solvers.neighborhood.Nowicki;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** An empty shell to implement a descent solver. */
|
||||
public class DescentSolver implements Solver {
|
||||
|
@ -23,7 +33,39 @@ public class DescentSolver implements Solver {
|
|||
|
||||
@Override
|
||||
public Result solve(Instance instance, long deadline) {
|
||||
throw new UnsupportedOperationException();
|
||||
Schedule schedule = baseSolver.solve(instance, deadline).schedule.get();
|
||||
ResourceOrder resourceOrder = new ResourceOrder(schedule);
|
||||
boolean ended = false;
|
||||
int bestMakespan;
|
||||
Neighbor<ResourceOrder> bestNeighbor;
|
||||
|
||||
while (!ended) {
|
||||
schedule = resourceOrder.toSchedule().get();
|
||||
bestMakespan = schedule.makespan();
|
||||
bestNeighbor = null;
|
||||
List<Neighbor<ResourceOrder>> generatedNeighbors = neighborhood.generateNeighbors(resourceOrder);
|
||||
Iterator<Neighbor<ResourceOrder>> iter = generatedNeighbors.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Neighbor<ResourceOrder> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ public class GreedySolver implements Solver {
|
|||
final Priority priority;
|
||||
|
||||
final ArrayList<Task> 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<instance.numTasks; i++) {
|
||||
sigmaT1 += instance.duration(t1.job, i);
|
||||
}
|
||||
for (i=t2.task; i<instance.numTasks; i++) {
|
||||
sigmaT2 += instance.duration(t2.job, i);
|
||||
}
|
||||
rt = sigmaT1 <= sigmaT2;
|
||||
}
|
||||
break;
|
||||
case EST_LRPT:
|
||||
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<instance.numTasks; i++) {
|
||||
sigmaT1 += instance.duration(t1.job, i);
|
||||
}
|
||||
for (i=t2.task; i<instance.numTasks; i++) {
|
||||
sigmaT2 += instance.duration(t2.job, i);
|
||||
}
|
||||
rt = sigmaT1 >= sigmaT2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return rt;
|
||||
}
|
||||
|
||||
private void addTask(Instance instance, Task task) throws Exception {
|
||||
Iterator<Task> 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<Task> 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<instance.numJobs; i++) {
|
||||
try {
|
||||
this.addTask(instance, new Task(i,0));
|
||||
} catch (Exception e) {
|
||||
System.out.println("ERREUR POLITIQUE DE PRIORITE INCONNUE");
|
||||
System.exit(2);
|
||||
}
|
||||
this.addTask(instance, new Task(i,0));
|
||||
this.jobFreeDate[i] = 0;
|
||||
}
|
||||
for (i=0; i<instance.numMachines; i++) {
|
||||
this.machineFreeDate[i] = 0;
|
||||
}
|
||||
ResourceOrder resourceOrder = new ResourceOrder(instance);
|
||||
Task task;
|
||||
|
@ -117,16 +180,14 @@ public class GreedySolver implements Solver {
|
|||
|
||||
//Itérations
|
||||
while (!this.tachesRestantes.isEmpty()) {
|
||||
task = this.getTask();
|
||||
task = this.getTask(instance);
|
||||
int startTime = getEarliestDate(instance, task);
|
||||
resourceOrder.addTaskToMachine(instance.machine(task), task);
|
||||
this.machineFreeDate[instance.machine(task)] = startTime + instance.duration(task);
|
||||
this.jobFreeDate[task.job] = startTime + instance.duration(task);
|
||||
nextTask = instance.nextTask(task);
|
||||
if (nextTask != null) {
|
||||
try {
|
||||
this.addTask(instance, new Task(task.job, task.task + 1));
|
||||
} catch (Exception e) {
|
||||
System.out.println("ERREUR POLITIQUE DE PRIORITE INCONNUE");
|
||||
System.exit(2);
|
||||
}
|
||||
this.addTask(instance, new Task(task.job, task.task + 1));
|
||||
}
|
||||
}
|
||||
return new Result (instance, resourceOrder.toSchedule(), ProvedOptimal);
|
||||
|
|
|
@ -2,6 +2,8 @@ package jobshop.solvers;
|
|||
|
||||
import jobshop.Instance;
|
||||
import jobshop.Result;
|
||||
import jobshop.encodings.ResourceOrder;
|
||||
import jobshop.solvers.neighborhood.Nowicki;
|
||||
|
||||
/** Common interface that must implemented by all solvers. */
|
||||
public interface Solver {
|
||||
|
@ -28,6 +30,14 @@ public interface Solver {
|
|||
case "est_lpt": return new GreedySolver(GreedySolver.Priority.EST_LPT);
|
||||
case "est_srpt": return new GreedySolver(GreedySolver.Priority.EST_SRPT);
|
||||
case "est_lrpt": return new GreedySolver(GreedySolver.Priority.EST_LRPT);
|
||||
case "descent_spt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.SPT));
|
||||
case "descent_lpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.LPT));
|
||||
case "descent_srpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.SRPT));
|
||||
case "descent_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.LRPT));
|
||||
case "descent_est_spt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SPT));
|
||||
case "descent_est_lpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LPT));
|
||||
case "descent_est_srpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SRPT));
|
||||
case "descent_est_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
|
||||
// TODO: add new solvers
|
||||
default: throw new RuntimeException("Unknown solver: "+ name);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package jobshop.solvers.neighborhood;
|
||||
|
||||
import jobshop.encodings.ResourceOrder;
|
||||
import jobshop.encodings.Task;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/** Implementation of the Nowicki and Smutnicki neighborhood.
|
||||
|
@ -78,13 +80,13 @@ public class Nowicki extends Neighborhood<ResourceOrder> {
|
|||
/** 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<ResourceOrder> {
|
|||
|
||||
/** Returns a list of all the blocks of the critical path. */
|
||||
List<Block> blocksOfCriticalPath(ResourceOrder order) {
|
||||
throw new UnsupportedOperationException();
|
||||
ArrayList<Block> results = new ArrayList<>();
|
||||
|
||||
List<Task> criticalPath = order.toSchedule().get().criticalPath();
|
||||
int currentMachine = -1;
|
||||
int currentFirstIndex = -1;
|
||||
int currentLastIndex = -1;
|
||||
|
||||
Iterator<Task> 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<Swap> neighbors(Block block) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
ArrayList<Swap> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -116,4 +116,121 @@ public class GreedySolverTest {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEST_SPT() {
|
||||
List<String> instancesNames = BestKnownResults.instancesMatching("la");
|
||||
instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
|
||||
|
||||
List<Instance> 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<String> instancesNames = BestKnownResults.instancesMatching("la");
|
||||
instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
|
||||
|
||||
List<Instance> 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<String> instancesNames = BestKnownResults.instancesMatching("la");
|
||||
instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
|
||||
|
||||
List<Instance> 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<String> instancesNames = BestKnownResults.instancesMatching("la");
|
||||
instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
|
||||
|
||||
List<Instance> 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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue