Skip to content

Commit 76f43ea

Browse files
croooomarcanpilami
authored andcommitted
Added: TimeWindows is now an extension point, notably allowing TimeWindow exclusions (#1)
1 parent b2b34a2 commit 76f43ea

File tree

9 files changed

+374
-33
lines changed

9 files changed

+374
-33
lines changed

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import com.graphhopper.jsprit.core.problem.constraint.HardConstraint;
2525
import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint;
2626
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
27-
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
2827
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
2928

3029
import java.util.ArrayList;
@@ -35,8 +34,6 @@
3534
* Created by schroeder on 06/02/17.
3635
*/
3736
abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator {
38-
protected TimeWindow defaultTimeWindow = TimeWindow.newInstance(0.0, Double.MAX_VALUE);
39-
4037
InsertionData checkRouteConstraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) {
4138
for (HardRouteConstraint hardRouteConstraint : constraintManager.getHardRouteConstraints()) {
4239
if (!hardRouteConstraint.fulfilled(insertionContext)) {

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,12 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
135135
nextAct = end;
136136
tourEnd = true;
137137
}
138+
139+
ActivityContext activityContext = new ActivityContext();
140+
activityContext.setInsertionIndex(actIndex);
141+
insertionContext.setActivityContext(activityContext);
138142
boolean not_fulfilled_break = true;
139-
for(TimeWindow timeWindow : service.getTimeWindows()) {
140-
ActivityContext activityContext = new ActivityContext();
141-
activityContext.setInsertionIndex(actIndex);
142-
insertionContext.setActivityContext(activityContext);
143-
if (!timeWindow.isApplicable(insertionContext)) {
144-
timeWindow = defaultTimeWindow;
145-
}
143+
for(TimeWindow timeWindow : service.getTimeWindows(insertionContext)) {
146144
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(timeWindow.getStart());
147145
deliveryAct2Insert.setTheoreticalLatestOperationStartTime(timeWindow.getEnd());
148146

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,10 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
140140
}
141141

142142
boolean pickupInsertionNotFulfilledBreak = true;
143-
for(TimeWindow pickupTimeWindow : shipment.getPickupTimeWindows()) {
144-
ActivityContext activityContext = new ActivityContext();
145-
activityContext.setInsertionIndex(i);
146-
insertionContext.setActivityContext(activityContext);
147-
if (!pickupTimeWindow.isApplicable(insertionContext)) {
148-
pickupTimeWindow = defaultTimeWindow;
149-
}
143+
ActivityContext activityContext = new ActivityContext();
144+
activityContext.setInsertionIndex(i);
145+
insertionContext.setActivityContext(activityContext);
146+
for(TimeWindow pickupTimeWindow : shipment.getPickupTimeWindows(insertionContext)) {
150147
pickupShipment.setTheoreticalLatestOperationStartTime(pickupTimeWindow.getEnd());
151148
pickupShipment.setTheoreticalEarliestOperationStartTime(pickupTimeWindow.getStart());
152149

@@ -194,13 +191,10 @@ else if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
194191
}
195192

196193
boolean deliveryInsertionNotFulfilledBreak = true;
197-
for (TimeWindow deliveryTimeWindow : shipment.getDeliveryTimeWindows()) {
198-
ActivityContext activityContext_ = new ActivityContext();
199-
activityContext_.setInsertionIndex(j);
200-
insertionContext.setActivityContext(activityContext_);
201-
if (!deliveryTimeWindow.isApplicable(insertionContext)) {
202-
deliveryTimeWindow = defaultTimeWindow;
203-
}
194+
ActivityContext activityContext_ = new ActivityContext();
195+
activityContext_.setInsertionIndex(j);
196+
insertionContext.setActivityContext(activityContext_);
197+
for (TimeWindow deliveryTimeWindow : shipment.getDeliveryTimeWindows(insertionContext)) {
204198
deliverShipment.setTheoreticalEarliestOperationStartTime(deliveryTimeWindow.getStart());
205199
deliverShipment.setTheoreticalLatestOperationStartTime(deliveryTimeWindow.getEnd());
206200

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
import com.graphhopper.jsprit.core.problem.Capacity;
2222
import com.graphhopper.jsprit.core.problem.Location;
2323
import com.graphhopper.jsprit.core.problem.Skills;
24+
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
2425
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
2526
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindows;
2627
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
28+
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsOverlapImpl;
2729
import com.graphhopper.jsprit.core.util.Coordinate;
2830

2931
import java.util.ArrayList;
@@ -87,7 +89,7 @@ public static Builder newInstance(String id) {
8789

8890
protected Location location;
8991

90-
protected TimeWindowsImpl timeWindows;
92+
protected TimeWindows timeWindows;
9193

9294
private boolean twAdded = false;
9395

@@ -184,6 +186,20 @@ public Builder<T> setTimeWindow(TimeWindow tw){
184186
return this;
185187
}
186188

189+
public Builder<T> setTimeWindows(TimeWindows timeWindows){
190+
if (timeWindows == null) throw new IllegalArgumentException("The time windows must not be null.");
191+
if (twAdded) {
192+
// Report already added TW for ascending compatibility and API clarity
193+
// (otherwise previous calls to addTimeWindow would be silently ignored)
194+
for (TimeWindow tw : this.timeWindows.getTimeWindows()) {
195+
timeWindows.add(tw);
196+
}
197+
}
198+
this.timeWindows = timeWindows;
199+
twAdded = true;
200+
return this;
201+
}
202+
187203
public Builder<T> addTimeWindow(TimeWindow timeWindow) {
188204
if (timeWindow == null) throw new IllegalArgumentException("The time window must not be null.");
189205
if(!twAdded){
@@ -310,6 +326,10 @@ public Collection<TimeWindow> getTimeWindows(){
310326
return timeWindows.getTimeWindows();
311327
}
312328

329+
public Collection<TimeWindow> getTimeWindows(JobInsertionContext insertionContext){
330+
return timeWindows.getTimeWindows(insertionContext);
331+
}
332+
313333
@Override
314334
public String getId() {
315335
return id;

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
import com.graphhopper.jsprit.core.problem.Capacity;
2222
import com.graphhopper.jsprit.core.problem.Location;
2323
import com.graphhopper.jsprit.core.problem.Skills;
24+
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
2425
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow;
26+
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindows;
2527
import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl;
2628

2729
import java.util.ArrayList;
@@ -76,13 +78,13 @@ public static class Builder {
7678

7779
private Location deliveryLocation_;
7880

79-
protected TimeWindowsImpl deliveryTimeWindows;
81+
protected TimeWindows deliveryTimeWindows;
8082

8183
private boolean deliveryTimeWindowAdded = false;
8284

8385
private boolean pickupTimeWindowAdded = false;
8486

85-
private TimeWindowsImpl pickupTimeWindows;
87+
private TimeWindows pickupTimeWindows;
8688

8789
private int priority = 2;
8890

@@ -176,7 +178,18 @@ public Builder setPickupTimeWindow(TimeWindow timeWindow) {
176178
return this;
177179
}
178180

179-
181+
public Builder setPickupTimeWindows(TimeWindows timeWindows){
182+
if (timeWindows == null) throw new IllegalArgumentException("The time windows must not be null.");
183+
if (pickupTimeWindows != null) {
184+
// Report already added TW for ascending compatibility and API clarity
185+
// (otherwise previous calls to addXXXTimeWindow would be silently ignored)
186+
for (TimeWindow tw : this.pickupTimeWindows.getTimeWindows()) {
187+
timeWindows.add(tw);
188+
}
189+
}
190+
this.pickupTimeWindows = timeWindows;
191+
return this;
192+
}
180193

181194
/**
182195
* Sets delivery location.
@@ -222,6 +235,19 @@ public Builder setDeliveryTimeWindow(TimeWindow timeWindow) {
222235
return this;
223236
}
224237

238+
public Builder setDeliveryTimeWindows(TimeWindows timeWindows){
239+
if (timeWindows == null) throw new IllegalArgumentException("The time windows must not be null.");
240+
if (deliveryTimeWindows != null) {
241+
// Report already added TW for ascending compatibility and API clarity
242+
// (otherwise previous calls to addXXXTimeWindow would be silently ignored)
243+
for (TimeWindow tw : this.deliveryTimeWindows.getTimeWindows()) {
244+
timeWindows.add(tw);
245+
}
246+
}
247+
this.deliveryTimeWindows = timeWindows;
248+
return this;
249+
}
250+
225251
/**
226252
* Adds capacity dimension.
227253
*
@@ -367,9 +393,9 @@ public Builder setMaxTimeInVehicle(double maxTimeInVehicle){
367393

368394
private final Location deliveryLocation_;
369395

370-
private final TimeWindowsImpl deliveryTimeWindows;
396+
private final TimeWindows deliveryTimeWindows;
371397

372-
private final TimeWindowsImpl pickupTimeWindows;
398+
private final TimeWindows pickupTimeWindows;
373399

374400
private final int priority;
375401

@@ -442,6 +468,10 @@ public Collection<TimeWindow> getDeliveryTimeWindows() {
442468
return deliveryTimeWindows.getTimeWindows();
443469
}
444470

471+
public Collection<TimeWindow> getDeliveryTimeWindows(JobInsertionContext insertionContext) {
472+
return deliveryTimeWindows.getTimeWindows(insertionContext);
473+
}
474+
445475
/**
446476
* Returns the time-window of pickup.
447477
*
@@ -455,6 +485,10 @@ public Collection<TimeWindow> getPickupTimeWindows() {
455485
return pickupTimeWindows.getTimeWindows();
456486
}
457487

488+
public Collection<TimeWindow> getPickupTimeWindows(JobInsertionContext insertionContext) {
489+
return pickupTimeWindows.getTimeWindows(insertionContext);
490+
}
491+
458492

459493
/**
460494
* Returns a string with the shipment's attributes.

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/activity/TimeWindows.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@
2020

2121
import java.util.Collection;
2222

23+
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
24+
2325
/**
2426
* Created by schroeder on 20/05/15.
2527
*/
2628
public interface TimeWindows {
29+
static TimeWindow defaultTimeWindow = TimeWindow.newInstance(0.0, Double.MAX_VALUE);
30+
31+
public void add(TimeWindow timeWindow);
2732

2833
public Collection<TimeWindow> getTimeWindows();
2934

35+
public Collection<TimeWindow> getTimeWindows(JobInsertionContext insertionContext);
36+
3037
}

jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/activity/TimeWindowsImpl.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import java.util.ArrayList;
2222
import java.util.Collection;
2323
import java.util.Collections;
24+
import java.util.List;
25+
26+
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
2427

2528
/**
2629
* Created by schroeder on 26/05/15.
@@ -29,6 +32,7 @@ public class TimeWindowsImpl implements TimeWindows {
2932

3033
private Collection<TimeWindow> timeWindows = new ArrayList<TimeWindow>();
3134

35+
@Override
3236
public void add(TimeWindow timeWindow){
3337
for(TimeWindow tw : timeWindows){
3438
if(timeWindow.getStart() > tw.getStart() && timeWindow.getStart() < tw.getEnd()){
@@ -44,10 +48,25 @@ public void add(TimeWindow timeWindow){
4448
timeWindows.add(timeWindow);
4549
}
4650

51+
@Override
4752
public Collection<TimeWindow> getTimeWindows() {
4853
return Collections.unmodifiableCollection(timeWindows);
4954
}
5055

56+
@Override
57+
public Collection<TimeWindow> getTimeWindows(JobInsertionContext insertionContext) {
58+
List<TimeWindow> timeWindows = new ArrayList<TimeWindow>(this.timeWindows.size());
59+
for(TimeWindow tw : this.timeWindows){
60+
if (tw.isApplicable(insertionContext)) {
61+
timeWindows.add(tw);
62+
}
63+
}
64+
if (timeWindows.isEmpty()) {
65+
timeWindows.add(TimeWindows.defaultTimeWindow);
66+
}
67+
return Collections.unmodifiableCollection(timeWindows);
68+
}
69+
5170
@Override
5271
public String toString() {
5372
StringBuffer sb = new StringBuffer(timeWindows.size() * 60);

0 commit comments

Comments
 (0)