This commit is contained in:
Paul Faure 2021-05-21 12:06:45 +02:00
parent 2824abf3a5
commit c604d1ff3e
10 changed files with 209 additions and 10 deletions

Binary file not shown.

View file

@ -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]);
}

View file

@ -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. */

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View 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;
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View 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);
}
}
}
}
}