mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
added egress/access calc
This commit is contained in:
parent
9a471a58be
commit
dc24411802
7 changed files with 135 additions and 34 deletions
|
|
@ -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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<String,Coordinate> coords = new HashMap<String, Coordinate>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
<construction>
|
||||
<insertion name="bestInsertion">
|
||||
<level forwardLooking="2" memory="1">route</level>
|
||||
|
||||
</insertion>
|
||||
</construction>
|
||||
|
||||
|
|
@ -35,8 +35,10 @@
|
|||
<searchStrategies>
|
||||
<searchStrategy name="radialRuinAndRecreate">
|
||||
<selector name="selectBest"/>
|
||||
<acceptor name="acceptNewRemoveWorst"/>
|
||||
|
||||
<acceptor name="schrimpfAcceptance">
|
||||
<alpha>0.05</alpha>
|
||||
<warmup>20</warmup>
|
||||
</acceptor>
|
||||
<modules>
|
||||
<module name="ruin_and_recreate">
|
||||
<ruin name="randomRuin">
|
||||
|
|
@ -51,7 +53,7 @@
|
|||
|
||||
<searchStrategy name="radialRuinAndRecreate">
|
||||
<selector name="selectBest"/>
|
||||
<acceptor name="acceptNewRemoveWorst"/>
|
||||
<acceptor name="schrimpfAcceptance"/>
|
||||
|
||||
<modules>
|
||||
<module name="ruin_and_recreate">
|
||||
|
|
@ -67,7 +69,7 @@
|
|||
|
||||
<searchStrategy name="radialRuinAndRecreate">
|
||||
<selector name="selectBest"/>
|
||||
<acceptor name="acceptNewRemoveWorst"/>
|
||||
<acceptor name="schrimpfAcceptance"/>
|
||||
<modules>
|
||||
<module name="ruin_and_recreate">
|
||||
<ruin id="2" name="radialRuin">
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue