1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

add shipment based activities, modify inserter and implement

insertionAlgo for shipments
This commit is contained in:
oblonski 2013-10-21 07:53:09 +02:00
parent c31e61a797
commit 2835d15dd3
12 changed files with 570 additions and 51 deletions

View file

@ -0,0 +1,68 @@
package algorithms;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import java.awt.image.CropImageFilter;
import org.junit.Before;
import org.junit.Test;
import util.Coordinate;
import util.CrowFlyCosts;
import util.Locations;
import util.ManhattanCosts;
import basics.Service;
import basics.Shipment;
public class AverageJobDistanceTest {
private CrowFlyCosts routingCosts;
@Before
public void doBefore(){
Locations locations = new Locations(){
@Override
public Coordinate getCoord(String id) {
//assume: locationId="x,y"
String[] splitted = id.split(",");
return Coordinate.newInstance(Double.parseDouble(splitted[0]),
Double.parseDouble(splitted[1]));
}
};
routingCosts = new CrowFlyCosts(locations);
}
@Test
public void distanceOfTwoEqualShipmentsShouldBeSmallerThanAnyOtherDistance(){
Shipment s1 = Shipment.Builder.newInstance("s1", 1).setPickupLocation("0,0").setDeliveryLocation("10,10").build();
Shipment s2 = Shipment.Builder.newInstance("s2", 1).setPickupLocation("0,0").setDeliveryLocation("10,10").build();
double dist = new AvgJobDistance(routingCosts).calculateDistance(s1, s2);
for(int i=0;i<10;i++){
for(int j=0;j<10;j++){
Shipment other1 = Shipment.Builder.newInstance("s1", 1).setPickupLocation("0,0").setDeliveryLocation(i+","+j).build();
Shipment other2 = Shipment.Builder.newInstance("s2", 1).setPickupLocation("0,0").setDeliveryLocation("10,10").build();
double dist2 = new AvgJobDistance(routingCosts).calculateDistance(other1, other2);
System.out.println("("+i+","+j+"), dist=" + dist + ", dist2=" + dist2);
assertTrue(dist<=dist2+dist2*0.001);
}
}
}
@Test
public void whenServicesHaveSameLocation_distanceShouldBeZero(){
Service s1 = Service.Builder.newInstance("s1", 1).setLocationId("10,0").build();
Service s2 = Service.Builder.newInstance("s2", 1).setLocationId("10,0").build();
double dist = new AvgJobDistance(routingCosts).calculateDistance(s1, s2);
assertEquals(0.0,dist,0.01);
}
}

View file

@ -0,0 +1,219 @@
/*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package algorithms;
import java.util.Collection;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import util.Coordinate;
import util.Solutions;
import algorithms.HardConstraints.HardActivityLevelConstraintManager;
import algorithms.StateManager.StateImpl;
import algorithms.StateUpdates.UpdateActivityTimes;
import algorithms.StateUpdates.UpdateCostsAtAllLevels;
import algorithms.StateUpdates.UpdateEarliestStartTimeWindowAtActLocations;
import algorithms.StateUpdates.UpdateLatestOperationStartTimeAtActLocations;
import algorithms.acceptors.AcceptNewIfBetterThanWorst;
import algorithms.selectors.SelectBest;
import basics.Delivery;
import basics.Job;
import basics.Pickup;
import basics.Shipment;
import basics.VehicleRoutingAlgorithm;
import basics.VehicleRoutingProblem;
import basics.VehicleRoutingProblemSolution;
import basics.algo.InsertionStartsListener;
import basics.algo.JobInsertedListener;
import basics.algo.SearchStrategy;
import basics.algo.SearchStrategyManager;
import basics.algo.SolutionCostCalculator;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleImpl;
import basics.route.VehicleRoute;
import basics.route.VehicleType;
import basics.route.VehicleTypeImpl;
public class BuildPDVRPWithShipmentsAlgoFromScratchTest {
VehicleRoutingProblem vrp;
VehicleRoutingAlgorithm vra;
static Logger log = Logger.getLogger(BuildPDVRPWithShipmentsAlgoFromScratchTest.class);
@Before
public void setup(){
VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance();
VehicleType type = VehicleTypeImpl.Builder.newInstance("t", 2).setCostPerDistance(1.0).build();
Vehicle v = VehicleImpl.Builder.newInstance("v").setLocationCoord(Coordinate.newInstance(-1, -1)).setType(type).build();
Shipment s1 = Shipment.Builder.newInstance("s1", 1).setPickupCoord(Coordinate.newInstance(0, 0)).setDeliveryCoord(Coordinate.newInstance(10, 10)).build();
Shipment s2 = Shipment.Builder.newInstance("s2", 1).setPickupCoord(Coordinate.newInstance(1, 1)).setDeliveryCoord(Coordinate.newInstance(10, 10)).build();
builder.addJob(s1).addJob(s2);
builder.addVehicle(v);
vrp = builder.build();
final StateManagerImpl stateManager = new StateManagerImpl();
HardActivityLevelConstraintManager actLevelConstraintAccumulator = new HardActivityLevelConstraintManager();
actLevelConstraintAccumulator.addConstraint(new HardConstraints.HardPickupAndDeliveryActivityLevelConstraint(stateManager));
actLevelConstraintAccumulator.addConstraint(new HardConstraints.HardTimeWindowActivityLevelConstraint(stateManager, vrp.getTransportCosts()));
ActivityInsertionCostsCalculator marginalCalculus = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), actLevelConstraintAccumulator);
ShipmentInsertionCalculator serviceInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), marginalCalculus, new HardConstraints.HardPickupAndDeliveryLoadConstraint(stateManager));
// CalculatesServiceInsertion serviceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), marginalCalculus, new HardConstraints.HardLoadConstraint(stateManager));
VehicleFleetManager fleetManager = new InfiniteVehicles(vrp.getVehicles());
JobInsertionCalculator finalServiceInsertion = new CalculatesVehTypeDepServiceInsertion(fleetManager, serviceInsertion);
BestInsertion bestInsertion = new BestInsertion(finalServiceInsertion);
RuinRadial radial = new RuinRadial(vrp, 0.15, new AvgJobDistance(vrp.getTransportCosts()));
RuinRandom random = new RuinRandom(vrp, 0.25);
SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() {
@Override
public void calculateCosts(VehicleRoutingProblemSolution solution) {
double costs = 0.0;
for(VehicleRoute route : solution.getRoutes()){
costs += stateManager.getRouteState(route, StateTypes.COSTS).toDouble();
}
solution.setCost(costs);
}
};
SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator);
RuinAndRecreateModule randomModule = new RuinAndRecreateModule("randomRuin_bestInsertion", bestInsertion, random);
randomStrategy.addModule(randomModule);
SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator);
RuinAndRecreateModule radialModule = new RuinAndRecreateModule("radialRuin_bestInsertion", bestInsertion, radial);
radialStrategy.addModule(radialModule);
SearchStrategyManager strategyManager = new SearchStrategyManager();
strategyManager.addStrategy(radialStrategy, 0.5);
strategyManager.addStrategy(randomStrategy, 0.5);
vra = new VehicleRoutingAlgorithm(vrp, strategyManager);
vra.getAlgorithmListeners().addListener(new StateUpdates.ResetStateManager(stateManager));
final RouteActivityVisitor iterateForward = new RouteActivityVisitor();
iterateForward.addActivityVisitor(new UpdateActivityTimes(vrp.getTransportCosts()));
iterateForward.addActivityVisitor(new UpdateEarliestStartTimeWindowAtActLocations(stateManager, vrp.getTransportCosts()));
iterateForward.addActivityVisitor(new UpdateCostsAtAllLevels(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
iterateForward.addActivityVisitor(new StateUpdates.UpdateOccuredDeliveriesAtActivityLevel(stateManager));
iterateForward.addActivityVisitor(new StateUpdates.UpdateLoadAtActivityLevel(stateManager));
final ReverseRouteActivityVisitor iterateBackward = new ReverseRouteActivityVisitor();
iterateBackward.addActivityVisitor(new UpdateLatestOperationStartTimeAtActLocations(stateManager, vrp.getTransportCosts()));
iterateBackward.addActivityVisitor(new StateUpdates.UpdateFuturePickupsAtActivityLevel(stateManager));
InsertionStartsListener loadVehicleInDepot = new InsertionStartsListener() {
@Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
for(VehicleRoute route : vehicleRoutes){
int loadAtDepot = 0;
int loadAtEnd = 0;
for(Job j : route.getTourActivities().getJobs()){
if(j instanceof Delivery){
loadAtDepot += j.getCapacityDemand();
}
if(j instanceof Pickup){
loadAtEnd += j.getCapacityDemand();
}
}
stateManager.putRouteState(route, StateTypes.LOAD_AT_DEPOT, new StateImpl(loadAtDepot));
stateManager.putRouteState(route, StateTypes.LOAD, new StateImpl(loadAtEnd));
iterateForward.visit(route);
iterateBackward.visit(route);
}
}
};
vra.getSearchStrategyManager().addSearchStrategyModuleListener(new RemoveEmptyVehicles(fleetManager));
JobInsertedListener updateLoadAfterJobHasBeenInserted = new JobInsertedListener() {
@Override
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
// log.info("insert job " + job2insert.getClass().toString() + " job " + job2insert + "" + job2insert.getCapacityDemand() + " in route " + inRoute.getTourActivities());
if(job2insert instanceof Delivery){
int loadAtDepot = (int) stateManager.getRouteState(inRoute, StateTypes.LOAD_AT_DEPOT).toDouble();
// log.info("loadAtDepot="+loadAtDepot);
stateManager.putRouteState(inRoute, StateTypes.LOAD_AT_DEPOT, new StateImpl(loadAtDepot + job2insert.getCapacityDemand()));
}
if(job2insert instanceof Pickup){
int loadAtEnd = (int) stateManager.getRouteState(inRoute, StateTypes.LOAD).toDouble();
// log.info("loadAtEnd="+loadAtEnd);
stateManager.putRouteState(inRoute, StateTypes.LOAD, new StateImpl(loadAtEnd + job2insert.getCapacityDemand()));
}
iterateForward.visit(inRoute);
iterateBackward.visit(inRoute);
}
};
bestInsertion.addListener(loadVehicleInDepot);
bestInsertion.addListener(updateLoadAfterJobHasBeenInserted);
VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion, solutionCostCalculator).createInitialSolution(vrp);
// System.out.println("ini: costs="+iniSolution.getCost()+";#routes="+iniSolution.getRoutes().size());
vra.addInitialSolution(iniSolution);
vra.setNuOfIterations(10000);
vra.setPrematureBreak(1000);
}
@Test
public void test(){
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
VehicleRoutingProblemSolution best = Solutions.getBest(solutions);
System.out.println(best.getCost());
for(VehicleRoute r : best.getRoutes()){
System.out.println(r);
System.out.println("#jobs="+r.getTourActivities().jobSize());
System.out.println(r.getStart());
for(TourActivity act : r.getTourActivities().getActivities()){
System.out.println(act);
}
System.out.println(r.getEnd());
}
// for()
// new VrpXMLWriter(vrp, solutions).write("output/pd_solomon_r101.xml");
}
}

View file

@ -0,0 +1,160 @@
package algorithms;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import util.Coordinate;
import util.Locations;
import util.ManhattanCosts;
import algorithms.HardConstraints.HardActivityLevelConstraint;
import algorithms.HardConstraints.HardRouteLevelConstraint;
import basics.Shipment;
import basics.costs.VehicleRoutingActivityCosts;
import basics.costs.VehicleRoutingTransportCosts;
import basics.route.Driver;
import basics.route.TourActivity;
import basics.route.Vehicle;
import basics.route.VehicleImpl;
import basics.route.VehicleRoute;
import basics.route.VehicleType;
import basics.route.VehicleTypeImpl;
public class ShipmentInsertionCalculatorTest {
VehicleRoutingTransportCosts routingCosts;
VehicleRoutingActivityCosts activityCosts = new VehicleRoutingActivityCosts(){
@Override
public double getActivityCost(TourActivity tourAct, double arrivalTime,Driver driver, Vehicle vehicle) {
return 0;
}
};
HardActivityLevelConstraint hardActivityLevelConstraint = new HardActivityLevelConstraint() {
@Override
public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
return true;
}
};
HardRouteLevelConstraint hardRouteLevelConstraint = new HardRouteLevelConstraint(){
@Override
public boolean fulfilled(InsertionContext insertionContext) {
return true;
}
};
ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
ShipmentInsertionCalculator insertionCalculator;
Vehicle vehicle;
@Before
public void doBefore(){
Locations locations = new Locations(){
@Override
public Coordinate getCoord(String id) {
//assume: locationId="x,y"
String[] splitted = id.split(",");
return Coordinate.newInstance(Double.parseDouble(splitted[0]),
Double.parseDouble(splitted[1]));
}
};
routingCosts = new ManhattanCosts(locations);
VehicleType type = VehicleTypeImpl.Builder.newInstance("t", 1).setCostPerDistance(1).build();
vehicle = VehicleImpl.Builder.newInstance("v").setLocationId("0,0").setType(type).build();
activityInsertionCostsCalculator = new LocalActivityInsertionCostsCalculator(routingCosts, activityCosts, hardActivityLevelConstraint);
createInsertionCalculator(hardRouteLevelConstraint);
}
private void createInsertionCalculator(HardRouteLevelConstraint hardRouteLevelConstraint) {
insertionCalculator = new ShipmentInsertionCalculator(routingCosts, activityInsertionCostsCalculator, hardRouteLevelConstraint);
}
@Test
public void whenCalculatingInsertionCostsOfShipment_itShouldReturnCorrectCostValue(){
Shipment shipment = Shipment.Builder.newInstance("s", 1).setPickupLocation("0,10").setDeliveryLocation("10,0").build();
VehicleRoute route = VehicleRoute.emptyRoute();
InsertionData iData = insertionCalculator.calculate(route, shipment, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(40.0,iData.getInsertionCost(),0.05);
}
@Test
public void whenCalculatingInsertionIntoExistingRoute_itShouldReturnCorrectCosts(){
Shipment shipment = Shipment.Builder.newInstance("s", 1).setPickupLocation("0,10").setDeliveryLocation("10,0").build();
Shipment shipment2 = Shipment.Builder.newInstance("s2", 1).setPickupLocation("10,10").setDeliveryLocation("0,0").build();
VehicleRoute route = VehicleRoute.emptyRoute();
new Inserter(new InsertionListeners()).insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route);
InsertionData iData = insertionCalculator.calculate(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(0.0,iData.getInsertionCost(),0.05);
assertEquals(1,iData.getPickupInsertionIndex());
assertEquals(2,iData.getDeliveryInsertionIndex());
}
@Test
public void whenInsertingShipmentInRouteWithNotEnoughCapacity_itShouldReturnNoInsertion(){
Shipment shipment = Shipment.Builder.newInstance("s", 1).setPickupLocation("0,10").setDeliveryLocation("10,0").build();
Shipment shipment2 = Shipment.Builder.newInstance("s2", 1).setPickupLocation("10,10").setDeliveryLocation("0,0").build();
VehicleRoute route = VehicleRoute.emptyRoute();
new Inserter(new InsertionListeners()).insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route);
createInsertionCalculator(new HardRouteLevelConstraint() {
@Override
public boolean fulfilled(InsertionContext insertionContext) {
return false;
}
});
InsertionData iData = insertionCalculator.calculate(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(InsertionData.noInsertionFound(),iData);
}
@Test
public void whenInsertingThirdShipment_itShouldCalcCorrectVal(){
Shipment shipment = Shipment.Builder.newInstance("s", 1).setPickupLocation("0,10").setDeliveryLocation("10,0").build();
Shipment shipment2 = Shipment.Builder.newInstance("s2", 1).setPickupLocation("10,10").setDeliveryLocation("0,0").build();
Shipment shipment3 = Shipment.Builder.newInstance("s3", 1).setPickupLocation("0,0").setDeliveryLocation("9,10").build();
VehicleRoute route = VehicleRoute.emptyRoute();
Inserter inserter = new Inserter(new InsertionListeners());
inserter.insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route);
inserter.insertJob(shipment2, new InsertionData(0,1,2,vehicle,null),route);
InsertionData iData = insertionCalculator.calculate(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(0.0,iData.getInsertionCost(),0.05);
assertEquals(0,iData.getPickupInsertionIndex());
assertEquals(1,iData.getDeliveryInsertionIndex());
}
@Test
public void whenInsertingThirdShipment_itShouldCalcCorrectVal2(){
Shipment shipment = Shipment.Builder.newInstance("s", 1).setPickupLocation("0,10").setDeliveryLocation("10,0").build();
Shipment shipment2 = Shipment.Builder.newInstance("s2", 1).setPickupLocation("10,10").setDeliveryLocation("0,0").build();
Shipment shipment3 = Shipment.Builder.newInstance("s3", 1).setPickupLocation("0,0").setDeliveryLocation("9,9").build();
VehicleRoute route = VehicleRoute.emptyRoute();
Inserter inserter = new Inserter(new InsertionListeners());
inserter.insertJob(shipment, new InsertionData(0,0,0,vehicle,null), route);
inserter.insertJob(shipment2, new InsertionData(0,1,2,vehicle,null),route);
InsertionData iData = insertionCalculator.calculate(route, shipment3, vehicle, 0.0, null, Double.MAX_VALUE);
assertEquals(2.0,iData.getInsertionCost(),0.05);
assertEquals(0,iData.getPickupInsertionIndex());
assertEquals(1,iData.getDeliveryInsertionIndex());
}
}

View file

@ -87,6 +87,8 @@ public class TestTour {
assertEquals(2,tour.getActivities().size());
}
@Test
public void whenRemovingShipment_tourShouldNotServiceItAnymore(){
Shipment s = Shipment.Builder.newInstance("s", 1).setDeliveryLocation("delLoc").setPickupLocation("pickLoc").build();