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()];
|
||||
// average distance to best known result for each solver
|
||||
float[] avg_distances = new float[solversToTest.size()];
|
||||
float[] avg_voisins = new float[solversToTest.size()];
|
||||
|
||||
try {
|
||||
// header of the result table :
|
||||
|
@ -88,11 +89,11 @@ public class Main {
|
|||
// - name of each column (second line)
|
||||
output.print( " ");
|
||||
for(String s : solversToTest)
|
||||
output.printf("%-30s", s);
|
||||
output.printf("%-38s", s);
|
||||
output.println();
|
||||
output.print("instance size best ");
|
||||
for(String s : solversToTest) {
|
||||
output.print("runtime makespan ecart ");
|
||||
output.print("runtime makespan ecart voisins ");
|
||||
}
|
||||
output.println();
|
||||
|
||||
|
@ -135,8 +136,8 @@ public class Main {
|
|||
float dist = 100f * (makespan - bestKnown) / (float) bestKnown;
|
||||
avg_runtimes[solverId] += (float) runtime / (float) instances.size();
|
||||
avg_distances[solverId] += dist / (float) instances.size();
|
||||
|
||||
output.printf("%7d %8s %5.1f ", runtime, makespan, dist);
|
||||
avg_voisins[solverId] += (float) result.getVoisinsVisites() / (float) instances.size();
|
||||
output.printf("%7d %8s %5.1f %7d ", runtime, makespan, dist, result.getVoisinsVisites());
|
||||
output.flush();
|
||||
}
|
||||
output.println();
|
||||
|
@ -146,7 +147,7 @@ public class Main {
|
|||
// we have finished all benchmarks, compute the average solve time and distance of each solver.
|
||||
output.printf("%-8s %-5s %4s ", "AVG", "-", "-");
|
||||
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. */
|
||||
public final ExitCause cause;
|
||||
|
||||
private int voisinsVisites;
|
||||
|
||||
/** Creates a new Result object with the corresponding fields. */
|
||||
public Result(Instance instance, Optional<Schedule> schedule, ExitCause cause) {
|
||||
this.instance = instance;
|
||||
this.schedule = schedule;
|
||||
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. */
|
||||
|
|
|
@ -38,14 +38,16 @@ public class DescentSolver implements Solver {
|
|||
boolean ended = false;
|
||||
int bestMakespan;
|
||||
Neighbor<ResourceOrder> bestNeighbor;
|
||||
int voisinsVisites = 0;
|
||||
|
||||
while (!ended) {
|
||||
while (!ended && deadline - System.currentTimeMillis() > 0) {
|
||||
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()) {
|
||||
voisinsVisites++;
|
||||
Neighbor<ResourceOrder> neighbor = iter.next();
|
||||
neighbor.applyOn(resourceOrder);
|
||||
try {
|
||||
|
@ -65,7 +67,15 @@ public class DescentSolver implements Solver {
|
|||
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;
|
||||
|
||||
//Itérations
|
||||
while (!this.tachesRestantes.isEmpty()) {
|
||||
while (!this.tachesRestantes.isEmpty() && deadline - System.currentTimeMillis() > 0) {
|
||||
task = this.getTask(instance);
|
||||
int startTime = getEarliestDate(instance, 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));
|
||||
}
|
||||
}
|
||||
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_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 "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
|
||||
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. */
|
||||
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;
|
||||
|
||||
/** 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.t1 = t1;
|
||||
this.t2 = t2;
|
||||
|
@ -88,6 +88,38 @@ public class Nowicki extends Neighborhood<ResourceOrder> {
|
|||
public void undoApplyOn(ResourceOrder current) {
|
||||
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