Browse Source

Complete documentation + equals/hashCode for encodings

Arthur Bit-Monnot 5 months ago
parent
commit
c98accd114

+ 7
- 4
doc/src/encodings.md View File

@@ -2,10 +2,11 @@
2 2
 
3 3
 Several encoding and associated utilities are provided in the `jobshop.encodings` package.
4 4
 The abstract class `Encoding` provides a common interface for all encodings.
5
+The only requirement for an encoding is to transform it self into a `Schedule`.
5 6
 
6 7
 ## Schedule
7 8
 
8
-The `Schedule` has direct encoding of a solution: it associates every task in the jobshop to a start time.
9
+The `Schedule` is direct encoding of a solution: it associates every task in the jobshop instance to a start time.
9 10
 
10 11
 It plays a particular role as it is the standard way of representing a solution. As a consequence, all other encodings must provide a way to produce a schedule.
11 12
 
@@ -19,7 +20,7 @@ Convenience methods:
19 20
 
20 21
  ## NumJobs
21 22
 
22
- The `NumJobs` encoding consists of a sequence of job numbers. To produce a schedule, one should iterate on the job numbers and tries to schedule *as early as possible* the next task of the job.
23
+ The `NumJobs` encoding consists of a sequence of job numbers. To produce a schedule, one should iterate on the job numbers and try to schedule *as early as possible* the next task of the job.
23 24
 
24 25
  For instance the encoding `[0 0 1 1 0 1]` will produce a schedule by trying to place as early as possible the following tasks (in this order):
25 26
 
@@ -35,7 +36,7 @@ Convenience methods:
35 36
 
36 37
 The resource order encoding specifies the order in which each machine will process its tasks.
37 38
 
38
-Each machine is associated with an array of task that specifies the order on which the task must be scheduled on the machine.
39
+Each machine is associated with an array of tasks that specifies the order on which the tasks must be scheduled on the machine.
39 40
 
40 41
 For instance, the encoding:
41 42
 
@@ -45,4 +46,6 @@ For instance, the encoding:
45 46
  machine 2: [(1, 2), (0, 2)]
46 47
  ```
47 48
 
48
- Specifies that the first machine (machine 0) will first process the second task of the first job `(0, 1)` and only when it is finished can start processing the first task of the second job `(1, 0)`.
49
+ Specifies that the first machine (machine 0) will first process the second task of the first job `(0, 1)` and only when it is finished can start processing the first task of the second job `(1, 0)`.
50
+
51
+ Unlike `JobNumbers`, the `ResourceOrder` encoding might represent invalid solutions. In this case, its `toSchedule()` method will return an empty result.

+ 12
- 10
doc/src/solvers.md View File

@@ -4,14 +4,19 @@
4 4
 
5 5
 `jobshop.solvers.Solver` provides a common interface for all solvers.
6 6
 
7
+Implementing the `Solver` interface requires implementing a method `solve(Instance instance, long deadline)` where:
7 8
 
8
-## Basic solver
9
+ - `instance` is the jobshop instance that should be solved.
10
+ - `deadline` is the absolute time by which the solver should have exited. This deadline is in milliseconds and can be compared with the result of `System.currentTimeMillis()`.
9 11
 
10
-A very simple solver that tries to schedule all first tasks, then all second tasks, then all third tasks, ...
12
+ The `solve()` method should return a `Result` object, that provides the found solution as a `Schedule` and the cause for exiting.
13
+
14
+## `BasicSolver`
11 15
 
12
-It does so using the `JobNumbers` encoding
16
+A very simple solver that tries to schedule all first tasks, then all second tasks, then all third tasks, ...
17
+It does so using the `JobNumbers` encoding.
13 18
 
14
-## Random solver
19
+## `RandomSolver`
15 20
 
16 21
 Another very simple solver based on the `JobNumbers` encoding.
17 22
 At each iteration, the solver generates a new random solution keeps it if it the best one found so far.
@@ -19,14 +24,11 @@ At each iteration, the solver generates a new random solution keeps it if it the
19 24
 It repeats this process until the deadline to produce a result is met and finally returns the best solution found.
20 25
 
21 26
 
22
-## Greedy solver
27
+## `GreedySolver`
23 28
 
24 29
 The greedy solver is not implemented yet. 
25 30
 Its constructor accepts a parameter that specifies the priority that should be used to produce solutions.
26 31
 
27
-## Descent Solver
28
-
29
-
30
-### Neighborhoods
32
+## `DescentSolver`
31 33
 
32
-TODO
34
+Not implemented yet. It should use the *Nowicki and Smutnicki* neighborhood for which some initial code is provided in the `jobshop.solver.neighborhood` package.

+ 2
- 2
src/main/java/jobshop/BestKnownResults.java View File

@@ -10,7 +10,7 @@ import java.util.stream.Collectors;
10 10
  * Note that the best known result might not have been proven to be the optimal solution
11 11
  * for the instance.
12 12
  */
13
-public class BestKnownResults {
13
+public final class BestKnownResults {
14 14
 
15 15
     /**
16 16
      * Checks whether we have data available for the provided instance.
@@ -35,7 +35,7 @@ public class BestKnownResults {
35 35
     }
36 36
 
37 37
     /**
38
-     * Returns the best known result for the given instance name.
38
+     * Returns the best known result for the given instance.
39 39
      * @param instanceName Instance of which we want to retrieve the best result.
40 40
      * @return Best makespan that has ever been found for this instance.
41 41
      */

+ 2
- 1
src/main/java/jobshop/Instance.java View File

@@ -9,7 +9,8 @@ import java.util.Iterator;
9 9
 import java.util.Scanner;
10 10
 import java.util.stream.Collectors;
11 11
 
12
-public class Instance {
12
+/** Represents an instance of a JobShop problem. */
13
+public final class Instance {
13 14
 
14 15
     /** Name of the instance. Same as the filename from which the instance is loaded. */
15 16
     public final String name;

+ 1
- 0
src/main/java/jobshop/MainTest.java View File

@@ -9,6 +9,7 @@ import jobshop.solvers.GreedySolver;
9 9
 import java.io.IOException;
10 10
 import java.nio.file.Paths;
11 11
 
12
+/** A java main classes for testing purposes. */
12 13
 public class MainTest {
13 14
 
14 15
     public static void main(String[] args) {

+ 18
- 2
src/main/java/jobshop/encodings/JobNumbers.java View File

@@ -4,11 +4,12 @@ import jobshop.Instance;
4 4
 
5 5
 import java.util.Arrays;
6 6
 import java.util.Comparator;
7
+import java.util.Objects;
7 8
 import java.util.Optional;
8 9
 import java.util.stream.IntStream;
9 10
 
10 11
 /** Encoding of the solution of a jobshop problem by job numbers. */
11
-public class JobNumbers extends Encoding {
12
+public final class JobNumbers extends Encoding {
12 13
 
13 14
     /** A numJobs * numTasks array containing the representation by job numbers. */
14 15
     public final int[] jobs;
@@ -25,7 +26,7 @@ public class JobNumbers extends Encoding {
25 26
         Arrays.fill(jobs, -1);
26 27
     }
27 28
 
28
-    /** Cerates a new encoding based on the given schedule. */
29
+    /** Creates a new encoding based on the given schedule. */
29 30
     public JobNumbers(Schedule schedule) {
30 31
         super(schedule.instance);
31 32
 
@@ -87,4 +88,19 @@ public class JobNumbers extends Encoding {
87 88
     public String toString() {
88 89
         return Arrays.toString(Arrays.copyOfRange(jobs,0, nextToSet));
89 90
     }
91
+
92
+    @Override
93
+    public boolean equals(Object o) {
94
+        if (this == o) return true;
95
+        if (o == null || getClass() != o.getClass()) return false;
96
+        JobNumbers that = (JobNumbers) o;
97
+        return nextToSet == that.nextToSet && Arrays.equals(jobs, that.jobs);
98
+    }
99
+
100
+    @Override
101
+    public int hashCode() {
102
+        int result = Objects.hash(nextToSet);
103
+        result = 31 * result + Arrays.hashCode(jobs);
104
+        return result;
105
+    }
90 106
 }

+ 25
- 5
src/main/java/jobshop/encodings/ResourceOrder.java View File

@@ -7,7 +7,8 @@ import java.util.Comparator;
7 7
 import java.util.Optional;
8 8
 import java.util.stream.IntStream;
9 9
 
10
-public class ResourceOrder extends Encoding {
10
+/** Encoding of a solution by the ordering of tasks on each machine. */
11
+public final class ResourceOrder extends Encoding {
11 12
 
12 13
     // for each machine m, taskByMachine[m] is an array of tasks to be
13 14
     // executed on this machine in the same order
@@ -55,9 +56,11 @@ public class ResourceOrder extends Encoding {
55 56
     /** Enqueues a task for the given job on the machine. We automatically, find the task
56 57
      * that must be executed on this particular machine. */
57 58
     public void addToMachine(int machine, int jobNumber) {
58
-        addTaskToMachine(machine, new Task(jobNumber, instance.task_with_machine(jobNumber, machine)));
59
+        Task taskToEnqueue = new Task(jobNumber, instance.task_with_machine(jobNumber, machine));
60
+        addTaskToMachine(machine, taskToEnqueue);
59 61
     }
60 62
 
63
+    /** Adds the given task to the queue of the given machine. */
61 64
     public void addTaskToMachine(int machine, Task task) {
62 65
         tasksByMachine[machine][nextFreeSlot[machine]] = task;
63 66
         nextFreeSlot[machine] += 1;
@@ -76,8 +79,8 @@ public class ResourceOrder extends Encoding {
76 79
     /** Exchange the order of two tasks that are scheduled on a given machine.
77 80
      *
78 81
      * @param machine Machine on which the two tasks appear (line on which to perform the exchange)
79
-     * @param indexTask1 Position of the first task on the machine (column of the first element)
80
-     * @param indexTask2 Position of the second task on the machine (column of the second element)
82
+     * @param indexTask1 Position of the first task in the machine's queue
83
+     * @param indexTask2 Position of the second task in the machine's queue
81 84
      */
82 85
     public void swapTasks(int machine, int indexTask1, int indexTask2) {
83 86
         Task tmp = tasksByMachine[machine][indexTask1];
@@ -138,7 +141,10 @@ public class ResourceOrder extends Encoding {
138 141
         return Optional.of(schedule);
139 142
     }
140 143
 
141
-    /** Creates an exact copy of this resource order. */
144
+    /** Creates an exact copy of this resource order.
145
+     *
146
+     * May fail if the resource order does not represent a valid solution.
147
+     */
142 148
     public ResourceOrder copy() {
143 149
         var schedule = this.toSchedule();
144 150
         if (schedule.isEmpty()) {
@@ -165,4 +171,18 @@ public class ResourceOrder extends Encoding {
165 171
         return s.toString();
166 172
     }
167 173
 
174
+    @Override
175
+    public boolean equals(Object o) {
176
+        if (this == o) return true;
177
+        if (o == null || getClass() != o.getClass()) return false;
178
+        ResourceOrder that = (ResourceOrder) o;
179
+        return Arrays.deepEquals(tasksByMachine, that.tasksByMachine) && Arrays.equals(nextFreeSlot, that.nextFreeSlot);
180
+    }
181
+
182
+    @Override
183
+    public int hashCode() {
184
+        int result = Arrays.hashCode(tasksByMachine);
185
+        result = 31 * result + Arrays.hashCode(nextFreeSlot);
186
+        return result;
187
+    }
168 188
 }

+ 1
- 1
src/main/java/jobshop/encodings/Task.java View File

@@ -14,7 +14,7 @@ public final class Task {
14 14
     /** Index of the task inside the job. */
15 15
     public final int task;
16 16
 
17
-
17
+    /** Creates a new Task object (job, task). */
18 18
     public Task(int job, int task) {
19 19
         this.job = job;
20 20
         this.task = task;

+ 1
- 1
src/main/java/jobshop/solvers/BasicSolver.java View File

@@ -14,7 +14,7 @@ public class BasicSolver implements Solver {
14 14
         JobNumbers sol = new JobNumbers(instance);
15 15
         for(int t = 0 ; t<instance.numTasks ; t++) {
16 16
             for(int j = 0 ; j<instance.numJobs ; j++) {
17
-                sol.jobs[sol.nextToSet++] = j;
17
+                sol.addTask(j);
18 18
             }
19 19
         }
20 20
 

+ 6
- 0
src/main/java/jobshop/solvers/DescentSolver.java View File

@@ -5,11 +5,17 @@ import jobshop.Result;
5 5
 import jobshop.encodings.ResourceOrder;
6 6
 import jobshop.solvers.neighborhood.Neighborhood;
7 7
 
8
+/** An empty shell to implement a descent solver. */
8 9
 public class DescentSolver implements Solver {
9 10
 
10 11
     final Neighborhood<ResourceOrder> neighborhood;
11 12
     final Solver baseSolver;
12 13
 
14
+    /** Creates a new descent solver with a given neighborhood and a solver for the initial solution.
15
+     *
16
+     * @param neighborhood Neighborhood object that should be used to generates neighbor solutions to the current candidate.
17
+     * @param baseSolver A solver to provide the initial solution.
18
+     */
13 19
     public DescentSolver(Neighborhood<ResourceOrder> neighborhood, Solver baseSolver) {
14 20
         this.neighborhood = neighborhood;
15 21
         this.baseSolver = baseSolver;

+ 5
- 0
src/main/java/jobshop/solvers/GreedySolver.java View File

@@ -3,13 +3,18 @@ package jobshop.solvers;
3 3
 import jobshop.Instance;
4 4
 import jobshop.Result;
5 5
 
6
+/** An empty shell to implement a greedy solver. */
6 7
 public class GreedySolver implements Solver {
7 8
 
9
+    /** All possible priorities for the greedy solver. */
8 10
     public enum Priority {
9 11
         SPT, LPT, SRPT, LRPT, EST_SPT, EST_LPT, EST_SRPT, EST_LRPT
10 12
     }
11 13
 
14
+    /** Priority that the solver should use. */
12 15
     final Priority priority;
16
+
17
+    /** Creates a new greedy solver that will use the given priority. */
13 18
     public GreedySolver(Priority p) {
14 19
         this.priority = p;
15 20
     }

+ 7
- 3
src/main/java/jobshop/solvers/RandomSolver.java View File

@@ -18,12 +18,16 @@ public class RandomSolver implements Solver {
18 18
 
19 19
         JobNumbers sol = new JobNumbers(instance);
20 20
 
21
+        // initialize a first solution to the problem.
21 22
         for(int j = 0 ; j<instance.numJobs ; j++) {
22 23
             for(int t = 0 ; t<instance.numTasks ; t++) {
23
-                sol.jobs[sol.nextToSet++] = j;
24
+                sol.addTask(j);
24 25
             }
25 26
         }
27
+        // best solution is currently the initial one
26 28
         Optional<Schedule> best = sol.toSchedule();
29
+
30
+        // while we have some time left, generate new solutions by shuffling the current one
27 31
         while(deadline - System.currentTimeMillis() > 1) {
28 32
             shuffleArray(sol.jobs, generator);
29 33
             Optional<Schedule> candidate = sol.toSchedule();
@@ -39,12 +43,12 @@ public class RandomSolver implements Solver {
39 43
     }
40 44
 
41 45
     /** Simple Fisher–Yates array shuffling */
42
-    private static void shuffleArray(int[] array, Random random)
46
+    private static void shuffleArray(int[] array, Random randomNumberGenerator)
43 47
     {
44 48
         int index;
45 49
         for (int i = array.length - 1; i > 0; i--)
46 50
         {
47
-            index = random.nextInt(i + 1);
51
+            index = randomNumberGenerator.nextInt(i + 1);
48 52
             if (index != i)
49 53
             {
50 54
                 array[index] ^= array[i];

+ 4
- 1
src/main/java/jobshop/solvers/neighborhood/Neighbor.java View File

@@ -3,7 +3,10 @@ package jobshop.solvers.neighborhood;
3 3
 import jobshop.encodings.Encoding;
4 4
 
5 5
 /** This class provides a representation of neighbor by allowing to transform
6
- * a solution in a particular encoding Enc into the neighbor and back.*/
6
+ * a solution in a particular encoding Enc into the neighbor and back.
7
+ *
8
+ * @param <Enc> A subclass of Encoding for that can be transformed into a neighbor and back.
9
+ * */
7 10
 public abstract class Neighbor<Enc extends Encoding> {
8 11
 
9 12
     /** Transform the given solution into the neighbor. */

+ 1
- 1
src/main/java/jobshop/solvers/neighborhood/Neighborhood.java View File

@@ -7,7 +7,7 @@ import java.util.List;
7 7
 /** For a particular encoding Enc, a neighborhood allow the generation of the neighbors of
8 8
  * a particular solution.
9 9
  *
10
- * @param <Enc> A subcless of Encoding for which this encoding can generate neighbors.
10
+ * @param <Enc> A subclass of Encoding for which this encoding can generate neighbors.
11 11
  */
12 12
 public abstract class Neighborhood<Enc extends Encoding> {
13 13
 

Loading…
Cancel
Save