No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ResourceOrder.java 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package jobshop.encodings;
  2. import jobshop.Instance;
  3. import java.util.Arrays;
  4. import java.util.Comparator;
  5. import java.util.Optional;
  6. import java.util.stream.IntStream;
  7. /** Encoding of a solution by the ordering of tasks on each machine. */
  8. public final class ResourceOrder extends Encoding {
  9. // for each machine m, taskByMachine[m] is an array of tasks to be
  10. // executed on this machine in the same order
  11. final Task[][] tasksByMachine;
  12. // for each machine, indicate how many tasks have been initialized
  13. final int[] nextFreeSlot;
  14. /** Creates a new empty resource order. */
  15. public ResourceOrder(Instance instance)
  16. {
  17. super(instance);
  18. // matrix of null elements (null is the default value of objects)
  19. tasksByMachine = new Task[instance.numMachines][instance.numJobs];
  20. // no task scheduled on any machine (0 is the default value)
  21. nextFreeSlot = new int[instance.numMachines];
  22. }
  23. /** Creates a resource order from a schedule. */
  24. public ResourceOrder(Schedule schedule)
  25. {
  26. super(schedule.instance);
  27. Instance pb = schedule.instance;
  28. this.tasksByMachine = new Task[pb.numMachines][];
  29. this.nextFreeSlot = new int[instance.numMachines];
  30. for(int m = 0; m<schedule.instance.numMachines ; m++) {
  31. final int machine = m;
  32. // for this machine, find all tasks that are executed on it and sort them by their start time
  33. tasksByMachine[m] =
  34. IntStream.range(0, pb.numJobs) // all job numbers
  35. .mapToObj(j -> new Task(j, pb.task_with_machine(j, machine))) // all tasks on this machine (one per job)
  36. .sorted(Comparator.comparing(t -> schedule.startTime(t.job, t.task))) // sorted by start time
  37. .toArray(Task[]::new); // as new array and store in tasksByMachine
  38. // indicate that all tasks have been initialized for machine m
  39. nextFreeSlot[m] = instance.numJobs;
  40. }
  41. }
  42. /** Adds the given task to the queue of the given machine. */
  43. public void addTaskToMachine(int machine, Task task) {
  44. if(instance.machine(task) != machine) {
  45. throw new RuntimeException("Task " + task + " cannot be scheduled on machine "+machine);
  46. }
  47. tasksByMachine[machine][nextFreeSlot[machine]] = task;
  48. nextFreeSlot[machine] += 1;
  49. }
  50. /** Returns the i-th task scheduled on a particular machine.
  51. *
  52. * @param machine Machine on which the task to retrieve is scheduled.
  53. * @param taskIndex Index of the task in the queue for this machine.
  54. * @return The i-th task scheduled on a machine.
  55. */
  56. public Task getTaskOfMachine(int machine, int taskIndex) {
  57. return tasksByMachine[machine][taskIndex];
  58. }
  59. /** Returns the index of a particular task scheduled on a particular machine.
  60. *
  61. * @param machine Machine on which the task to retrieve is scheduled.
  62. * @param task Task in the queue for this machine.
  63. * @return The index of the task scheduled on a machine.
  64. */
  65. public int getIndexOfTaskOnMachine(int machine, Task task) {
  66. int i = 0;
  67. boolean found = false;
  68. while (i<instance.numJobs && !found) {
  69. found = getTaskOfMachine(machine, i).equals(task);
  70. i++;
  71. }
  72. return i - 1;
  73. }
  74. /** Exchange the order of two tasks that are scheduled on a given machine.
  75. *
  76. * @param machine Machine on which the two tasks appear (line on which to perform the exchange)
  77. * @param indexTask1 Position of the first task in the machine's queue
  78. * @param indexTask2 Position of the second task in the machine's queue
  79. */
  80. public void swapTasks(int machine, int indexTask1, int indexTask2) {
  81. Task tmp = tasksByMachine[machine][indexTask1];
  82. tasksByMachine[machine][indexTask1] = tasksByMachine[machine][indexTask2];
  83. tasksByMachine[machine][indexTask2] = tmp;
  84. }
  85. @Override
  86. public Optional<Schedule> toSchedule() {
  87. // indicate for each task that have been scheduled, its start time
  88. Schedule schedule = new Schedule(instance);
  89. // for each job, how many tasks have been scheduled (0 initially)
  90. int[] nextToScheduleByJob = new int[instance.numJobs];
  91. // for each machine, how many tasks have been scheduled (0 initially)
  92. int[] nextToScheduleByMachine = new int[instance.numMachines];
  93. // for each machine, earliest time at which the machine can be used
  94. int[] releaseTimeOfMachine = new int[instance.numMachines];
  95. // loop while there remains a job that has unscheduled tasks
  96. while(IntStream.range(0, instance.numJobs).anyMatch(m -> nextToScheduleByJob[m] < instance.numTasks)) {
  97. // selects a task that has no unscheduled predecessor on its job and machine :
  98. // - it is the next to be schedule on a machine
  99. // - it is the next to be scheduled on its job
  100. // If there is no such task, we have cyclic dependency and the solution is invalid.
  101. Optional<Task> schedulable =
  102. IntStream.range(0, instance.numMachines) // all machines ...
  103. .filter(m -> nextToScheduleByMachine[m] < instance.numJobs) // ... with unscheduled jobs
  104. .mapToObj(m -> this.tasksByMachine[m][nextToScheduleByMachine[m]]) // tasks that are next to schedule on a machine ...
  105. .filter(task -> task.task == nextToScheduleByJob[task.job]) // ... and on their job
  106. .findFirst(); // select the first one if any
  107. if(schedulable.isPresent()) {
  108. // we have a schedulable task, lets call it t
  109. Task t = schedulable.get();
  110. int machine = instance.machine(t.job, t.task);
  111. // compute the earliest start time (est) of the task
  112. int est = t.task == 0 ? 0 : schedule.endTime(t.job, t.task-1);
  113. est = Math.max(est, releaseTimeOfMachine[instance.machine(t)]);
  114. schedule.setStartTime(t.job, t.task, est);
  115. // mark the task as scheduled
  116. nextToScheduleByJob[t.job]++;
  117. nextToScheduleByMachine[machine]++;
  118. // increase the release time of the machine
  119. releaseTimeOfMachine[machine] = est + instance.duration(t.job, t.task);
  120. } else {
  121. // no tasks are schedulable, there is no solution for this resource ordering
  122. return Optional.empty();
  123. }
  124. }
  125. // we exited the loop : all tasks have been scheduled successfully
  126. return Optional.of(schedule);
  127. }
  128. /** Creates an exact copy of this resource order.
  129. *
  130. * May fail if the resource order does not represent a valid solution.
  131. */
  132. public ResourceOrder copy() {
  133. var schedule = this.toSchedule();
  134. if (schedule.isEmpty()) {
  135. throw new RuntimeException("Cannot copy an invalid ResourceOrder");
  136. } else {
  137. return new ResourceOrder(schedule.get());
  138. }
  139. }
  140. @Override
  141. public String toString()
  142. {
  143. StringBuilder s = new StringBuilder();
  144. for(int m=0; m < instance.numMachines; m++)
  145. {
  146. s.append("Machine ").append(m).append(" : ");
  147. for(int j=0; j<instance.numJobs; j++)
  148. {
  149. s.append(tasksByMachine[m][j]).append(" ; ");
  150. }
  151. s.append("\n");
  152. }
  153. return s.toString();
  154. }
  155. @Override
  156. public boolean equals(Object o) {
  157. if (this == o) return true;
  158. if (o == null || getClass() != o.getClass()) return false;
  159. ResourceOrder that = (ResourceOrder) o;
  160. return Arrays.deepEquals(tasksByMachine, that.tasksByMachine) && Arrays.equals(nextFreeSlot, that.nextFreeSlot);
  161. }
  162. @Override
  163. public int hashCode() {
  164. int result = Arrays.hashCode(tasksByMachine);
  165. result = 31 * result + Arrays.hashCode(nextFreeSlot);
  166. return result;
  167. }
  168. }