192 lines
7.1 KiB
Java
192 lines
7.1 KiB
Java
package jobshop.solvers;
|
|
|
|
import jobshop.Instance;
|
|
import jobshop.encodings.Schedule;
|
|
import jobshop.encodings.Task;
|
|
|
|
import java.util.*;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
|
|
/** An empty shell to implement a greedy solver. */
|
|
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
|
|
}
|
|
|
|
/** Priority that the solver should use. */
|
|
final Priority priority;
|
|
/** Creates a new greedy solver that will use the given priority. */
|
|
public GreedySolver(Priority p) {
|
|
this.priority = p;
|
|
|
|
}
|
|
|
|
private Integer heuristiqueSPT(Task t, Instance instance){
|
|
return instance.duration(t);
|
|
}
|
|
private Integer heuristiqueLPT(Task t, Instance instance){
|
|
return instance.duration(t);
|
|
}
|
|
private Integer heuristiqueSRPT(Task t, Instance instance){
|
|
return instance.duration(t);
|
|
}
|
|
private Integer heuristiqueLRPT(Task t, Instance instance){
|
|
int sum = 0;
|
|
// we sum all durations starting at the current tasks' in the job
|
|
for (int i = t.task; i < instance.numTasks; i++){
|
|
sum += instance.duration(t.job, i);
|
|
}
|
|
return sum;
|
|
}
|
|
private Integer heuristiqueEST(Task t, Instance instance, int[] machineStatus, int[] jobStatus){
|
|
return Integer.max(machineStatus[instance.machine(t)], jobStatus[t.job]);
|
|
}
|
|
private Integer heuristiqueEST_SRPT(Task t, Instance instance){
|
|
return instance.duration(t);
|
|
}
|
|
private Integer heuristiqueEST_LRPT(Task t, Instance instance){
|
|
return instance.duration(t);
|
|
}
|
|
|
|
|
|
public Task findNextTask(ArrayList<Task> lTask, Instance instance, int[] machineStatus, int[] jobStatus){
|
|
switch (priority) {
|
|
case SPT:
|
|
return(
|
|
lTask.stream()
|
|
.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()
|
|
.max(Comparator.comparing(e -> heuristiqueLRPT(e, instance)))
|
|
.get() // it returns an optional
|
|
);
|
|
case EST_SPT:
|
|
|
|
// find the minimal next execution time value
|
|
int EST_SPT_minValue = lTask.stream()
|
|
.map(e -> heuristiqueEST(e, instance,machineStatus, jobStatus))
|
|
.sorted()
|
|
.toArray(Integer[]::new)[0];
|
|
|
|
// find all tasks with this next execution time value
|
|
Task[] EST_SPT_closestTasks = lTask.stream()
|
|
.filter(e -> heuristiqueEST(e, instance,machineStatus, jobStatus) == EST_SPT_minValue)
|
|
.toArray(Task[]::new);
|
|
|
|
// run SPT (see above) on this
|
|
return(
|
|
Arrays.stream(EST_SPT_closestTasks)
|
|
.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
|
|
int EST_LRPT_minValue = lTask.stream()
|
|
.map(e -> heuristiqueEST(e, instance,machineStatus, jobStatus))
|
|
.sorted()
|
|
.toArray(Integer[]::new)[0];
|
|
|
|
// find all tasks with this next execution time value
|
|
Task[] EST_LRPT_closestTasks = lTask.stream()
|
|
.filter(e -> heuristiqueEST(e, instance,machineStatus, jobStatus) == EST_LRPT_minValue)
|
|
.toArray(Task[]::new);
|
|
|
|
// run LRPT (see above) on this
|
|
return(
|
|
Arrays.stream(EST_LRPT_closestTasks)
|
|
.max(Comparator.comparing(e -> heuristiqueLRPT(e, instance)))
|
|
.get() // it returns an optional
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
public Optional<Schedule> solve(Instance instance, long deadline) {
|
|
return solve(instance,deadline,5);
|
|
}
|
|
|
|
public Optional<Schedule> solve(Instance instance, long deadline, int percentRandom) {
|
|
Random r = new Random();
|
|
|
|
// keeps track of the next time the machine is free
|
|
int[] machineStatus = new int[instance.numMachines];
|
|
// keeps track of the next time the job is free
|
|
int[] jobStatus = new int[instance.numJobs];
|
|
Arrays.fill(machineStatus,0);
|
|
Arrays.fill(jobStatus,0);
|
|
|
|
int time ;
|
|
Schedule schedule = new Schedule(instance);
|
|
ArrayList<Task> possibleTasks = new ArrayList<>();
|
|
/* Initialization */
|
|
for (int i = 0; i < instance.numJobs; i++){
|
|
possibleTasks.add(new Task(i, 0));
|
|
}
|
|
|
|
/* Main Loop*/
|
|
while(possibleTasks.size() > 0){
|
|
Task task;
|
|
if (r.nextInt(100) < percentRandom) {
|
|
task = possibleTasks.get(r.nextInt(possibleTasks.size()));
|
|
} else {
|
|
task = findNextTask(possibleTasks, instance, machineStatus, jobStatus);
|
|
}
|
|
possibleTasks.remove(task);
|
|
|
|
// Update schedule
|
|
time = Integer.max(machineStatus[instance.machine(task)], jobStatus[task.job]);
|
|
schedule.setStartTime(task.job, task.task, time);
|
|
|
|
// recalculate next free time for job/machine
|
|
machineStatus[instance.machine(task)] = time + instance.duration(task);
|
|
jobStatus[task.job] = time + instance.duration(task);
|
|
|
|
// if there are any more remaining tasks : add the next one
|
|
if ((task.task + 1) < instance.numTasks) {
|
|
possibleTasks.add(new Task(task.job, task.task + 1));
|
|
}
|
|
}
|
|
return Optional.of(schedule);
|
|
}
|
|
|
|
|
|
}
|