diff --git a/jsprit-core/src/main/java/algorithms/Inserter.java b/jsprit-core/src/main/java/algorithms/Inserter.java
index a7dd5721..3e70125f 100644
--- a/jsprit-core/src/main/java/algorithms/Inserter.java
+++ b/jsprit-core/src/main/java/algorithms/Inserter.java
@@ -19,19 +19,91 @@ package algorithms;
import algorithms.InsertionData.NoInsertionFound;
import basics.Job;
import basics.Service;
+import basics.Shipment;
+import basics.route.DefaultShipmentActivityFactory;
import basics.route.DefaultTourActivityFactory;
+import basics.route.TourActivity;
import basics.route.TourActivityFactory;
+import basics.route.TourShipmentActivityFactory;
import basics.route.VehicleRoute;
class Inserter {
+
+ interface JobInsertionHandler {
+ void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route);
+
+ void setNextHandler(JobInsertionHandler handler);
+ }
+
+ class JobExceptionHandler implements JobInsertionHandler{
+
+ @Override
+ public void handleJobInsertion(Job job, InsertionData iData,VehicleRoute route) {
+ throw new IllegalStateException("job insertion is not supported. Do not know job type.");
+ }
+
+ @Override
+ public void setNextHandler(JobInsertionHandler handler) {
+ // TODO Auto-generated method stub
+
+ }
+
+ }
+
+ class ServiceInsertionHandler implements JobInsertionHandler{
+
+ private TourActivityFactory activityFactory = new DefaultTourActivityFactory();
+
+ private JobInsertionHandler delegator = new JobExceptionHandler();
+
+ @Override
+ public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
+ if(job instanceof Service){
+ route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), this.activityFactory.createActivity((Service)job));
+ route.setDepartureTime(iData.getVehicleDepartureTime());
+ }
+ else delegator.handleJobInsertion(job, iData, route);
+ }
+
+ public void setNextHandler(JobInsertionHandler jobInsertionHandler){
+ this.delegator = jobInsertionHandler;
+ }
+
+ }
+
+ class ShipmentInsertionHandler implements JobInsertionHandler {
+
+ private TourShipmentActivityFactory activityFactory = new DefaultShipmentActivityFactory();
+
+ private JobInsertionHandler delegator = new JobExceptionHandler();
+
+ @Override
+ public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
+ if(job instanceof Shipment){
+ TourActivity pickupShipment = this.activityFactory.createPickup((Shipment)job);
+ TourActivity deliverShipment = this.activityFactory.createDelivery((Shipment)job);
+ route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), deliverShipment);
+ route.getTourActivities().addActivity(iData.getPickupInsertionIndex(), pickupShipment);
+ route.setDepartureTime(iData.getVehicleDepartureTime());
+ }
+ else delegator.handleJobInsertion(job, iData, route);
+ }
+
+ public void setNextHandler(JobInsertionHandler jobInsertionHandler){
+ this.delegator = jobInsertionHandler;
+ }
+
+ }
private InsertionListeners insertionListeners;
- private TourActivityFactory activityFactory;
+ private JobInsertionHandler jobInsertionHandler;
public Inserter(InsertionListeners insertionListeners) {
this.insertionListeners = insertionListeners;
- activityFactory = new DefaultTourActivityFactory();
+ new DefaultTourActivityFactory();
+ jobInsertionHandler = new ServiceInsertionHandler();
+ jobInsertionHandler.setNextHandler(new ShipmentInsertionHandler());
}
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){
@@ -43,14 +115,7 @@ class Inserter {
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
-// if(vehicleRoute.getDepartureTime() != vehicleRoute.g)
- if(job instanceof Service) {
- vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), activityFactory.createActivity((Service)job));
- vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime());
- }
- else throw new IllegalStateException("neither service nor shipment. this is not supported.");
-
+ jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
-// updateTour(vehicleRoute);
}
}
diff --git a/jsprit-core/src/main/java/algorithms/LocalActivityInsertionCostsCalculator.java b/jsprit-core/src/main/java/algorithms/LocalActivityInsertionCostsCalculator.java
index f845fd33..9dd9a20b 100644
--- a/jsprit-core/src/main/java/algorithms/LocalActivityInsertionCostsCalculator.java
+++ b/jsprit-core/src/main/java/algorithms/LocalActivityInsertionCostsCalculator.java
@@ -30,6 +30,7 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
private HardActivityLevelConstraint hardConstraint;
private VehicleRoutingTransportCosts routingCosts;
+
private VehicleRoutingActivityCosts activityCosts;
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint) {
@@ -66,12 +67,16 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double oldCosts;
double oldTime;
if(iFacts.getRoute().isEmpty()){
- oldCosts = 0.0;
- oldTime = 0.0;
+ double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
+ double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
+
+ double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
+ oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
+ oldTime = (nextAct.getArrTime() - depTimeAtPrevAct);
}
else{
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
- double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getNewDriver(), iFacts.getNewVehicle());
+ double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
diff --git a/jsprit-core/src/main/java/algorithms/ShipmentInsertionCalculator.java b/jsprit-core/src/main/java/algorithms/ShipmentInsertionCalculator.java
index 1f2cb998..a2d91f8c 100644
--- a/jsprit-core/src/main/java/algorithms/ShipmentInsertionCalculator.java
+++ b/jsprit-core/src/main/java/algorithms/ShipmentInsertionCalculator.java
@@ -145,7 +145,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
if(totalActivityInsertionCosts < bestCost){
bestCost = totalActivityInsertionCosts;
pickupInsertionIndex = i;
- deliveryInsertionIndex = activities.size() - 1;
+ deliveryInsertionIndex = activities.size();
}
}
//update prevAct and endTime
@@ -166,43 +166,11 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
double totalActivityInsertionCosts = pickupAIC.getAdditionalCosts() + deliveryAIC.getAdditionalCosts();
if(totalActivityInsertionCosts < bestCost){
bestCost = totalActivityInsertionCosts;
- pickupInsertionIndex = activities.size() - 1;
- deliveryInsertionIndex = activities.size() - 1;
+ pickupInsertionIndex = activities.size();
+ deliveryInsertionIndex = activities.size();
}
}
}
-
-// for(TourActivity nextAct : activities){
-// if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
-// ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActEndTime);
-// if(mc != null){
-// if(mc.getAdditionalCosts() < bestCost){
-// bestCost = mc.getAdditionalCosts();
-// bestMarginals = mc;
-// insertionIndex = actIndex;
-// }
-// }
-// }
-// double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActEndTime, newDriver, newVehicle);
-// double nextActEndTime = CalcUtils.getActivityEndTime(nextActArrTime, nextAct);
-//
-// prevActEndTime = nextActEndTime;
-//
-// prevAct = nextAct;
-// actIndex++;
-// }
-// End nextAct = end;
-// if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){
-// ActivityInsertionCosts mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActEndTime);
-// if(mc != null) {
-// if(mc.getAdditionalCosts() < bestCost){
-// bestCost = mc.getAdditionalCosts();
-// bestMarginals = mc;
-// insertionIndex = actIndex;
-// }
-// }
-// }
-
if(pickupInsertionIndex == InsertionData.NO_INDEX) {
return InsertionData.noInsertionFound();
}
@@ -211,7 +179,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCalculator{
return insertionData;
}
- public ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
+ private ActivityInsertionCosts calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
return activityInsertionCostsCalculator.calculate(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
}
diff --git a/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java b/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java
index dad31f6a..ae020b00 100644
--- a/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java
+++ b/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java
@@ -236,14 +236,25 @@ public class VehicleRoutingProblem {
if(job instanceof Service) {
addService((Service) job);
}
+ else if(job instanceof Shipment){
+ addShipment((Shipment)job);
+ }
else{
- if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); }
- jobs.put(job.getId(),job);
+// if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); }
+// coordinates.put(job.getLocationId(), job.getCoord());
+// jobs.put(job.getId(),job);
}
return this;
}
+ private void addShipment(Shipment job) {
+ if(jobs.containsKey(job.getId())){ logger.warn("job " + job + " already in job list. overrides existing job."); }
+ coordinates.put(job.getPickupLocation(), job.getPickupCoord());
+ coordinates.put(job.getDeliveryLocation(), job.getDeliveryCoord());
+ jobs.put(job.getId(),job);
+ }
+
/**
* Adds a vehicle.
*
diff --git a/jsprit-core/src/main/java/basics/route/DeliverShipment.java b/jsprit-core/src/main/java/basics/route/DeliverShipment.java
index 0813bc9e..95c4a572 100644
--- a/jsprit-core/src/main/java/basics/route/DeliverShipment.java
+++ b/jsprit-core/src/main/java/basics/route/DeliverShipment.java
@@ -80,4 +80,8 @@ public final class DeliverShipment implements DeliveryActivity{
return new DeliverShipment(this);
}
+ @Override
+ public String toString() {
+ return "[act="+getName()+"][loc="+getLocationId()+"]";
+ }
}
diff --git a/jsprit-core/src/main/java/basics/route/PickupShipment.java b/jsprit-core/src/main/java/basics/route/PickupShipment.java
index 60c108d2..c509cf78 100644
--- a/jsprit-core/src/main/java/basics/route/PickupShipment.java
+++ b/jsprit-core/src/main/java/basics/route/PickupShipment.java
@@ -79,5 +79,10 @@ public final class PickupShipment implements PickupActivity{
public TourActivity duplicate() {
return new PickupShipment(this);
}
+
+ @Override
+ public String toString() {
+ return "[act="+getName()+"][loc="+getLocationId()+"]";
+ }
}
diff --git a/jsprit-core/src/main/java/basics/route/TourActivities.java b/jsprit-core/src/main/java/basics/route/TourActivities.java
index 1625b683..c7a1eaf5 100644
--- a/jsprit-core/src/main/java/basics/route/TourActivities.java
+++ b/jsprit-core/src/main/java/basics/route/TourActivities.java
@@ -152,6 +152,7 @@ public class TourActivities {
public void addActivity(int insertionIndex, TourActivity act) {
assert insertionIndex >= 0 : "insertionIndex == 0, this cannot be";
+ if(tourActivities.contains(act)) throw new IllegalStateException("act " + act + " already in tour. cannot add act twice.");
/*
* if 1 --> between start and act(0) --> act(0)
* if 2 && 2 <= acts.size --> between act(0) and act(1) --> act(1)
@@ -164,6 +165,12 @@ public class TourActivities {
addJob(act);
}
+ /**
+ * adds activity.
+ *
+ * @throw {@link IllegalStateException} if same activity is added twice.
+ * @param act
+ */
public void addActivity(TourActivity act){
if(tourActivities.contains(act)) throw new IllegalStateException("act " + act + " already in tour. cannot add act twice.");
tourActivities.add(act);
diff --git a/jsprit-core/src/main/java/basics/route/VehicleRoute.java b/jsprit-core/src/main/java/basics/route/VehicleRoute.java
index 3f6f41bc..865f3aa3 100644
--- a/jsprit-core/src/main/java/basics/route/VehicleRoute.java
+++ b/jsprit-core/src/main/java/basics/route/VehicleRoute.java
@@ -187,6 +187,11 @@ public class VehicleRoute {
public End getEnd() {
return end;
}
+
+ @Override
+ public String toString() {
+ return "[start="+start+"][end=" + end + "][departureTime=" + start.getEndTime() + "][vehicle=" + vehicle + "][driver=" + driver + "][nuOfActs="+tourActivities.getActivities().size()+"]";
+ }
@Deprecated
public void setVehicleRouteCostCalculator(VehicleRouteCostCalculator costAccumulator){
diff --git a/jsprit-core/src/test/java/algorithms/AverageJobDistanceTest.java b/jsprit-core/src/test/java/algorithms/AverageJobDistanceTest.java
new file mode 100644
index 00000000..ec375f72
--- /dev/null
+++ b/jsprit-core/src/test/java/algorithms/AverageJobDistanceTest.java
@@ -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);
+ }
+}
diff --git a/jsprit-core/src/test/java/algorithms/BuildPDVRPWithShipmentsAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildPDVRPWithShipmentsAlgoFromScratchTest.java
new file mode 100644
index 00000000..598f54a7
--- /dev/null
+++ b/jsprit-core/src/test/java/algorithms/BuildPDVRPWithShipmentsAlgoFromScratchTest.java
@@ -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 .
+ ******************************************************************************/
+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 vehicleRoutes, Collection 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 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");
+
+ }
+
+}
diff --git a/jsprit-core/src/test/java/algorithms/ShipmentInsertionCalculatorTest.java b/jsprit-core/src/test/java/algorithms/ShipmentInsertionCalculatorTest.java
new file mode 100644
index 00000000..5dac938a
--- /dev/null
+++ b/jsprit-core/src/test/java/algorithms/ShipmentInsertionCalculatorTest.java
@@ -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());
+ }
+
+}
diff --git a/jsprit-core/src/test/java/basics/route/TestTour.java b/jsprit-core/src/test/java/basics/route/TestTour.java
index e006f15c..6afcc5a5 100644
--- a/jsprit-core/src/test/java/basics/route/TestTour.java
+++ b/jsprit-core/src/test/java/basics/route/TestTour.java
@@ -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();