Skip to content

Commit f59b2c4

Browse files
committed
allow access to job calculator factories and rename switcher to selector
1 parent e60f7c6 commit f59b2c4

File tree

9 files changed

+125
-52
lines changed

9 files changed

+125
-52
lines changed

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ public static class Builder {
184184

185185
private JobFilter jobFilter = null;
186186

187+
private ServiceInsertionCalculatorFactory serviceCalculatorFactory = null;
188+
private ShipmentInsertionCalculatorFactory shipmentCalculatorFactory = null;
189+
190+
187191
public static Builder newInstance(VehicleRoutingProblem vrp) {
188192
return new Builder(vrp);
189193
}
@@ -333,6 +337,22 @@ public Builder setJobFilter(JobFilter jobFilter) {
333337
return this;
334338
}
335339

340+
/**
341+
* Set a custom service insertion calculator factory
342+
*/
343+
public Builder setServiceInsertionCalculatorFactory(ServiceInsertionCalculatorFactory factory) {
344+
this.serviceCalculatorFactory = factory;
345+
return this;
346+
}
347+
348+
/**
349+
* Set a custom shipment insertion calculator factory
350+
*/
351+
public Builder setShipmentInsertionCalculatorFactory(ShipmentInsertionCalculatorFactory factory) {
352+
this.shipmentCalculatorFactory = factory;
353+
return this;
354+
}
355+
336356
public VehicleRoutingAlgorithm buildAlgorithm() {
337357
return new Jsprit(this).create(vrp);
338358
}
@@ -401,6 +421,10 @@ public int createNumberToBeRemoved() {
401421

402422
private final Map<SearchStrategy, Double> customStrategies = new HashMap<>();
403423

424+
private final ServiceInsertionCalculatorFactory serviceCalculatorFactory;
425+
426+
private final ShipmentInsertionCalculatorFactory shipmentCalculatorFactory;
427+
404428
private VehicleFleetManager vehicleFleetManager;
405429

406430
private Jsprit(Builder builder) {
@@ -415,6 +439,8 @@ private Jsprit(Builder builder) {
415439
this.activityInsertion = builder.activityInsertionCalculator;
416440
this.acceptor = builder.solutionAcceptor;
417441
this.jobFilter = builder.jobFilter;
442+
this.shipmentCalculatorFactory = builder.shipmentCalculatorFactory;
443+
this.serviceCalculatorFactory = builder.serviceCalculatorFactory;
418444
regretScorer = builder.regretScorer;
419445
regretScoringFunction = builder.regretScoringFunction;
420446
customStrategies.putAll(builder.customStrategies);
@@ -575,6 +601,8 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
575601
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
576602
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
577603
.setActivityInsertionCostCalculator(activityInsertion)
604+
.setServiceInsertionCalculator(this.serviceCalculatorFactory)
605+
.setShipmentInsertionCalculatorFactory(this.shipmentCalculatorFactory)
578606
.build();
579607
regretInsertion.setRegretScoringFunction(regretScoringFunction);
580608
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
@@ -587,6 +615,8 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
587615
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
588616
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
589617
.setActivityInsertionCostCalculator(activityInsertion)
618+
.setServiceInsertionCalculator(this.serviceCalculatorFactory)
619+
.setShipmentInsertionCalculatorFactory(this.shipmentCalculatorFactory)
590620
.build();
591621
regretInsertion.setRegretScoringFunction(regretScoringFunction);
592622
regret = regretInsertion;
@@ -599,6 +629,8 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
599629
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
600630
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
601631
.setActivityInsertionCostCalculator(activityInsertion)
632+
.setServiceInsertionCalculator(this.serviceCalculatorFactory)
633+
.setShipmentInsertionCalculatorFactory(this.shipmentCalculatorFactory)
602634
.build();
603635
regretInsertion.setRegretScoringFunction(regretScoringFunction);
604636
regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes());
@@ -610,7 +642,9 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
610642
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
611643
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
612644
.setActivityInsertionCostCalculator(activityInsertion)
613-
.build();
645+
.setServiceInsertionCalculator(this.serviceCalculatorFactory)
646+
.setShipmentInsertionCalculatorFactory(this.shipmentCalculatorFactory)
647+
.build();
614648
regretInsertion.setRegretScoringFunction(regretScoringFunction);
615649
regret = regretInsertion;
616650
}
@@ -624,6 +658,8 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
624658
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
625659
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
626660
.setActivityInsertionCostCalculator(activityInsertion)
661+
.setServiceInsertionCalculator(this.serviceCalculatorFactory)
662+
.setShipmentInsertionCalculatorFactory(this.shipmentCalculatorFactory)
627663
.build();
628664
best = bestInsertion;
629665
} else {
@@ -633,6 +669,8 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
633669
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
634670
.setConcurrentMode(es, noThreads)
635671
.setActivityInsertionCostCalculator(activityInsertion)
672+
.setServiceInsertionCalculator(this.serviceCalculatorFactory)
673+
.setShipmentInsertionCalculatorFactory(this.shipmentCalculatorFactory)
636674
.build();
637675
best = bestInsertion;
638676
}
@@ -736,7 +774,7 @@ private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
736774
vra.addListener(new BreakScheduling(vrp, stateManager, constraintManager));
737775
}
738776
handleExecutorShutdown(vra);
739-
vra.setMaxIterations(Integer.valueOf(properties.getProperty(Parameter.ITERATIONS.toString())));
777+
vra.setMaxIterations(Integer.parseInt(properties.getProperty(Parameter.ITERATIONS.toString())));
740778

741779
return vra;
742780

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

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,3 @@
1-
/*
2-
* Licensed to GraphHopper GmbH under one or more contributor
3-
* license agreements. See the NOTICE file distributed with this work for
4-
* additional information regarding copyright ownership.
5-
*
6-
* GraphHopper GmbH licenses this file to you under the Apache License,
7-
* Version 2.0 (the "License"); you may not use this file except in
8-
* compliance with the License. You may obtain a copy of the License at
9-
*
10-
* http://www.apache.org/licenses/LICENSE-2.0
11-
*
12-
* Unless required by applicable law or agreed to in writing, software
13-
* distributed under the License is distributed on an "AS IS" BASIS,
14-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15-
* See the License for the specific language governing permissions and
16-
* limitations under the License.
17-
*/
18-
191
package com.graphhopper.jsprit.core.algorithm.recreate;
202

213
import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager;
@@ -24,18 +6,26 @@
246
import com.graphhopper.jsprit.core.problem.constraint.HardConstraint;
257
import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint;
268
import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext;
9+
import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute;
10+
import com.graphhopper.jsprit.core.problem.solution.route.activity.End;
11+
import com.graphhopper.jsprit.core.problem.solution.route.activity.Start;
2712
import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity;
13+
import com.graphhopper.jsprit.core.problem.vehicle.Vehicle;
2814

2915
import java.util.ArrayList;
3016
import java.util.Collection;
3117
import java.util.List;
3218

3319
/**
34-
* Created by schroeder on 06/02/17.
20+
* Enhanced AbstractInsertionCalculator with more common functionality moved up
21+
* to simplify implementation of concrete calculators.
3522
*/
36-
abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator {
23+
public abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator {
3724

38-
InsertionData checkRouteConstraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) {
25+
/**
26+
* Check if route constraints are fulfilled
27+
*/
28+
protected InsertionData checkRouteConstraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) {
3929
for (HardRouteConstraint hardRouteConstraint : constraintManager.getHardRouteConstraints()) {
4030
if (!hardRouteConstraint.fulfilled(insertionContext)) {
4131
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
@@ -46,7 +36,10 @@ InsertionData checkRouteConstraints(JobInsertionContext insertionContext, Constr
4636
return null;
4737
}
4838

49-
ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime, Collection<HardConstraint> failedActivityConstraints, ConstraintManager constraintManager) {
39+
/**
40+
* Check if activity constraints are fulfilled
41+
*/
42+
protected ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime, Collection<HardConstraint> failedActivityConstraints, ConstraintManager constraintManager) {
5043
if (!constraintManager.hasHardActivityConstraints()) return ConstraintsStatus.FULFILLED;
5144
ConstraintsStatus notFulfilled = null;
5245
List<HardConstraint> failed = new ArrayList<>();
@@ -94,4 +87,53 @@ ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, To
9487
return ConstraintsStatus.FULFILLED;
9588
}
9689

97-
}
90+
/**
91+
* Creates a Start activity for a vehicle at a given departure time
92+
*/
93+
protected Start createStartActivity(Vehicle vehicle, double departureTime) {
94+
Start start = new Start(vehicle.getStartLocation(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
95+
start.setEndTime(departureTime);
96+
return start;
97+
}
98+
99+
/**
100+
* Creates an End activity for a vehicle
101+
*/
102+
protected End createEndActivity(Vehicle vehicle) {
103+
return new End(vehicle.getEndLocation(), 0.0, vehicle.getLatestArrival());
104+
}
105+
106+
/**
107+
* Creates a NoInsertionFound result with failed constraint information
108+
*/
109+
protected InsertionData createNoInsertionFoundResult(Collection<HardConstraint> failedConstraints) {
110+
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
111+
for (HardConstraint failed : failedConstraints) {
112+
emptyInsertionData.addFailedConstrainName(failed.getClass().getSimpleName());
113+
}
114+
return emptyInsertionData;
115+
}
116+
117+
/**
118+
* Adds events to insertion data for a job that requires two activities (like Shipment)
119+
*/
120+
protected void addActivitiesAndVehicleSwitch(InsertionData insertionData, VehicleRoute route,
121+
Vehicle vehicle, TourActivity firstActivity, int firstActivityIndex,
122+
TourActivity secondActivity, int secondActivityIndex,
123+
double departureTime) {
124+
// Order matters here - we need to insert second activity before first to maintain indices
125+
insertionData.getEvents().add(new InsertActivity(route, vehicle, secondActivity, secondActivityIndex));
126+
insertionData.getEvents().add(new InsertActivity(route, vehicle, firstActivity, firstActivityIndex));
127+
insertionData.getEvents().add(new SwitchVehicle(route, vehicle, departureTime));
128+
}
129+
130+
/**
131+
* Adds events to insertion data for a job that requires a single activity (like Service)
132+
*/
133+
protected void addActivityAndVehicleSwitch(InsertionData insertionData, VehicleRoute route,
134+
Vehicle vehicle, TourActivity activity, int activityIndex,
135+
double departureTime) {
136+
insertionData.getEvents().add(new InsertActivity(route, vehicle, activity, activityIndex));
137+
insertionData.getEvents().add(new SwitchVehicle(route, vehicle, departureTime));
138+
}
139+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public static InsertionData createEmptyInsertionData() {
5454
return noInsertion;
5555
}
5656

57-
static int NO_INDEX = -1;
57+
public static int NO_INDEX = -1;
5858

5959
private final double insertionCost;
6060

jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobCalculatorSwitcher.java renamed to jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobCalculatorSelector.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
import java.util.Map;
2727

2828

29-
class JobCalculatorSwitcher implements JobInsertionCostsCalculator {
29+
class JobCalculatorSelector implements JobInsertionCostsCalculator {
3030

31-
private Map<Class<? extends Job>, JobInsertionCostsCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCostsCalculator>();
31+
private final Map<Class<? extends Job>, JobInsertionCostsCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCostsCalculator>();
3232

3333
void put(Class<? extends Job> jobClass, JobInsertionCostsCalculator jic) {
3434
calcMap.put(jobClass, jic);

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -316,16 +316,16 @@ public List<AbstractActivity> createActivities(Job job) {
316316
JobInsertionCostsCalculator serviceInsertion = serviceCalculatorFactory.create(vrp, actInsertionCalc, activityFactory, constraintManager);
317317
JobInsertionCostsCalculator breakInsertion = breakCalculatorFactory.create(vrp, actInsertionCalc, activityFactory, constraintManager);
318318

319-
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
320-
switcher.put(Shipment.class, shipmentInsertion);
321-
switcher.put(Service.class, serviceInsertion);
322-
switcher.put(Pickup.class, serviceInsertion);
323-
switcher.put(Delivery.class, serviceInsertion);
324-
switcher.put(EnRoutePickup.class, serviceInsertion);
325-
switcher.put(EnRouteDelivery.class, serviceInsertion);
326-
switcher.put(Break.class, breakInsertion);
327-
328-
CalculatorPlusListeners calculatorPlusListeners = new CalculatorPlusListeners(switcher);
319+
JobCalculatorSelector jobCalculatorSelector = new JobCalculatorSelector();
320+
jobCalculatorSelector.put(Shipment.class, shipmentInsertion);
321+
jobCalculatorSelector.put(Service.class, serviceInsertion);
322+
jobCalculatorSelector.put(Pickup.class, serviceInsertion);
323+
jobCalculatorSelector.put(Delivery.class, serviceInsertion);
324+
jobCalculatorSelector.put(EnRoutePickup.class, serviceInsertion);
325+
jobCalculatorSelector.put(EnRouteDelivery.class, serviceInsertion);
326+
jobCalculatorSelector.put(Break.class, breakInsertion);
327+
328+
CalculatorPlusListeners calculatorPlusListeners = new CalculatorPlusListeners(jobCalculatorSelector);
329329
if (configLocal != null) {
330330
calculatorPlusListeners.insertionListener.add(configLocal);
331331
}

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

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,9 @@ public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job
115115
TimeWindow bestPickupTimeWindow = null;
116116
TimeWindow bestDeliveryTimeWindow = null;
117117

118-
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
119-
start.setEndTime(newVehicleDepartureTime);
118+
Start start = createStartActivity(newVehicle, newVehicleDepartureTime);
120119

121-
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
120+
End end = createEndActivity(newVehicle);
122121

123122
ActivityContext pickupContext = new ActivityContext();
124123

@@ -244,21 +243,15 @@ else if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
244243
}
245244
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
246245
LOGGER.trace("Position cost: {}, feasible: {}", -1, false);
247-
InsertionData emptyInsertionData = new InsertionData.NoInsertionFound();
248-
for (HardConstraint failed : failedActivityConstraints) {
249-
emptyInsertionData.addFailedConstrainName(failed.getClass().getSimpleName());
250-
}
251-
return emptyInsertionData;
246+
return createNoInsertionFoundResult(failedActivityConstraints);
252247
}
253248
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
254249
pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart());
255250
pickupShipment.setTheoreticalLatestOperationStartTime(bestPickupTimeWindow.getEnd());
256251
deliverShipment.setTheoreticalEarliestOperationStartTime(bestDeliveryTimeWindow.getStart());
257252
deliverShipment.setTheoreticalLatestOperationStartTime(bestDeliveryTimeWindow.getEnd());
258253
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
259-
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, deliverShipment, deliveryInsertionIndex));
260-
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, pickupShipment, pickupInsertionIndex));
261-
insertionData.getEvents().add(new SwitchVehicle(currentRoute, newVehicle, newVehicleDepartureTime));
254+
addActivitiesAndVehicleSwitch(insertionData, currentRoute, newVehicle, pickupShipment, pickupInsertionIndex, deliverShipment, deliveryInsertionIndex, newVehicleDepartureTime);
262255
return insertionData;
263256
}
264257

jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionAndLoadConstraintsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public List<AbstractActivity> createActivities(Job job) {
134134
ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager);
135135
constraintManager.addLoadConstraint();
136136
stateManager.informInsertionStarts(Arrays.asList(route), null);
137-
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
137+
JobCalculatorSelector switcher = new JobCalculatorSelector();
138138
ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
139139
ShipmentInsertionCalculator insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
140140
switcher.put(Pickup.class, serviceInsertionCalc);

jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorFlexTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ void whenInsertingServiceWhileNoCapIsAvailable_itMustReturnNoInsertionData() {
311311
List<AbstractActivity> activities = new ArrayList<AbstractActivity>();
312312
activities.add(new PickupService(service));
313313
when(activityFactory.createActivities(service)).thenReturn(activities);
314-
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
314+
JobCalculatorSelector switcher = new JobCalculatorSelector();
315315
ServiceInsertionCalculator serviceInsertionCalc = new ServiceInsertionCalculator(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager, activityFactory);
316316
ShipmentInsertionCalculatorFlex insertionCalculator = new ShipmentInsertionCalculatorFlex(routingCosts, activityCosts, activityInsertionCostsCalculator, constraintManager);
317317
insertionCalculator.setJobActivityFactory(activityFactory);

0 commit comments

Comments
 (0)