From dc24411802a3099acede61b968b667316be8f0bf Mon Sep 17 00:00:00 2001 From: oblonski <4sschroeder@gmail.com> Date: Mon, 10 Feb 2014 16:23:42 +0100 Subject: [PATCH] added egress/access calc --- .../AdditionalAccessEgressCalculator.java | 58 +++++++++++++++++ .../recreate/ServiceInsertionCalculator.java | 6 +- .../TestCalculatesServiceInsertion.java | 62 ++++++++++++++++++- jsprit-examples/input/algorithmConfig.xml | 12 ++-- ...FromScratchWithHardAndSoftConstraints.java | 3 +- .../jsprit/examples/MultipleDepotExample.java | 2 +- ...ltipleDepotExampleWithPenaltyVehicles.java | 26 ++------ 7 files changed, 135 insertions(+), 34 deletions(-) create mode 100644 jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AdditionalAccessEgressCalculator.java diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AdditionalAccessEgressCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AdditionalAccessEgressCalculator.java new file mode 100644 index 00000000..164a3186 --- /dev/null +++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/AdditionalAccessEgressCalculator.java @@ -0,0 +1,58 @@ +package jsprit.core.algorithm.recreate; + +import jsprit.core.problem.cost.VehicleRoutingTransportCosts; +import jsprit.core.problem.driver.Driver; +import jsprit.core.problem.misc.JobInsertionContext; +import jsprit.core.problem.solution.route.VehicleRoute; +import jsprit.core.problem.solution.route.activity.TourActivity; +import jsprit.core.problem.vehicle.Vehicle; + +/** + * Estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location. + * + *
If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero. + * + * @author schroeder + * + */ +class AdditionalAccessEgressCalculator { + + private VehicleRoutingTransportCosts routingCosts; + + /** + * Constructs the estimator that estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location. + * + *
If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero.
+ *
+ * @author schroeder
+ *
+ */
+ public AdditionalAccessEgressCalculator(VehicleRoutingTransportCosts routingCosts) {
+ this.routingCosts = routingCosts;
+ }
+
+ public double getCosts(JobInsertionContext insertionContext){
+ double delta_access = 0.0;
+ double delta_egress = 0.0;
+ VehicleRoute currentRoute = insertionContext.getRoute();
+ Vehicle newVehicle = insertionContext.getNewVehicle();
+ Driver newDriver = insertionContext.getNewDriver();
+ double newVehicleDepartureTime = insertionContext.getNewDepTime();
+ if(!currentRoute.isEmpty()){
+ double accessTransportCostNew = routingCosts.getTransportCost(newVehicle.getLocationId(), currentRoute.getActivities().get(0).getLocationId(), newVehicleDepartureTime, newDriver, newVehicle);
+ double accessTransportCostOld = routingCosts.getTransportCost(currentRoute.getStart().getLocationId(), currentRoute.getActivities().get(0).getLocationId(), currentRoute.getDepartureTime(), currentRoute.getDriver(), currentRoute.getVehicle());
+
+ delta_access = accessTransportCostNew - accessTransportCostOld;
+
+ TourActivity lastActivityBeforeEndOfRoute = currentRoute.getActivities().get(currentRoute.getActivities().size()-1);
+ double lastActivityEndTimeWithOldVehicleAndDepartureTime = lastActivityBeforeEndOfRoute.getEndTime();
+ double lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime = Math.max(0.0, lastActivityEndTimeWithOldVehicleAndDepartureTime + (newVehicleDepartureTime - currentRoute.getDepartureTime()));
+ double egressTransportCostNew = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocationId(), newVehicle.getLocationId() , lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime, newDriver, newVehicle);
+ double egressTransportCostOld = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocationId(), currentRoute.getEnd().getLocationId(), lastActivityEndTimeWithOldVehicleAndDepartureTime, currentRoute.getDriver(), currentRoute.getVehicle());
+
+ delta_egress = egressTransportCostNew - egressTransportCostOld;
+ }
+ return delta_access + delta_egress;
+ }
+
+}
\ No newline at end of file
diff --git a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java
index 289fe9fd..72265579 100644
--- a/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java
+++ b/jsprit-core/src/main/java/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java
@@ -47,7 +47,7 @@ import org.apache.log4j.Logger;
*
*/
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
-
+
private static final Logger logger = Logger.getLogger(ServiceInsertionCalculator.class);
private HardRouteStateLevelConstraint hardRouteLevelConstraint;
@@ -63,6 +63,8 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
private TourActivityFactory activityFactory;
+
+ private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
super();
@@ -73,6 +75,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
activityFactory = new DefaultTourActivityFactory();
+ additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
logger.info("initialise " + this);
}
@@ -100,6 +103,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
//from job2insert induced costs at route level
double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext);
+ additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
Service service = (Service)jobToInsert;
int insertionIndex = InsertionData.NO_INDEX;
diff --git a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java
index 0baaae61..7b957c22 100644
--- a/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java
+++ b/jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java
@@ -23,22 +23,30 @@ import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import jsprit.core.algorithm.state.StateManager;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.constraint.ConstraintManager;
+import jsprit.core.problem.cost.AbstractForwardVehicleRoutingTransportCosts;
import jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
+import jsprit.core.problem.driver.Driver;
import jsprit.core.problem.driver.DriverImpl;
import jsprit.core.problem.driver.DriverImpl.NoDriver;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
+import jsprit.core.problem.misc.JobInsertionContext;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.ServiceActivity;
import jsprit.core.problem.solution.route.activity.TimeWindow;
import jsprit.core.problem.solution.route.activity.TourActivities;
import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.vehicle.Vehicle;
+import jsprit.core.problem.vehicle.VehicleImpl;
+import jsprit.core.util.Coordinate;
+import jsprit.core.util.EuclideanDistanceCalculator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
@@ -184,7 +192,6 @@ public class TestCalculatesServiceInsertion {
VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle);
states.informInsertionStarts(Arrays.asList(route), null);
-// stateUpdater.update(route);
InsertionData iData = serviceInsertion.getInsertionData(route, first, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE);
assertEquals(20.0, iData.getInsertionCost(), 0.2);
@@ -253,8 +260,6 @@ public class TestCalculatesServiceInsertion {
tour.addActivity(ServiceActivity.newInstance(third));
VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle);
-// route.addActivity(states.getActivity(first,true));
-// route.addActivity(states.getActivity(third,true));
states.informInsertionStarts(Arrays.asList(route), null);
InsertionData iData = serviceInsertion.getInsertionData(route, second, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE);
@@ -262,6 +267,57 @@ public class TestCalculatesServiceInsertion {
assertEquals(2, iData.getDeliveryInsertionIndex());
}
+ @Test
+ public void whenInsertingJobAndCurrRouteIsEmpty_accessEggressCalcShouldReturnZero(){
+ VehicleRoute route = VehicleRoute.Builder.newInstance(VehicleImpl.createNoVehicle(), DriverImpl.noDriver()).build();
+ AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(costs);
+ Job job = Service.Builder.newInstance("1", 0).setLocationId("1").setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build();
+ JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0);
+ assertEquals(0.0, accessEgressCalc.getCosts(iContex),0.01);
+ }
+ @Test
+ public void whenInsertingJobAndCurrRouteAndVehicleHaveTheSameLocation_accessEggressCalcShouldReturnZero(){
+ VehicleRoute route = VehicleRoute.Builder.newInstance(newVehicle, DriverImpl.noDriver())
+ .addService(Service.Builder.newInstance("1", 0).setLocationId("1").setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build())
+ .build();
+
+ AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(costs);
+ Job job = Service.Builder.newInstance("1", 0).setLocationId("1").setTimeWindow(TimeWindow.newInstance(0.0, 100.0)).build();
+ JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0);
+ assertEquals(0.0, accessEgressCalc.getCosts(iContex),0.01);
+ }
+ @Test
+ public void whenInsertingJobAndCurrRouteAndNewVehicleHaveDifferentLocations_accessEggressCostsMustBeCorrect(){
+ final Map