Browse Source

Descente OK

Paul Faure 2 years ago
parent
commit
2824abf3a5

+ 16
- 0
src/main/java/jobshop/encodings/ResourceOrder.java View File

72
         return tasksByMachine[machine][taskIndex];
72
         return tasksByMachine[machine][taskIndex];
73
     }
73
     }
74
 
74
 
75
+    /** Returns the index of a particular task scheduled on a particular machine.
76
+     *
77
+     * @param machine Machine on which the task to retrieve is scheduled.
78
+     * @param task Task in the queue for this machine.
79
+     * @return The index of the task scheduled on a machine.
80
+     */
81
+    public int getIndexOfTaskOnMachine(int machine, Task task) {
82
+        int i = 0;
83
+        boolean found = false;
84
+        while (i<instance.numJobs && !found) {
85
+            found = getTaskOfMachine(machine, i).equals(task);
86
+            i++;
87
+        }
88
+        return i - 1;
89
+    }
90
+
75
     /** Exchange the order of two tasks that are scheduled on a given machine.
91
     /** Exchange the order of two tasks that are scheduled on a given machine.
76
      *
92
      *
77
      * @param machine Machine on which the two tasks appear (line on which to perform the exchange)
93
      * @param machine Machine on which the two tasks appear (line on which to perform the exchange)

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

3
 import jobshop.Instance;
3
 import jobshop.Instance;
4
 import jobshop.Result;
4
 import jobshop.Result;
5
 import jobshop.encodings.ResourceOrder;
5
 import jobshop.encodings.ResourceOrder;
6
+import jobshop.encodings.Schedule;
7
+import jobshop.solvers.neighborhood.Neighbor;
6
 import jobshop.solvers.neighborhood.Neighborhood;
8
 import jobshop.solvers.neighborhood.Neighborhood;
9
+import jobshop.solvers.neighborhood.Nowicki;
10
+
11
+import java.io.IOException;
12
+import java.nio.file.Paths;
13
+import java.util.ArrayList;
14
+import java.util.Iterator;
15
+import java.util.List;
16
+import java.util.stream.Collectors;
7
 
17
 
8
 /** An empty shell to implement a descent solver. */
18
 /** An empty shell to implement a descent solver. */
9
 public class DescentSolver implements Solver {
19
 public class DescentSolver implements Solver {
23
 
33
 
24
     @Override
34
     @Override
25
     public Result solve(Instance instance, long deadline) {
35
     public Result solve(Instance instance, long deadline) {
26
-        throw new UnsupportedOperationException();
36
+        Schedule schedule = baseSolver.solve(instance, deadline).schedule.get();
37
+        ResourceOrder resourceOrder = new ResourceOrder(schedule);
38
+        boolean ended = false;
39
+        int bestMakespan;
40
+        Neighbor<ResourceOrder> bestNeighbor;
41
+
42
+        while (!ended) {
43
+            schedule = resourceOrder.toSchedule().get();
44
+            bestMakespan = schedule.makespan();
45
+            bestNeighbor = null;
46
+            List<Neighbor<ResourceOrder>> generatedNeighbors = neighborhood.generateNeighbors(resourceOrder);
47
+            Iterator<Neighbor<ResourceOrder>> iter = generatedNeighbors.iterator();
48
+            while (iter.hasNext()) {
49
+                Neighbor<ResourceOrder> neighbor = iter.next();
50
+                neighbor.applyOn(resourceOrder);
51
+                try {
52
+                    Schedule currentSchedule = resourceOrder.toSchedule().get();
53
+                    int currentMakespan = currentSchedule.makespan();
54
+                    if (currentMakespan < bestMakespan) {
55
+                        bestMakespan = currentMakespan;
56
+                        bestNeighbor = neighbor;
57
+                    }
58
+                } catch (Exception e) {
59
+                }
60
+                neighbor.undoApplyOn(resourceOrder);
61
+            }
62
+            if (bestNeighbor == null) {
63
+                ended = true;
64
+            } else {
65
+                bestNeighbor.applyOn(resourceOrder);
66
+            }
67
+        }
68
+        return new Result(instance, resourceOrder.toSchedule(), Result.ExitCause.ProvedOptimal);
27
     }
69
     }
28
 
70
 
29
 }
71
 }

+ 96
- 35
src/main/java/jobshop/solvers/GreedySolver.java View File

23
     final Priority priority;
23
     final Priority priority;
24
 
24
 
25
     final ArrayList<Task> tachesRestantes;
25
     final ArrayList<Task> tachesRestantes;
26
+    int[] machineFreeDate;
27
+    int[] jobFreeDate;
28
+
26
 
29
 
27
 
30
 
28
     /** Creates a new greedy solver that will use the given priority. */
31
     /** Creates a new greedy solver that will use the given priority. */
31
         this.tachesRestantes = new ArrayList<>();
34
         this.tachesRestantes = new ArrayList<>();
32
     }
35
     }
33
 
36
 
37
+    private int getEarliestDate(Instance instance, Task task) {
38
+        return Math.max(machineFreeDate[instance.machine(task)], jobFreeDate[task.job]);
39
+    }
40
+
34
     /** return true if t1 est plus prioritaire que t1 **/
41
     /** return true if t1 est plus prioritaire que t1 **/
35
-    private boolean prioritaire(Instance instance, Task t1, Task t2) throws Exception {
42
+    private boolean prioritaire(Instance instance, Task t1, Task t2) {
36
         boolean rt = false;
43
         boolean rt = false;
37
         switch(priority) {
44
         switch(priority) {
38
             case SPT:
45
             case SPT:
65
                 rt = sigmaT1 >= sigmaT2;
72
                 rt = sigmaT1 >= sigmaT2;
66
                 break;
73
                 break;
67
             case EST_SPT:
74
             case EST_SPT:
68
-                throw new Exception("UNKNOWN PRIORITY");
69
-                //break;
75
+                if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) {
76
+                    rt = true;
77
+                } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) {
78
+                    rt = false;
79
+                } else {
80
+                    rt = instance.duration(t1) <= instance.duration(t2);
81
+                }
82
+                break;
70
             case EST_LPT:
83
             case EST_LPT:
71
-                throw new Exception("UNKNOWN PRIORITY");
72
-                //break;
84
+                if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) {
85
+                    rt = true;
86
+                } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) {
87
+                    rt = false;
88
+                } else {
89
+                    rt = instance.duration(t1) >= instance.duration(t2);
90
+                }
91
+                break;
73
             case EST_SRPT:
92
             case EST_SRPT:
74
-                throw new Exception("UNKNOWN PRIORITY");
75
-                //break;
93
+                if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) {
94
+                    rt = true;
95
+                } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) {
96
+                    rt = false;
97
+                } else {
98
+                    sigmaT1 = 0;
99
+                    sigmaT2 = 0;
100
+                    for (i=t1.task; i<instance.numTasks; i++) {
101
+                        sigmaT1 += instance.duration(t1.job, i);
102
+                    }
103
+                    for (i=t2.task; i<instance.numTasks; i++) {
104
+                        sigmaT2 += instance.duration(t2.job, i);
105
+                    }
106
+                    rt = sigmaT1 <= sigmaT2;
107
+                }
108
+                break;
76
             case EST_LRPT:
109
             case EST_LRPT:
77
-                throw new Exception("UNKNOWN PRIORITY");
78
-                //break;
110
+                if (getEarliestDate(instance, t1) < getEarliestDate(instance, t2)) {
111
+                    rt = true;
112
+                } else if (getEarliestDate(instance, t1) > getEarliestDate(instance, t2)) {
113
+                    rt = false;
114
+                } else {
115
+                    sigmaT1 = 0;
116
+                    sigmaT2 = 0;
117
+                    for (i=t1.task; i<instance.numTasks; i++) {
118
+                        sigmaT1 += instance.duration(t1.job, i);
119
+                    }
120
+                    for (i=t2.task; i<instance.numTasks; i++) {
121
+                        sigmaT2 += instance.duration(t2.job, i);
122
+                    }
123
+                    rt = sigmaT1 >= sigmaT2;
124
+                }
125
+                break;
79
         }
126
         }
80
         return rt;
127
         return rt;
81
     }
128
     }
82
 
129
 
83
-    private void addTask(Instance instance, Task task) throws Exception {
84
-        Iterator<Task> iter = this.tachesRestantes.iterator();
85
-        int index = 0;
86
-        boolean trouve = false;
87
-        while (iter.hasNext() && !trouve) {
88
-            Task current = iter.next();
89
-            if (this.prioritaire(instance, task, current)) {
90
-                trouve = true;
91
-            } else {
92
-                index++;
130
+    private void addTask(Instance instance, Task task) {
131
+        if (priority == Priority.SPT || priority == Priority.LPT || priority == Priority.SRPT || priority == Priority.LRPT) {
132
+            Iterator<Task> iter = this.tachesRestantes.iterator();
133
+            int index = 0;
134
+            boolean trouve = false;
135
+            while (iter.hasNext() && !trouve) {
136
+                Task current = iter.next();
137
+                if (this.prioritaire(instance, task, current)) {
138
+                    trouve = true;
139
+                } else {
140
+                    index++;
141
+                }
93
             }
142
             }
143
+            this.tachesRestantes.add(index, task);
144
+        } else {
145
+            this.tachesRestantes.add(task);
94
         }
146
         }
95
-        this.tachesRestantes.add(index, task);
96
     }
147
     }
97
 
148
 
98
-    private Task getTask() {
99
-        return this.tachesRestantes.remove(0);
149
+    private Task getTask(Instance instance) {
150
+        if (priority == Priority.SPT || priority == Priority.LPT || priority == Priority.SRPT || priority == Priority.LRPT) {
151
+            return this.tachesRestantes.remove(0);
152
+        } else {
153
+            int indexBest = 0;
154
+            int indexChallenger;
155
+            for (indexChallenger = 1; indexChallenger < tachesRestantes.size(); indexChallenger++) {
156
+                if (prioritaire(instance, tachesRestantes.get(indexChallenger), tachesRestantes.get(indexBest))) {
157
+                    indexBest = indexChallenger;
158
+                }
159
+            }
160
+            return  this.tachesRestantes.remove(indexBest);
161
+        }
100
     }
162
     }
101
 
163
 
102
     @Override
164
     @Override
103
     public Result solve(Instance instance, long deadline) {
165
     public Result solve(Instance instance, long deadline) {
104
         //Initialisation
166
         //Initialisation
167
+        jobFreeDate = new int[instance.numJobs];
168
+        machineFreeDate = new int[instance.numMachines];
105
         int i;
169
         int i;
106
         for (i=0; i<instance.numJobs; i++) {
170
         for (i=0; i<instance.numJobs; i++) {
107
-            try {
108
-                this.addTask(instance, new Task(i,0));
109
-            } catch (Exception e) {
110
-                System.out.println("ERREUR POLITIQUE DE PRIORITE INCONNUE");
111
-                System.exit(2);
112
-            }
171
+            this.addTask(instance, new Task(i,0));
172
+            this.jobFreeDate[i] = 0;
173
+        }
174
+        for (i=0; i<instance.numMachines; i++) {
175
+            this.machineFreeDate[i] = 0;
113
         }
176
         }
114
         ResourceOrder resourceOrder = new ResourceOrder(instance);
177
         ResourceOrder resourceOrder = new ResourceOrder(instance);
115
         Task task;
178
         Task task;
117
 
180
 
118
         //Itérations
181
         //Itérations
119
         while (!this.tachesRestantes.isEmpty()) {
182
         while (!this.tachesRestantes.isEmpty()) {
120
-            task = this.getTask();
183
+            task = this.getTask(instance);
184
+            int startTime = getEarliestDate(instance, task);
121
             resourceOrder.addTaskToMachine(instance.machine(task), task);
185
             resourceOrder.addTaskToMachine(instance.machine(task), task);
186
+            this.machineFreeDate[instance.machine(task)] = startTime + instance.duration(task);
187
+            this.jobFreeDate[task.job] = startTime + instance.duration(task);
122
             nextTask = instance.nextTask(task);
188
             nextTask = instance.nextTask(task);
123
             if (nextTask != null) {
189
             if (nextTask != null) {
124
-                try {
125
-                    this.addTask(instance, new Task(task.job, task.task + 1));
126
-                } catch (Exception e) {
127
-                    System.out.println("ERREUR POLITIQUE DE PRIORITE INCONNUE");
128
-                    System.exit(2);
129
-                }
190
+                this.addTask(instance, new Task(task.job, task.task + 1));
130
             }
191
             }
131
         }
192
         }
132
         return new Result (instance, resourceOrder.toSchedule(), ProvedOptimal);
193
         return new Result (instance, resourceOrder.toSchedule(), ProvedOptimal);

+ 10
- 0
src/main/java/jobshop/solvers/Solver.java View File

2
 
2
 
3
 import jobshop.Instance;
3
 import jobshop.Instance;
4
 import jobshop.Result;
4
 import jobshop.Result;
5
+import jobshop.encodings.ResourceOrder;
6
+import jobshop.solvers.neighborhood.Nowicki;
5
 
7
 
6
 /** Common interface that must implemented by all solvers. */
8
 /** Common interface that must implemented by all solvers. */
7
 public interface Solver {
9
 public interface Solver {
28
             case "est_lpt": return new GreedySolver(GreedySolver.Priority.EST_LPT);
30
             case "est_lpt": return new GreedySolver(GreedySolver.Priority.EST_LPT);
29
             case "est_srpt": return new GreedySolver(GreedySolver.Priority.EST_SRPT);
31
             case "est_srpt": return new GreedySolver(GreedySolver.Priority.EST_SRPT);
30
             case "est_lrpt": return new GreedySolver(GreedySolver.Priority.EST_LRPT);
32
             case "est_lrpt": return new GreedySolver(GreedySolver.Priority.EST_LRPT);
33
+            case "descent_spt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.SPT));
34
+            case "descent_lpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.LPT));
35
+            case "descent_srpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.SRPT));
36
+            case "descent_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.LRPT));
37
+            case "descent_est_spt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SPT));
38
+            case "descent_est_lpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LPT));
39
+            case "descent_est_srpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_SRPT));
40
+            case "descent_est_lrpt": return new DescentSolver(new Nowicki(), new GreedySolver(GreedySolver.Priority.EST_LRPT));
31
             // TODO: add new solvers
41
             // TODO: add new solvers
32
             default: throw new RuntimeException("Unknown solver: "+ name);
42
             default: throw new RuntimeException("Unknown solver: "+ name);
33
         }
43
         }

+ 45
- 6
src/main/java/jobshop/solvers/neighborhood/Nowicki.java View File

1
 package jobshop.solvers.neighborhood;
1
 package jobshop.solvers.neighborhood;
2
 
2
 
3
 import jobshop.encodings.ResourceOrder;
3
 import jobshop.encodings.ResourceOrder;
4
+import jobshop.encodings.Task;
4
 
5
 
5
 import java.util.ArrayList;
6
 import java.util.ArrayList;
7
+import java.util.Iterator;
6
 import java.util.List;
8
 import java.util.List;
7
 
9
 
8
 /** Implementation of the Nowicki and Smutnicki neighborhood.
10
 /** Implementation of the Nowicki and Smutnicki neighborhood.
78
         /** Apply this swap on the given ResourceOrder, transforming it into a new solution. */
80
         /** Apply this swap on the given ResourceOrder, transforming it into a new solution. */
79
         @Override
81
         @Override
80
         public void applyOn(ResourceOrder current) {
82
         public void applyOn(ResourceOrder current) {
81
-            throw new UnsupportedOperationException();
83
+            current.swapTasks(machine, t1, t2);
82
         }
84
         }
83
 
85
 
84
         /** Unapply this swap on the neighbor, transforming it back into the original solution. */
86
         /** Unapply this swap on the neighbor, transforming it back into the original solution. */
85
         @Override
87
         @Override
86
         public void undoApplyOn(ResourceOrder current) {
88
         public void undoApplyOn(ResourceOrder current) {
87
-            throw new UnsupportedOperationException();
89
+            current.swapTasks(machine, t1, t2);
88
         }
90
         }
89
     }
91
     }
90
 
92
 
109
 
111
 
110
     /** Returns a list of all the blocks of the critical path. */
112
     /** Returns a list of all the blocks of the critical path. */
111
     List<Block> blocksOfCriticalPath(ResourceOrder order) {
113
     List<Block> blocksOfCriticalPath(ResourceOrder order) {
112
-        throw new UnsupportedOperationException();
114
+        ArrayList<Block> results = new ArrayList<>();
115
+
116
+        List<Task> criticalPath = order.toSchedule().get().criticalPath();
117
+        int currentMachine = -1;
118
+        int currentFirstIndex = -1;
119
+        int currentLastIndex = -1;
120
+
121
+        Iterator<Task> iter = criticalPath.iterator();
122
+        Task currentTask;
123
+        if (iter.hasNext()) {
124
+            currentTask = iter.next();
125
+            currentMachine = order.instance.machine(currentTask);
126
+            currentFirstIndex = order.getIndexOfTaskOnMachine(currentMachine, currentTask);
127
+            currentLastIndex = currentFirstIndex;
128
+        }
129
+        while (iter.hasNext()) {
130
+            currentTask = iter.next();
131
+            if (currentMachine == order.instance.machine(currentTask)) {
132
+                currentLastIndex = order.getIndexOfTaskOnMachine(currentMachine, currentTask);
133
+            } else {
134
+                if (currentLastIndex > currentFirstIndex) {
135
+                    results.add(new Block(currentMachine, currentFirstIndex, currentLastIndex));
136
+                }
137
+                currentMachine = order.instance.machine(currentTask);
138
+                currentFirstIndex = order.getIndexOfTaskOnMachine(currentMachine, currentTask);
139
+                currentLastIndex = currentFirstIndex;
140
+            }
141
+        }
142
+        if (currentLastIndex > currentFirstIndex) {
143
+            results.add(new Block(currentMachine, currentFirstIndex, currentLastIndex));
144
+        }
145
+
146
+        return results;
113
     }
147
     }
114
 
148
 
115
     /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */
149
     /** For a given block, return the possible swaps for the Nowicki and Smutnicki neighborhood */
116
     List<Swap> neighbors(Block block) {
150
     List<Swap> neighbors(Block block) {
117
-        throw new UnsupportedOperationException();
118
-
151
+        ArrayList<Swap> swaps = new ArrayList<>();
152
+        if (block.lastTask - block.firstTask == 1) {
153
+            swaps.add(new Swap(block.machine, block.firstTask, block.lastTask));
154
+        } else {
155
+            swaps.add(new Swap(block.machine, block.firstTask, block.firstTask + 1));
156
+            swaps.add(new Swap(block.machine, block.lastTask - 1, block.lastTask));
157
+        }
158
+        return swaps;
119
     }
159
     }
120
-
121
 }
160
 }

+ 117
- 0
src/test/java/jobshop/solvers/GreedySolverTest.java View File

116
             }
116
             }
117
         }
117
         }
118
     }
118
     }
119
+
120
+    @Test
121
+    public void testEST_SPT() {
122
+        List<String> instancesNames = BestKnownResults.instancesMatching("la");
123
+        instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
124
+
125
+        List<Instance> instances = instancesNames.stream().map(name -> {
126
+            Instance instance = null;
127
+            try {
128
+                instance = Instance.fromFile(Paths.get("instances/", name));
129
+            } catch (IOException e) {
130
+                e.printStackTrace();
131
+            }
132
+            return instance;
133
+        }).collect(Collectors.toList());
134
+
135
+        GreedySolver solver = new GreedySolver(EST_SPT);
136
+        Result result;
137
+        for (int i = 0; i < instances.size(); i++) {
138
+            result = solver.solve(instances.get(i), 100000);
139
+            assert result.schedule.get().isValid();
140
+            if (BestKnownResults.isKnown(instancesNames.get(i))) {
141
+                assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i));
142
+            }
143
+        }
144
+    }
145
+
146
+    @Test
147
+    public void testEST_LPT() throws IOException {
148
+        List<String> instancesNames = BestKnownResults.instancesMatching("la");
149
+        instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
150
+
151
+        List<Instance> instances = instancesNames.stream().map(name -> {
152
+            Instance instance = null;
153
+            try {
154
+                instance = Instance.fromFile(Paths.get("instances/", name));
155
+            } catch (IOException e) {
156
+                e.printStackTrace();
157
+            }
158
+            return instance;
159
+        }).collect(Collectors.toList());
160
+
161
+        GreedySolver solver = new GreedySolver(EST_LPT);
162
+        Result result;
163
+        for (int i = 0; i < instances.size(); i++) {
164
+            result = solver.solve(instances.get(i), 100000);
165
+            assert result.schedule.get().isValid();
166
+            if (BestKnownResults.isKnown(instancesNames.get(i))) {
167
+                assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i));
168
+            }
169
+        }
170
+    }
171
+
172
+    @Test
173
+    public void testEST_SRPT() throws IOException {
174
+        List<String> instancesNames = BestKnownResults.instancesMatching("la");
175
+        instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
176
+
177
+        List<Instance> instances = instancesNames.stream().map(name -> {
178
+            Instance instance = null;
179
+            try {
180
+                instance = Instance.fromFile(Paths.get("instances/", name));
181
+            } catch (IOException e) {
182
+                e.printStackTrace();
183
+            }
184
+            return instance;
185
+        }).collect(Collectors.toList());
186
+
187
+        GreedySolver solver = new GreedySolver(EST_SRPT);
188
+        Result result;
189
+        for (int i = 0; i < instances.size(); i++) {
190
+            result = solver.solve(instances.get(i), 100000);
191
+            assert result.schedule.get().isValid();
192
+            if (BestKnownResults.isKnown(instancesNames.get(i))) {
193
+                assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i));
194
+            }
195
+        }
196
+    }
197
+
198
+    @Test
199
+    public void testEST_LRPT() throws IOException {
200
+        List<String> instancesNames = BestKnownResults.instancesMatching("la");
201
+        instancesNames.addAll(BestKnownResults.instancesMatching("ft"));
202
+
203
+        List<Instance> instances = instancesNames.stream().map(name -> {
204
+            Instance instance = null;
205
+            try {
206
+                instance = Instance.fromFile(Paths.get("instances/", name));
207
+            } catch (IOException e) {
208
+                e.printStackTrace();
209
+            }
210
+            return instance;
211
+        }).collect(Collectors.toList());
212
+
213
+        GreedySolver solver = new GreedySolver(EST_LRPT);
214
+        Result result;
215
+        for (int i = 0; i < instances.size(); i++) {
216
+            result = solver.solve(instances.get(i), 100000);
217
+            assert result.schedule.get().isValid();
218
+            if (BestKnownResults.isKnown(instancesNames.get(i))) {
219
+                assert result.schedule.get().makespan() >= BestKnownResults.of(instancesNames.get(i));
220
+            }
221
+        }
222
+    }
223
+
224
+    @Test
225
+    public void testSusucre() throws IOException {
226
+
227
+        Instance instance = Instance.fromFile(Paths.get("instances/aaa3"));
228
+
229
+        GreedySolver solver = new GreedySolver(EST_LRPT);
230
+        Result result = solver.solve(instance, 100000);
231
+        System.out.println("SCHEDULE EST_LRPT: " + result.schedule.get().toString());
232
+        solver = new GreedySolver(EST_SPT);
233
+        result = solver.solve(instance, 100000);
234
+        System.out.println("SCHEDULE EST_SPT: " + result.schedule.get().toString());
235
+    }
119
 }
236
 }

Loading…
Cancel
Save