diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java index cdd7dac2..0f91eab1 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java @@ -22,6 +22,7 @@ import com.graphhopper.jsprit.core.algorithm.state.InternalStates; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment; import com.graphhopper.jsprit.core.problem.solution.route.activity.End; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; @@ -77,7 +78,9 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal double oldCosts = 0.; if (iFacts.getRoute().isEmpty()) { - double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double tp_costs_prevAct_nextAct = 0.; + if (newAct instanceof DeliverShipment) + tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); oldCosts += tp_costs_prevAct_nextAct; } else { double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java index 66ff5063..b9e4f631 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java @@ -28,6 +28,7 @@ import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts; import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Service; +import com.graphhopper.jsprit.core.problem.job.Shipment; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.activity.End; @@ -91,6 +92,74 @@ public class TestLocalActivityInsertionCostsCalculator { return Location.Builder.newInstance().setId(i).build(); } + @Test + public void whenAddingServiceBetweenDiffStartAndEnd_costMustBeCorrect() { + VehicleImpl v = VehicleImpl.Builder.newInstance("v") + .setStartLocation(Location.newInstance(0, 0)) + .setEndLocation(Location.newInstance(20, 0)) + .build(); + Service s = Service.Builder.newInstance("s") + .setLocation(Location.newInstance(10, 0)) + .build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addVehicle(v) + .addJob(s) + .build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + JobInsertionContext jobInsertionContext = + new JobInsertionContext(route, s, v, null, 0); + LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator = + new LocalActivityInsertionCostsCalculator( + vrp.getTransportCosts(), + vrp.getActivityCosts(), + new StateManager(vrp)); + double cost = localActivityInsertionCostsCalculator.getCosts( + jobInsertionContext, + new Start(v.getStartLocation(),0,Double.MAX_VALUE), + new End(v.getEndLocation(),0,Double.MAX_VALUE), + vrp.getActivities(s).get(0), + 0); + assertEquals(20., cost, Math.ulp(20.)); + } + + @Test + public void whenAddingShipmentBetweenDiffStartAndEnd_costMustBeCorrect() { + VehicleImpl v = VehicleImpl.Builder.newInstance("v") + .setStartLocation(Location.newInstance(0, 0)) + .setEndLocation(Location.newInstance(20, 0)) + .build(); + Shipment s = Shipment.Builder.newInstance("p") + .setPickupLocation(Location.newInstance(10, 0)) + .setDeliveryLocation(Location.newInstance(10, 7.5)) + .build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addVehicle(v) + .addJob(s) + .build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + JobInsertionContext jobInsertionContext = + new JobInsertionContext(route, s, v, null, 0); + LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator = + new LocalActivityInsertionCostsCalculator( + vrp.getTransportCosts(), + vrp.getActivityCosts(), + new StateManager(vrp)); + double cost = localActivityInsertionCostsCalculator.getCosts( + jobInsertionContext, + new Start(v.getStartLocation(),0,Double.MAX_VALUE), + new End(v.getEndLocation(),0,Double.MAX_VALUE), + vrp.getActivities(s).get(0), + 0); + assertEquals(20., cost, Math.ulp(20.)); + cost = localActivityInsertionCostsCalculator.getCosts( + jobInsertionContext, + vrp.getActivities(s).get(0), + new End(v.getEndLocation(),0,Double.MAX_VALUE), + vrp.getActivities(s).get(1), + 0); + assertEquals(10, cost, Math.ulp(10.)); + } + @Test public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts() { TourActivity prevAct = mock(TourActivity.class);