Compare commits
No commits in common. "8c11d274fc75e0a393e716d43792b7912d3ac756" and "1fb64286940cdc5203fc59d19bd538f34076321a" have entirely different histories.
8c11d274fc
...
1fb6428694
6 changed files with 33 additions and 211 deletions
|
|
@ -1,9 +1,7 @@
|
||||||
package jobshop.encodings;
|
package jobshop.encodings;
|
||||||
|
|
||||||
import jobshop.Instance;
|
import jobshop.Instance;
|
||||||
import jobshop.solvers.neighborhood.Nowicki;
|
|
||||||
|
|
||||||
import java.sql.Array;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -196,25 +194,4 @@ public final class ResourceOrder extends Encoding {
|
||||||
result = 31 * result + Arrays.hashCode(nextFreeSlot);
|
result = 31 * result + Arrays.hashCode(nextFreeSlot);
|
||||||
return result;
|
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();
|
best = order.toSchedule().get().makespan();
|
||||||
System.out.println("\u001b[32m" + "Current best makespam : " + best + "\u001b[0m, "
|
System.out.println("\u001b[32m" + "Current best makespam : " + best + "\u001b[0m, "
|
||||||
+ "\u001b[33m" + "Number of neighbours : " + getNumberOfNeighbours(neighbours) + "\u001b[0m");
|
+ "\u001b[33m" + "Number of neighbours : " + getNumberOfNeighbours(neighbours) + "\u001b[0m");
|
||||||
} catch (ArrayIndexOutOfBoundsException e) { // no solution found ==> stop
|
} catch (Exception e) { // no solution found ==> stop
|
||||||
bestFound = true;
|
bestFound = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ public class GreedySolver implements Solver {
|
||||||
|
|
||||||
/** All possible priorities for the greedy solver. */
|
/** All possible priorities for the greedy solver. */
|
||||||
public enum Priority {
|
public enum Priority {
|
||||||
SPT, LRPT, EST_SPT, EST_LRPT
|
SPT, LPT, SRPT, LRPT, EST_SPT, EST_LPT, EST_SRPT, EST_LRPT
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Priority that the solver should use. */
|
/** Priority that the solver should use. */
|
||||||
|
|
@ -54,6 +54,20 @@ public class GreedySolver implements Solver {
|
||||||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||||
.toArray(Task[]::new)[0]
|
.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:
|
case LRPT:
|
||||||
return(
|
return(
|
||||||
lTask.stream()
|
lTask.stream()
|
||||||
|
|
@ -79,6 +93,21 @@ public class GreedySolver implements Solver {
|
||||||
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
.sorted(Comparator.comparing(e -> heuristiqueSPT(e, instance)))
|
||||||
.toArray(Task[]::new)[0]
|
.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:
|
case EST_LRPT:
|
||||||
|
|
||||||
// find the minimal next execution time value
|
// find the minimal next execution time value
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ public interface Solver {
|
||||||
case "desc_est_spt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SPT));
|
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_est_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
|
||||||
case "desc_multi": return new DescentSolverMultiStart(new Nowicki());
|
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);
|
default: throw new RuntimeException("Unknown solver: "+ name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
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.*;
|
|
||||||
|
|
||||||
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;
|
|
||||||
// Create an array to store the cycle
|
|
||||||
ArrayList<Integer> historic = new ArrayList<Integer>();
|
|
||||||
|
|
||||||
/*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
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we have a cycle */
|
|
||||||
if (isCycle(historic, result.toSchedule().get())){
|
|
||||||
System.out.println("CYCLE");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isCycle(ArrayList historic, Schedule schedule){
|
|
||||||
historic.add(schedule.hashCode());
|
|
||||||
Boolean found = false;
|
|
||||||
Boolean result = true;
|
|
||||||
int indexCycle = 0;
|
|
||||||
int testTurtle = 0;
|
|
||||||
int testRabbit = 0;
|
|
||||||
if (historic.size() > 20) {
|
|
||||||
historic.remove(0);
|
|
||||||
}
|
|
||||||
int rabbit = 2;
|
|
||||||
for (int turtle = 1; turtle < (historic.size()/2) - 1; turtle ++){
|
|
||||||
if (historic.get(turtle) == historic.get(rabbit)){
|
|
||||||
indexCycle = turtle;
|
|
||||||
found = true;
|
|
||||||
testTurtle = turtle;
|
|
||||||
testRabbit = rabbit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rabbit = 2*turtle;
|
|
||||||
}
|
|
||||||
if (found){
|
|
||||||
for (int i = indexCycle; i < historic.size() - rabbit; i++)
|
|
||||||
if (historic.get(testTurtle) != historic.get(testRabbit)){
|
|
||||||
result = false;
|
|
||||||
testTurtle ++;
|
|
||||||
testRabbit ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result && found){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -8,6 +8,8 @@ import java.util.List;
|
||||||
* a set of closely related solutions.
|
* a set of closely related solutions.
|
||||||
*/
|
*/
|
||||||
public abstract class Neighborhood {
|
public abstract class Neighborhood {
|
||||||
|
|
||||||
/** Generates all neighbors for the current solution. */
|
/** Generates all neighbors for the current solution. */
|
||||||
public abstract List<ResourceOrder> generateNeighbors(ResourceOrder current);
|
public abstract List<ResourceOrder> generateNeighbors(ResourceOrder current);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue