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 coords = new HashMap(); + coords.put("oldV", Coordinate.newInstance(1, 0)); + coords.put("newV", Coordinate.newInstance(5, 0)); + coords.put("service", Coordinate.newInstance(0, 0)); + + AbstractForwardVehicleRoutingTransportCosts routingCosts = new AbstractForwardVehicleRoutingTransportCosts() { + + @Override + public double getTransportTime(String fromId, String toId,double departureTime, Driver driver, Vehicle vehicle) { + return getTransportCost(fromId, toId, departureTime, driver, vehicle); + } + + @Override + public double getTransportCost(String fromId, String toId,double departureTime, Driver driver, Vehicle vehicle) { + return EuclideanDistanceCalculator.calculateDistance(coords.get(fromId), coords.get(toId)); + } + }; + Vehicle oldVehicle = VehicleImpl.Builder.newInstance("oldV").setLocationId("oldV").build(); + + VehicleRoute route = VehicleRoute.Builder.newInstance(oldVehicle, DriverImpl.noDriver()) + .addService(Service.Builder.newInstance("service", 0).setLocationId("service").build()) + .build(); + + Vehicle newVehicle = VehicleImpl.Builder.newInstance("newV").setLocationId("newV").build(); + + AdditionalAccessEgressCalculator accessEgressCalc = new AdditionalAccessEgressCalculator(routingCosts); + Job job = Service.Builder.newInstance("service2", 0).setLocationId("service").build(); + JobInsertionContext iContex = new JobInsertionContext(route, job, newVehicle, mock(Driver.class), 0.0); + assertEquals(8.0, accessEgressCalc.getCosts(iContex),0.01); + } } diff --git a/jsprit-examples/input/algorithmConfig.xml b/jsprit-examples/input/algorithmConfig.xml index 410727cd..917e27bd 100755 --- a/jsprit-examples/input/algorithmConfig.xml +++ b/jsprit-examples/input/algorithmConfig.xml @@ -26,7 +26,7 @@ - route + @@ -35,8 +35,10 @@ - - + + 0.05 + 20 + @@ -51,7 +53,7 @@ - + @@ -67,7 +69,7 @@ - + diff --git a/jsprit-examples/src/main/java/jsprit/examples/BuildAlgorithmFromScratchWithHardAndSoftConstraints.java b/jsprit-examples/src/main/java/jsprit/examples/BuildAlgorithmFromScratchWithHardAndSoftConstraints.java index 64f5aa9d..fa62669f 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/BuildAlgorithmFromScratchWithHardAndSoftConstraints.java +++ b/jsprit-examples/src/main/java/jsprit/examples/BuildAlgorithmFromScratchWithHardAndSoftConstraints.java @@ -40,7 +40,6 @@ import jsprit.core.algorithm.state.StateManager; import jsprit.core.algorithm.state.UpdateVariableCosts; import jsprit.core.algorithm.termination.IterationWithoutImprovementTermination; import jsprit.core.problem.VehicleRoutingProblem; -import jsprit.core.problem.constraint.AdditionalTransportationCosts; import jsprit.core.problem.constraint.ConstraintManager; import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.VehicleRoutingProblemSolution; @@ -135,7 +134,7 @@ public class BuildAlgorithmFromScratchWithHardAndSoftConstraints { * add an arbitrary number of hardConstraints by * constraintManager.addConstraint(...) */ - constraintManager.addConstraint(new AdditionalTransportationCosts(vrp.getTransportCosts())); + /* * define a fleetManager, here infinite vehicles can be used diff --git a/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExample.java b/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExample.java index af082fcd..2fc6cf24 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExample.java +++ b/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExample.java @@ -101,7 +101,7 @@ public class MultipleDepotExample { /* * solve the problem */ - VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfig.xml"); + VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfigWithSchrimpfAcceptance.xml"); vra.getAlgorithmListeners().addListener(new StopWatch(),Priority.HIGH); vra.getAlgorithmListeners().addListener(new AlgorithmSearchProgressChartListener("output/progress.png")); Collection solutions = vra.searchSolutions(); diff --git a/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExampleWithPenaltyVehicles.java b/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExampleWithPenaltyVehicles.java index 9d2b5efd..206b0f77 100644 --- a/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExampleWithPenaltyVehicles.java +++ b/jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExampleWithPenaltyVehicles.java @@ -32,7 +32,6 @@ import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem.FleetSize; import jsprit.core.problem.io.VrpXMLReader; import jsprit.core.problem.solution.VehicleRoutingProblemSolution; -import jsprit.core.problem.vehicle.PenaltyVehicleType; import jsprit.core.problem.vehicle.Vehicle; import jsprit.core.problem.vehicle.VehicleImpl; import jsprit.core.problem.vehicle.VehicleType; @@ -85,30 +84,13 @@ public class MultipleDepotExampleWithPenaltyVehicles { Vehicle vehicle = vehicleBuilder.build(); vrpBuilder.addVehicle(vehicle); } - /* - * define penalty-type with the same id, but other higher fixed and variable costs - */ - VehicleType penaltyType = VehicleTypeImpl.Builder.newInstance(depotCounter + "_type", capacity).setFixedCost(50).setCostPerDistance(3.0).build(); - /* - * to mark the penalty-type as penalty-type, wrap it with PenaltyVehicleType(Wrapper) - * this is to tell the fleetManager that this is not a regular but a penalty vehicle - */ - PenaltyVehicleType penaltyVehicleType = new PenaltyVehicleType(penaltyType,3); - String vehicleId = depotCounter + "_vehicle#penalty"; - VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance(vehicleId); - vehicleBuilder.setLocationCoord(depotCoord); - /* - * set PenaltyVehicleType - */ - vehicleBuilder.setType(penaltyVehicleType); - vehicleBuilder.setLatestArrival(maxDuration); - Vehicle penaltyVehicle = vehicleBuilder.build(); - vrpBuilder.addVehicle(penaltyVehicle); - depotCounter++; } - + /* + * define penalty-type with the same id, but other higher fixed and variable costs + */ + vrpBuilder.addPenaltyVehicles(3, 50); /* * define problem with finite fleet