Added TabooSolver solver and did testing
This commit is contained in:
parent
1fb6428694
commit
d26d947b12
6 changed files with 171 additions and 33 deletions
|
@ -1,7 +1,9 @@
|
|||
package jobshop.encodings;
|
||||
|
||||
import jobshop.Instance;
|
||||
import jobshop.solvers.neighborhood.Nowicki;
|
||||
|
||||
import java.sql.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
|
@ -194,4 +196,25 @@ public final class ResourceOrder extends Encoding {
|
|||
result = 31 * result + Arrays.hashCode(nextFreeSlot);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public int[] getSwap(ResourceOrder o){ // returns [machineNb,task1,task2]
|
||||
int[] ret = {0,0,0};
|
||||
if (this.equals(o)){
|
||||
ret = new int[]{-1, -1, -1};
|
||||
}
|
||||
Task[][] thisTasks = this.getTasksByMachine();
|
||||
Task[][] otherTasks = o.getTasksByMachine();
|
||||
for(int i=0; i< instance.numMachines; i++){
|
||||
for(int j=0; j< instance.numJobs; j++){
|
||||
if (thisTasks[i][j] != otherTasks[i][j]){
|
||||
ret[0] = i;
|
||||
ret[1] = j;
|
||||
ret[2] = j+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -48,7 +48,7 @@ public class DescentSolver implements Solver {
|
|||
best = order.toSchedule().get().makespan();
|
||||
System.out.println("\u001b[32m" + "Current best makespam : " + best + "\u001b[0m, "
|
||||
+ "\u001b[33m" + "Number of neighbours : " + getNumberOfNeighbours(neighbours) + "\u001b[0m");
|
||||
} catch (Exception e) { // no solution found ==> stop
|
||||
} catch (ArrayIndexOutOfBoundsException e) { // no solution found ==> stop
|
||||
bestFound = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public class GreedySolver implements Solver {
|
|||
|
||||
/** All possible priorities for the greedy solver. */
|
||||
public enum Priority {
|
||||
SPT, LPT, SRPT, LRPT, EST_SPT, EST_LPT, EST_SRPT, EST_LRPT
|
||||
SPT, LRPT, EST_SPT, EST_LRPT
|
||||
}
|
||||
|
||||
/** Priority that the solver should use. */
|
||||
|
@ -54,20 +54,6 @@ public class GreedySolver implements Solver {
|
|||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||
.toArray(Task[]::new)[0]
|
||||
);
|
||||
case LPT:
|
||||
// TODO
|
||||
return(
|
||||
lTask.stream()
|
||||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||
.toArray(Task[]::new)[0]
|
||||
);
|
||||
case SRPT:
|
||||
// TODO
|
||||
return(
|
||||
lTask.stream()
|
||||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||
.toArray(Task[]::new)[0]
|
||||
);
|
||||
case LRPT:
|
||||
return(
|
||||
lTask.stream()
|
||||
|
@ -93,21 +79,6 @@ public class GreedySolver implements Solver {
|
|||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||
.toArray(Task[]::new)[0]
|
||||
);
|
||||
|
||||
case EST_LPT:
|
||||
// TODO
|
||||
return(
|
||||
lTask.stream()
|
||||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||
.toArray(Task[]::new)[0]
|
||||
);
|
||||
case EST_SRPT:
|
||||
//TODO
|
||||
return(
|
||||
lTask.stream()
|
||||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||
.toArray(Task[]::new)[0]
|
||||
);
|
||||
case EST_LRPT:
|
||||
|
||||
// find the minimal next execution time value
|
||||
|
|
|
@ -29,6 +29,8 @@ public interface Solver {
|
|||
case "desc_est_spt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SPT));
|
||||
case "desc_est_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
|
||||
case "desc_multi": return new DescentSolverMultiStart(new Nowicki());
|
||||
case "taboo_est_spt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SPT));
|
||||
case "taboo_est_lrpt": return new TabooSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
|
||||
default: throw new RuntimeException("Unknown solver: "+ name);
|
||||
}
|
||||
}
|
||||
|
|
144
src/main/java/jobshop/solvers/TabooSolver.java
Normal file
144
src/main/java/jobshop/solvers/TabooSolver.java
Normal file
|
@ -0,0 +1,144 @@
|
|||
package jobshop.solvers;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import jobshop.Instance;
|
||||
import jobshop.encodings.ResourceOrder;
|
||||
import jobshop.encodings.Schedule;
|
||||
import jobshop.solvers.neighborhood.Neighborhood;
|
||||
|
||||
import java.time.format.ResolverStyle;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class TabooSolver implements Solver {
|
||||
final Neighborhood neighborhood;
|
||||
final Solver baseSolver;
|
||||
|
||||
/** Creates a new descent 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 neighborhood, Solver baseSolver) {
|
||||
this.neighborhood = neighborhood;
|
||||
this.baseSolver = baseSolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Schedule> solve(Instance instance, long deadline, int randomness, int randomRunNumber) {
|
||||
Schedule schedule = baseSolver.solve(instance, deadline,randomness,randomRunNumber).get();
|
||||
ResourceOrder order = new ResourceOrder(schedule);
|
||||
ResourceOrder result = order;
|
||||
|
||||
/*for output writing*/
|
||||
FileWriter fw = null;
|
||||
try {
|
||||
fw = new FileWriter("output.csv");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
PrintWriter pw = new PrintWriter(fw);
|
||||
|
||||
|
||||
//init forbidden states : Array of forbidden swaps
|
||||
int[][][] forbiddenNeighbours = new int[instance.numMachines][instance.numJobs][instance.numJobs];
|
||||
int[] zeroArray = new int[instance.numJobs];
|
||||
Arrays.fill(zeroArray,0);
|
||||
|
||||
for (int i = 0; i < instance.numMachines; i++) {
|
||||
Arrays.fill(forbiddenNeighbours[i],zeroArray);
|
||||
}
|
||||
int iterationCount = 0;
|
||||
Boolean noMoreSolution = false;
|
||||
Integer best = Integer.MAX_VALUE;
|
||||
ResourceOrder bestRO = order;
|
||||
ResourceOrder previousRO;
|
||||
while(System.currentTimeMillis() < deadline && !noMoreSolution) {
|
||||
List<ResourceOrder> neighbours = neighborhood.generateNeighbors(order);
|
||||
previousRO = order;
|
||||
try {
|
||||
Integer finalBest = best;
|
||||
try { // is there an improving best ?
|
||||
order = neighbours.stream()
|
||||
.filter(e -> e.toSchedule().get().isValid()) // removes invalid solutions
|
||||
.filter(e -> e.toSchedule().get().makespan() < finalBest) // removes solutions that do not improve
|
||||
.sorted(Comparator.comparing(e -> e.toSchedule().get().makespan())) // sorts with regard to makespan
|
||||
.toArray(ResourceOrder[]::new)[0];
|
||||
result = order;
|
||||
} catch (ArrayIndexOutOfBoundsException e1) {
|
||||
|
||||
/*added to have final variables*/
|
||||
ResourceOrder finalPreviousRO = previousRO;
|
||||
int[][][] finalForbiddenNeighbours = forbiddenNeighbours;
|
||||
int finalIterationCount = iterationCount;
|
||||
|
||||
order = neighbours.stream()
|
||||
.filter(e -> e.toSchedule().get().isValid()) // removes invalid solutions
|
||||
.filter(e -> !isForbidden(e, finalPreviousRO, finalForbiddenNeighbours, finalIterationCount))
|
||||
.sorted(Comparator.comparing(e -> e.toSchedule().get().makespan())) // sorts with regard to makespan
|
||||
.toArray(ResourceOrder[]::new)[0];
|
||||
result = order;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e2) { // no solution found ==> stop
|
||||
|
||||
}
|
||||
System.out.println("\u001b[34m" + "Current makespam : " + result.toSchedule().get().makespan() + "\u001b[0m, "
|
||||
+ "\u001b[32m" + "Current best makespam : " + best + "\u001b[0m, "
|
||||
+ "\u001b[33m" + "Number of neighbours : " + getNumberOfNeighbours(neighbours) + "\u001b[0m, "
|
||||
+ "\u001b[37m" + "Number of non-forbidden neighbours : " + getNumberOfNonForbiddenNeighbours(neighbours,previousRO, forbiddenNeighbours, iterationCount) + "\u001b[0m");
|
||||
|
||||
pw.println(result.toSchedule().get().makespan() + ","
|
||||
+ best + ","
|
||||
+ getNumberOfNeighbours(neighbours) + ","
|
||||
+ getNumberOfNonForbiddenNeighbours(neighbours,previousRO, forbiddenNeighbours, iterationCount));
|
||||
|
||||
|
||||
best = Integer.min(result.toSchedule().get().makespan(),best);
|
||||
if (bestRO.toSchedule().get().makespan() > result.toSchedule().get().makespan()) {
|
||||
bestRO = result;
|
||||
}
|
||||
forbiddenNeighbours = computeNewForbidden(result,previousRO,forbiddenNeighbours,iterationCount);
|
||||
iterationCount++;
|
||||
}
|
||||
|
||||
return bestRO.toSchedule();
|
||||
}
|
||||
// used to compute the number of neighbours seen
|
||||
private int getNumberOfNeighbours(List<ResourceOrder> neighbours) {
|
||||
return neighbours.stream()
|
||||
.filter(e -> e.toSchedule().get().isValid()) // removes invalid solutions
|
||||
.toArray(ResourceOrder[]::new).length;
|
||||
}
|
||||
|
||||
private int getNumberOfNonForbiddenNeighbours(List<ResourceOrder> neighbours, ResourceOrder previous, int[][][] forbiddenNeighbours, int iterationCount) {
|
||||
return neighbours.stream()
|
||||
.filter(e -> e.toSchedule().get().isValid()) // removes invalid solutions
|
||||
.filter(e -> !isForbidden(e, previous, forbiddenNeighbours, iterationCount))
|
||||
.toArray(ResourceOrder[]::new).length;
|
||||
}
|
||||
|
||||
private boolean isForbidden(ResourceOrder ro, ResourceOrder previous, int[][][] forbiddenNeighbours, int iterationCount){
|
||||
int[] changes = ro.getSwap(previous);
|
||||
|
||||
if (changes[0] == -1) {return true;}
|
||||
|
||||
if ((forbiddenNeighbours[changes[0]][changes[1]][changes[2]] == 0)
|
||||
|| (forbiddenNeighbours[changes[0]][changes[1]][changes[2]] < iterationCount - 10 /*to tune*/)){
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private int[][][] computeNewForbidden(ResourceOrder ro, ResourceOrder previous, int[][][] forbiddenNeighbours, int iterationCount){
|
||||
int[] changes = ro.getSwap(previous);
|
||||
if (changes[0] != -1){
|
||||
forbiddenNeighbours[changes[0]][changes[1]][changes[2]] = iterationCount;
|
||||
}
|
||||
return forbiddenNeighbours;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,8 +8,6 @@ import java.util.List;
|
|||
* a set of closely related solutions.
|
||||
*/
|
||||
public abstract class Neighborhood {
|
||||
|
||||
/** Generates all neighbors for the current solution. */
|
||||
public abstract List<ResourceOrder> generateNeighbors(ResourceOrder current);
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue