Taboo OK
This commit is contained in:
parent
2824abf3a5
commit
c604d1ff3e
10 changed files with 209 additions and 10 deletions
BIN
doc/src/TP_Meta-20-21-Version2.pdf
Normal file
BIN
doc/src/TP_Meta-20-21-Version2.pdf
Normal file
Binary file not shown.
|
@ -81,6 +81,7 @@ public class Main {
|
||||||
float[] avg_runtimes = new float[solversToTest.size()];
|
float[] avg_runtimes = new float[solversToTest.size()];
|
||||||
// average distance to best known result for each solver
|
// average distance to best known result for each solver
|
||||||
float[] avg_distances = new float[solversToTest.size()];
|
float[] avg_distances = new float[solversToTest.size()];
|
||||||
|
float[] avg_voisins = new float[solversToTest.size()];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// header of the result table :
|
// header of the result table :
|
||||||
|
@ -88,11 +89,11 @@ public class Main {
|
||||||
// - name of each column (second line)
|
// - name of each column (second line)
|
||||||
output.print( " ");
|
output.print( " ");
|
||||||
for(String s : solversToTest)
|
for(String s : solversToTest)
|
||||||
output.printf("%-30s", s);
|
output.printf("%-38s", s);
|
||||||
output.println();
|
output.println();
|
||||||
output.print("instance size best ");
|
output.print("instance size best ");
|
||||||
for(String s : solversToTest) {
|
for(String s : solversToTest) {
|
||||||
output.print("runtime makespan ecart ");
|
output.print("runtime makespan ecart voisins ");
|
||||||
}
|
}
|
||||||
output.println();
|
output.println();
|
||||||
|
|
||||||
|
@ -135,8 +136,8 @@ public class Main {
|
||||||
float dist = 100f * (makespan - bestKnown) / (float) bestKnown;
|
float dist = 100f * (makespan - bestKnown) / (float) bestKnown;
|
||||||
avg_runtimes[solverId] += (float) runtime / (float) instances.size();
|
avg_runtimes[solverId] += (float) runtime / (float) instances.size();
|
||||||
avg_distances[solverId] += dist / (float) instances.size();
|
avg_distances[solverId] += dist / (float) instances.size();
|
||||||
|
avg_voisins[solverId] += (float) result.getVoisinsVisites() / (float) instances.size();
|
||||||
output.printf("%7d %8s %5.1f ", runtime, makespan, dist);
|
output.printf("%7d %8s %5.1f %7d ", runtime, makespan, dist, result.getVoisinsVisites());
|
||||||
output.flush();
|
output.flush();
|
||||||
}
|
}
|
||||||
output.println();
|
output.println();
|
||||||
|
@ -146,7 +147,7 @@ public class Main {
|
||||||
// we have finished all benchmarks, compute the average solve time and distance of each solver.
|
// we have finished all benchmarks, compute the average solve time and distance of each solver.
|
||||||
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 ", avg_runtimes[solverId], "-", avg_distances[solverId]);
|
output.printf("%7.1f %8s %5.1f %7.1f ", avg_runtimes[solverId], "-", avg_distances[solverId], avg_voisins[solverId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,11 +16,22 @@ public class Result {
|
||||||
/** Reason why the solver exited with this solution. */
|
/** Reason why the solver exited with this solution. */
|
||||||
public final ExitCause cause;
|
public final ExitCause cause;
|
||||||
|
|
||||||
|
private int voisinsVisites;
|
||||||
|
|
||||||
/** Creates a new Result object with the corresponding fields. */
|
/** Creates a new Result object with the corresponding fields. */
|
||||||
public Result(Instance instance, Optional<Schedule> schedule, ExitCause cause) {
|
public Result(Instance instance, Optional<Schedule> schedule, ExitCause cause) {
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
this.schedule = schedule;
|
this.schedule = schedule;
|
||||||
this.cause = cause;
|
this.cause = cause;
|
||||||
|
this.voisinsVisites = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVoisinsVisites() {
|
||||||
|
return voisinsVisites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVoisinsVisites(int voisinsVisites) {
|
||||||
|
this.voisinsVisites = voisinsVisites;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Documents the reason why a solver returned the solution. */
|
/** Documents the reason why a solver returned the solution. */
|
||||||
|
|
|
@ -38,14 +38,16 @@ public class DescentSolver implements Solver {
|
||||||
boolean ended = false;
|
boolean ended = false;
|
||||||
int bestMakespan;
|
int bestMakespan;
|
||||||
Neighbor<ResourceOrder> bestNeighbor;
|
Neighbor<ResourceOrder> bestNeighbor;
|
||||||
|
int voisinsVisites = 0;
|
||||||
|
|
||||||
while (!ended) {
|
while (!ended && deadline - System.currentTimeMillis() > 0) {
|
||||||
schedule = resourceOrder.toSchedule().get();
|
schedule = resourceOrder.toSchedule().get();
|
||||||
bestMakespan = schedule.makespan();
|
bestMakespan = schedule.makespan();
|
||||||
bestNeighbor = null;
|
bestNeighbor = null;
|
||||||
List<Neighbor<ResourceOrder>> generatedNeighbors = neighborhood.generateNeighbors(resourceOrder);
|
List<Neighbor<ResourceOrder>> generatedNeighbors = neighborhood.generateNeighbors(resourceOrder);
|
||||||
Iterator<Neighbor<ResourceOrder>> iter = generatedNeighbors.iterator();
|
Iterator<Neighbor<ResourceOrder>> iter = generatedNeighbors.iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
|
voisinsVisites++;
|
||||||
Neighbor<ResourceOrder> neighbor = iter.next();
|
Neighbor<ResourceOrder> neighbor = iter.next();
|
||||||
neighbor.applyOn(resourceOrder);
|
neighbor.applyOn(resourceOrder);
|
||||||
try {
|
try {
|
||||||
|
@ -65,7 +67,15 @@ public class DescentSolver implements Solver {
|
||||||
bestNeighbor.applyOn(resourceOrder);
|
bestNeighbor.applyOn(resourceOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.ProvedOptimal);
|
|
||||||
|
Result result;
|
||||||
|
if (ended) {
|
||||||
|
result = new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.Blocked);
|
||||||
|
} else {
|
||||||
|
result = new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.Timeout);
|
||||||
|
}
|
||||||
|
result.setVoisinsVisites(voisinsVisites);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -179,7 +179,7 @@ public class GreedySolver implements Solver {
|
||||||
Task nextTask;
|
Task nextTask;
|
||||||
|
|
||||||
//Itérations
|
//Itérations
|
||||||
while (!this.tachesRestantes.isEmpty()) {
|
while (!this.tachesRestantes.isEmpty() && deadline - System.currentTimeMillis() > 0) {
|
||||||
task = this.getTask(instance);
|
task = this.getTask(instance);
|
||||||
int startTime = getEarliestDate(instance, task);
|
int startTime = getEarliestDate(instance, task);
|
||||||
resourceOrder.addTaskToMachine(instance.machine(task), task);
|
resourceOrder.addTaskToMachine(instance.machine(task), task);
|
||||||
|
@ -190,6 +190,13 @@ public class GreedySolver implements Solver {
|
||||||
this.addTask(instance, new Task(task.job, task.task + 1));
|
this.addTask(instance, new Task(task.job, task.task + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Result (instance, resourceOrder.toSchedule(), ProvedOptimal);
|
|
||||||
|
Result result;
|
||||||
|
if (this.tachesRestantes.isEmpty()) {
|
||||||
|
result = new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.Blocked);
|
||||||
|
} else {
|
||||||
|
result = new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.Timeout);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,14 @@ public interface Solver {
|
||||||
case "descent_est_lpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LPT));
|
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_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));
|
case "descent_est_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
|
||||||
|
case "taboo_spt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.SPT));
|
||||||
|
case "taboo_lpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.LPT));
|
||||||
|
case "taboo_srpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.SRPT));
|
||||||
|
case "taboo_lrpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.LRPT));
|
||||||
|
case "taboo_est_spt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SPT));
|
||||||
|
case "taboo_est_lpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LPT));
|
||||||
|
case "taboo_est_srpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SRPT));
|
||||||
|
case "taboo_est_lrpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
|
||||||
// TODO: add new solvers
|
// TODO: add new solvers
|
||||||
default: throw new RuntimeException("Unknown solver: "+ name);
|
default: throw new RuntimeException("Unknown solver: "+ name);
|
||||||
}
|
}
|
||||||
|
|
101
src/main/java/jobshop/solvers/TabooSolver.java
Normal file
101
src/main/java/jobshop/solvers/TabooSolver.java
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
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 TabooSolver implements Solver {
|
||||||
|
|
||||||
|
final Neighborhood<ResourceOrder> neighborhood;
|
||||||
|
final Solver baseSolver;
|
||||||
|
int maxIter = 100;
|
||||||
|
int dureeTaboo = 4;
|
||||||
|
|
||||||
|
/** Creates a new taboo solver with a given neighborhood and a solver for the initial solution.
|
||||||
|
*
|
||||||
|
* @param neighborhood Neighborhood object that should be used to generates neighbor solutions to the current candidate.
|
||||||
|
* @param baseSolver A solver to provide the initial solution.
|
||||||
|
*/
|
||||||
|
public TabooSolver(Neighborhood<ResourceOrder> neighborhood, Solver baseSolver) {
|
||||||
|
this.neighborhood = neighborhood;
|
||||||
|
this.baseSolver = baseSolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result solve(Instance instance, long deadline) {
|
||||||
|
Schedule schedule = baseSolver.solve(instance, deadline).schedule.get();
|
||||||
|
ResourceOrder resourceOrder = new ResourceOrder(schedule);
|
||||||
|
int nbKey = Nowicki.Swap.getNbKey(instance.numMachines, instance.numJobs);
|
||||||
|
int[] taboo = new int[nbKey];
|
||||||
|
for (int i = 0; i<nbKey; i++) {
|
||||||
|
taboo[i] = -1;
|
||||||
|
}
|
||||||
|
int starMakespan = resourceOrder.toSchedule().get().makespan();
|
||||||
|
ResourceOrder starResourceOrder = resourceOrder.copy();
|
||||||
|
int bestMakespan;
|
||||||
|
Neighbor<ResourceOrder> bestNeighbor;
|
||||||
|
int voisinsVisites = 0;
|
||||||
|
int k = 0;
|
||||||
|
while (deadline - System.currentTimeMillis() > 0 && k < maxIter) {
|
||||||
|
k++;
|
||||||
|
bestMakespan = Integer.MAX_VALUE;
|
||||||
|
bestNeighbor = null;
|
||||||
|
List<Neighbor<ResourceOrder>> generatedNeighbors = neighborhood.generateNeighbors(resourceOrder);
|
||||||
|
Iterator<Neighbor<ResourceOrder>> iter = generatedNeighbors.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
voisinsVisites++;
|
||||||
|
Neighbor<ResourceOrder> neighbor = iter.next();
|
||||||
|
Nowicki.Swap currentSwap = (Nowicki.Swap) neighbor.getChange();
|
||||||
|
int currentMakespan = Integer.MAX_VALUE;
|
||||||
|
try {
|
||||||
|
neighbor.applyOn(resourceOrder);
|
||||||
|
Schedule currentSchedule = resourceOrder.toSchedule().get();
|
||||||
|
currentMakespan = currentSchedule.makespan();
|
||||||
|
neighbor.undoApplyOn(resourceOrder);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
if (taboo[currentSwap.generateKey(instance.numJobs)] < k || currentMakespan < starMakespan) {
|
||||||
|
neighbor.applyOn(resourceOrder);
|
||||||
|
try {
|
||||||
|
Schedule currentSchedule = resourceOrder.toSchedule().get();
|
||||||
|
currentMakespan = currentSchedule.makespan();
|
||||||
|
if (currentMakespan < bestMakespan) {
|
||||||
|
bestMakespan = currentMakespan;
|
||||||
|
bestNeighbor = neighbor;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
neighbor.undoApplyOn(resourceOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestNeighbor != null) {
|
||||||
|
Nowicki.Swap swap = (Nowicki.Swap) bestNeighbor.getChange();
|
||||||
|
taboo[swap.generateKey(instance.numJobs)] = k + dureeTaboo;
|
||||||
|
bestNeighbor.applyOn(resourceOrder);
|
||||||
|
if (bestMakespan < starMakespan) {
|
||||||
|
starMakespan = bestMakespan;
|
||||||
|
starResourceOrder = resourceOrder.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result result;
|
||||||
|
result = new Result(instance, starResourceOrder.toSchedule(), Result.ExitCause.Timeout);
|
||||||
|
result.setVoisinsVisites(voisinsVisites);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,4 +15,7 @@ public abstract class Neighbor<Enc extends Encoding> {
|
||||||
/** Transform the neighbor back into the original solution. */
|
/** Transform the neighbor back into the original solution. */
|
||||||
public abstract void undoApplyOn(Enc current);
|
public abstract void undoApplyOn(Enc current);
|
||||||
|
|
||||||
|
/** Renvoi l'objet caracterisant le changement **/
|
||||||
|
public abstract Object getChange();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ public class Nowicki extends Neighborhood<ResourceOrder> {
|
||||||
public final int t2;
|
public final int t2;
|
||||||
|
|
||||||
/** Creates a new swap of two tasks. */
|
/** Creates a new swap of two tasks. */
|
||||||
Swap(int machine, int t1, int t2) {
|
public Swap(int machine, int t1, int t2) {
|
||||||
this.machine = machine;
|
this.machine = machine;
|
||||||
this.t1 = t1;
|
this.t1 = t1;
|
||||||
this.t2 = t2;
|
this.t2 = t2;
|
||||||
|
@ -88,6 +88,38 @@ public class Nowicki extends Neighborhood<ResourceOrder> {
|
||||||
public void undoApplyOn(ResourceOrder current) {
|
public void undoApplyOn(ResourceOrder current) {
|
||||||
current.swapTasks(machine, t1, t2);
|
current.swapTasks(machine, t1, t2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int generateKey(int nbJobs) {
|
||||||
|
int myT1;
|
||||||
|
int myT2;
|
||||||
|
if (t2 < t1) {
|
||||||
|
myT1 = t2;
|
||||||
|
myT2 = t1;
|
||||||
|
} else {
|
||||||
|
myT1 = t1;
|
||||||
|
myT2 = t2;
|
||||||
|
}
|
||||||
|
int a = (((nbJobs - 1)*nbJobs*(machine + 1))/2);
|
||||||
|
int b = (((nbJobs-1-myT1)*(nbJobs-myT1))/2);
|
||||||
|
int c = (myT2 - myT1 - 1);
|
||||||
|
//System.out.println(a + " " + b + " " + c);
|
||||||
|
return a - b + c;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getNbKey(int nbMachines, int nbJobs) {
|
||||||
|
return ((nbJobs - 1)*nbJobs*nbMachines)/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals (Object o) {
|
||||||
|
Swap obj = (Swap) o;
|
||||||
|
return (machine == obj.machine && ((t1 == obj.t1 && t2 == obj.t2) || (t1 == obj.t2 && t2 == obj.t1 )));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getChange() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
26
src/test/java/jobshop/swap/SwapTest.java
Normal file
26
src/test/java/jobshop/swap/SwapTest.java
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package jobshop.swap;
|
||||||
|
|
||||||
|
import jobshop.solvers.neighborhood.Nowicki;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
||||||
|
public class SwapTest {
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int nbJobs = 5;
|
||||||
|
int nbMachine = 8;
|
||||||
|
int k = -1;
|
||||||
|
for (int machine = 0; machine<nbMachine; machine++) {
|
||||||
|
for (int t1 = 0; t1<nbJobs; t1++) {
|
||||||
|
for (int t2 = (t1 + 1); t2<nbJobs; t2++) {
|
||||||
|
Nowicki.Swap swap = new Nowicki.Swap(machine, t1, t2);
|
||||||
|
int key = swap.generateKey(nbJobs);
|
||||||
|
k++;
|
||||||
|
//System.out.println("m : " + machine + "; t1 : " + t1 + "; t2 : " + t2);
|
||||||
|
//System.out.println("Key : " + key + "; K : " + k);
|
||||||
|
assert (key == k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue