From 099d01ddd8682513033f193163512bd26c3f5e7a Mon Sep 17 00:00:00 2001 From: Stefan Schroeder <4sschroeder@gmail.com> Date: Wed, 21 Aug 2013 13:53:27 +0200 Subject: [PATCH] experiment with insertionCalcs --- .../algorithms/BackwardInTimeListeners.java | 50 ++ .../algorithms/BestInsertionConcurrent.java | 352 +++++++------- .../CalculatesServiceInsertion.java | 60 +-- ...tesServiceInsertionConsideringFixCost.java | 16 +- ...alculatesServiceInsertionOnRouteLevel.java | 22 +- ...erviceInsertionWithTriangleInequality.java | 211 ++++++++ .../CalculatesVehTypeDepServiceInsertion.java | 15 +- .../java/algorithms/CalculatorBuilder.java | 36 +- .../ConfigureFixCostCalculator.java | 2 +- .../algorithms/FindCheaperVehicleAlgo.java | 2 +- .../algorithms/ForwardInTimeListeners.java | 39 ++ .../main/java/algorithms/HardConstraint.java | 7 + .../src/main/java/algorithms/Inserter.java | 2 +- .../main/java/algorithms/InsertionData.java | 16 + .../java/algorithms/InsertionFactory.java | 27 +- .../java/algorithms/InsertionListeners.java | 4 +- .../IterateRouteBackwardInTime.java | 69 +++ .../algorithms/IterateRouteForwardInTime.java | 85 ++++ .../src/main/java/algorithms/JobObserver.java | 2 +- .../main/java/algorithms/RegretInsertion.java | 456 +++++++++--------- .../src/main/java/algorithms/StateTypes.java | 8 +- .../main/java/algorithms/StatesContainer.java | 8 +- .../java/algorithms/StatesContainerImpl.java | 92 +++- .../java/algorithms/TourStateUpdater.java | 91 ---- .../algorithms/UdateCostsAtRouteLevel.java | 53 ++ .../java/algorithms/UpdateActivityTimes.java | 26 + .../algorithms/UpdateCostsAtAllLevels.java | 81 ++++ ...EarliestStartTimeWindowAtActLocations.java | 31 ++ ...atestOperationStartTimeAtActLocations.java | 32 ++ .../algorithms/UpdateLoadAtAllLevels.java | 46 ++ .../algorithms/UpdateLoadAtRouteLevel.java | 42 ++ .../src/main/java/algorithms/UpdateRoute.java | 36 -- .../main/java/algorithms/UpdateStates.java | 55 +++ .../UpdateTourStatesBackwardInTime.java | 105 ---- .../UpdateTourStatesForwardInTime.java | 156 ------ .../java/algorithms/VehicleRouteUpdater.java | 2 +- .../algorithms/VehicleRoutingAlgorithms.java | 95 ++-- .../java/basics/algo/JobInsertedListener.java | 2 +- .../src/main/java/basics/route/End.java | 1 + .../test/java/algorithms/AlgorithmsSuite.java | 1 - .../java/algorithms/GendreauPostOptTest.java | 64 +-- .../TestCalculatesActivityInsertion.java | 286 ----------- .../TestCalculatesServiceInsertion.java | 44 +- ...alculatesServiceInsertionOnRouteLevel.java | 14 +- .../TestIterateRouteForwardInTime.java | 196 ++++++++ .../TestTourStateUpdaterWithService.java | 10 +- jsprit-examples/input/algorithmConfig.xml | 4 +- 47 files changed, 1711 insertions(+), 1343 deletions(-) create mode 100644 jsprit-core/src/main/java/algorithms/BackwardInTimeListeners.java create mode 100644 jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTriangleInequality.java create mode 100644 jsprit-core/src/main/java/algorithms/ForwardInTimeListeners.java create mode 100644 jsprit-core/src/main/java/algorithms/HardConstraint.java create mode 100644 jsprit-core/src/main/java/algorithms/IterateRouteBackwardInTime.java create mode 100644 jsprit-core/src/main/java/algorithms/IterateRouteForwardInTime.java delete mode 100644 jsprit-core/src/main/java/algorithms/TourStateUpdater.java create mode 100644 jsprit-core/src/main/java/algorithms/UdateCostsAtRouteLevel.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateActivityTimes.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateEarliestStartTimeWindowAtActLocations.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateLatestOperationStartTimeAtActLocations.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateLoadAtAllLevels.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateLoadAtRouteLevel.java delete mode 100644 jsprit-core/src/main/java/algorithms/UpdateRoute.java create mode 100644 jsprit-core/src/main/java/algorithms/UpdateStates.java delete mode 100644 jsprit-core/src/main/java/algorithms/UpdateTourStatesBackwardInTime.java delete mode 100644 jsprit-core/src/main/java/algorithms/UpdateTourStatesForwardInTime.java delete mode 100644 jsprit-core/src/test/java/algorithms/TestCalculatesActivityInsertion.java create mode 100644 jsprit-core/src/test/java/algorithms/TestIterateRouteForwardInTime.java diff --git a/jsprit-core/src/main/java/algorithms/BackwardInTimeListeners.java b/jsprit-core/src/main/java/algorithms/BackwardInTimeListeners.java new file mode 100644 index 00000000..1904155b --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/BackwardInTimeListeners.java @@ -0,0 +1,50 @@ +package algorithms; + +import java.util.ArrayList; +import java.util.Collection; + +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class BackwardInTimeListeners { + + interface BackwardInTimeListener{ + + public void start(VehicleRoute route); + + public void prevActivity(TourActivity act, double latestDepartureTime, double latestOperationStartTime); + + public void finnish(); + + } + + private Collection listeners = new ArrayList(); + + public void addListener(BackwardInTimeListener l){ + listeners.add(l); + } + + public void start(VehicleRoute route){ + for(BackwardInTimeListener l : listeners){ l.start(route); } + } + + /** + * Informs listener about nextActivity. + * + *

LatestDepartureTime is the theoretical latest departureTime to meet the latestOperationStartTimeWindow at the nextActivity (forward in time), i.e. + * assume act_i and act_j are two successive activities and the latestDepTime of act_j is 10pm. With a travelTime from act_i to act_j of 1h the latestDepartureTime at act_i is 9pm. + * However, the latestOperationStartTime of act_i is 8pm, then (with a serviceTime of 0) the latestOperationStartTime at act_i amounts to 8pm. + * + * @param act + * @param latestDepartureTime + * @param latestOperationStartTime + */ + public void prevActivity(TourActivity act, double latestDepartureTime, double latestOperationStartTime){ + for(BackwardInTimeListener l : listeners){ l.prevActivity(act,latestDepartureTime,latestOperationStartTime); } + } + + public void finnish(){ + for(BackwardInTimeListener l : listeners){ l.finnish(); } + } + +} diff --git a/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java b/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java index 742e29b4..4f41d2e0 100644 --- a/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java +++ b/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java @@ -33,182 +33,182 @@ import basics.Job; import basics.algo.InsertionListener; import basics.route.VehicleRoute; - - -/** - * - * @author stefan schroeder - * - */ - -final class BestInsertionConcurrent implements InsertionStrategy{ - - public static BestInsertionConcurrent newInstance(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads){ - return new BestInsertionConcurrent(routeAlgorithm, executor, nuOfThreads); - } - - static class Batch { - List routes = new ArrayList(); - - } - - private static Logger logger = Logger.getLogger(BestInsertionConcurrent.class); - - private Random random = RandomNumberGeneration.getRandom(); - - private RouteAlgorithm routeAlgorithm; - -// private ExecutorService executor; - - private int nuOfBatches; - - private ExecutorCompletionService completionService; - - public void setRandom(Random random) { - this.random = random; - } - - private BestInsertionConcurrent(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads) { - super(); - this.routeAlgorithm = routeAlgorithm; -// this.executor = executor; - logger.info("initialise " + this); - this.nuOfBatches = nuOfThreads; - completionService = new ExecutorCompletionService(executor); - } - - @Override - public String toString() { - return "[name=concurrentBestInsertion]"; - } - - @Override - public void insertJobs(Collection vehicleRoutes, Collection unassignedJobs) { - List unassignedJobList = new ArrayList(unassignedJobs); - Collections.shuffle(unassignedJobList, random); -// informInsertionStarts(vehicleRoutes,unassignedJobs.size()); - int inserted = 0; - for(final Job unassignedJob : unassignedJobList){ - VehicleRoute insertIn = null; - Insertion bestInsertion = null; - double bestInsertionCost = Double.MAX_VALUE; - - List batches = distributeRoutes(vehicleRoutes,nuOfBatches); - - for(final Batch batch : batches){ - completionService.submit(new Callable() { - - @Override - public Insertion call() throws Exception { - return getBestInsertion(batch,unassignedJob); - } - - }); - - } - - try{ - for(int i=0;i futureIData = completionService.take(); - Insertion insertion = futureIData.get(); - if(insertion == null) continue; - if(insertion.getInsertionData().getInsertionCost() < bestInsertionCost){ - bestInsertion = insertion; - bestInsertionCost = insertion.getInsertionData().getInsertionCost(); - } - } - } - catch(InterruptedException e){ - Thread.currentThread().interrupt(); - } - catch (ExecutionException e) { - e.printStackTrace(); - logger.error(e.getCause().toString()); - System.exit(1); - } - - if(bestInsertion != null){ -// informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); - insertIn = bestInsertion.getRoute(); -// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost()); - routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); - } - else { -// VehicleRoute newRoute = VehicleRoute.emptyRoute(); -// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE); -// if(bestI instanceof InsertionData.NoInsertionFound) - throw new IllegalStateException("given the vehicles, could not create a valid solution.\n\tthe reason might be" + - " inappropriate vehicle capacity.\n\tthe job that does not fit in any vehicle anymore is \n\t" + unassignedJob); -// insertIn = newRoute; -// informBeforeJobInsertion(unassignedJob,bestI,newRoute); -// routeAlgorithm.insertJob(unassignedJob,bestI,newRoute); -// vehicleRoutes.add(newRoute); - } - inserted++; -// informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn); - } -// informInsertionEndsListeners(vehicleRoutes); - } - - private Insertion getBestInsertion(Batch batch, Job unassignedJob) { - Insertion bestInsertion = null; - double bestInsertionCost = Double.MAX_VALUE; - for(VehicleRoute vehicleRoute : batch.routes){ - InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost); - if(iData instanceof NoInsertionFound) continue; - if(iData.getInsertionCost() < bestInsertionCost){ - bestInsertion = new Insertion(vehicleRoute,iData); - bestInsertionCost = iData.getInsertionCost(); - } - } - return bestInsertion; - } - - private List distributeRoutes(Collection vehicleRoutes, int nuOfBatches) { - List batches = new ArrayList(); - for(int i=0;i routes = new ArrayList(); +// +// } +// +// private static Logger logger = Logger.getLogger(BestInsertionConcurrent.class); +// +// private Random random = RandomNumberGeneration.getRandom(); +// +// private RouteAlgorithm routeAlgorithm; +// +//// private ExecutorService executor; +// +// private int nuOfBatches; +// +// private ExecutorCompletionService completionService; +// +// public void setRandom(Random random) { +// this.random = random; +// } +// +// private BestInsertionConcurrent(RouteAlgorithm routeAlgorithm, ExecutorService executor, int nuOfThreads) { +// super(); +// this.routeAlgorithm = routeAlgorithm; +//// this.executor = executor; +// logger.info("initialise " + this); +// this.nuOfBatches = nuOfThreads; +// completionService = new ExecutorCompletionService(executor); +// } +// +// @Override +// public String toString() { +// return "[name=concurrentBestInsertion]"; +// } +// +// @Override +// public void insertJobs(Collection vehicleRoutes, Collection unassignedJobs) { +// List unassignedJobList = new ArrayList(unassignedJobs); +// Collections.shuffle(unassignedJobList, random); +//// informInsertionStarts(vehicleRoutes,unassignedJobs.size()); +// int inserted = 0; +// for(final Job unassignedJob : unassignedJobList){ +// VehicleRoute insertIn = null; +// Insertion bestInsertion = null; +// double bestInsertionCost = Double.MAX_VALUE; +// +// List batches = distributeRoutes(vehicleRoutes,nuOfBatches); +// +// for(final Batch batch : batches){ +// completionService.submit(new Callable() { +// +// @Override +// public Insertion call() throws Exception { +// return getBestInsertion(batch,unassignedJob); +// } +// +// }); +// +// } +// +// try{ +// for(int i=0;i futureIData = completionService.take(); +// Insertion insertion = futureIData.get(); +// if(insertion == null) continue; +// if(insertion.getInsertionData().getInsertionCost() < bestInsertionCost){ +// bestInsertion = insertion; +// bestInsertionCost = insertion.getInsertionData().getInsertionCost(); +// } +// } +// } +// catch(InterruptedException e){ +// Thread.currentThread().interrupt(); +// } +// catch (ExecutionException e) { +// e.printStackTrace(); +// logger.error(e.getCause().toString()); +// System.exit(1); +// } +// +// if(bestInsertion != null){ +//// informBeforeJobInsertion(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); +// insertIn = bestInsertion.getRoute(); +//// logger.debug("insert job="+unassignedJob+" at index=" + bestInsertion.getInsertionData().getInsertionIndex() + " delta cost=" + bestInsertion.getInsertionData().getInsertionCost()); +// routeAlgorithm.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); +// } +// else { +//// VehicleRoute newRoute = VehicleRoute.emptyRoute(); +//// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE); +//// if(bestI instanceof InsertionData.NoInsertionFound) +// throw new IllegalStateException("given the vehicles, could not create a valid solution.\n\tthe reason might be" + +// " inappropriate vehicle capacity.\n\tthe job that does not fit in any vehicle anymore is \n\t" + unassignedJob); +//// insertIn = newRoute; +//// informBeforeJobInsertion(unassignedJob,bestI,newRoute); +//// routeAlgorithm.insertJob(unassignedJob,bestI,newRoute); +//// vehicleRoutes.add(newRoute); +// } +// inserted++; +//// informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn); +// } +//// informInsertionEndsListeners(vehicleRoutes); +// } +// +// private Insertion getBestInsertion(Batch batch, Job unassignedJob) { +// Insertion bestInsertion = null; +// double bestInsertionCost = Double.MAX_VALUE; +// for(VehicleRoute vehicleRoute : batch.routes){ +// InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost); +// if(iData instanceof NoInsertionFound) continue; +// if(iData.getInsertionCost() < bestInsertionCost){ +// bestInsertion = new Insertion(vehicleRoute,iData); +// bestInsertionCost = iData.getInsertionCost(); // } // } -// else{ - vehicleRoutes.add(VehicleRoute.emptyRoute()); +// return bestInsertion; +// } +// +// private List distributeRoutes(Collection vehicleRoutes, int nuOfBatches) { +// List batches = new ArrayList(); +// for(int i=0;i getListeners() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void addListener(InsertionListener insertionListener) { - // TODO Auto-generated method stub - - } - -} +// return batches; +// } +// +// +// @Override +// public void removeListener(InsertionListener insertionListener) { +// // TODO Auto-generated method stub +// +// } +// +// @Override +// public Collection getListeners() { +// // TODO Auto-generated method stub +// return null; +// } +// +// @Override +// public void addListener(InsertionListener insertionListener) { +// // TODO Auto-generated method stub +// +// } +// +//} diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java index 482036f9..616f60be 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java +++ b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java @@ -15,8 +15,7 @@ package algorithms; import org.apache.log4j.Logger; import util.Neighborhood; - -import algorithms.RouteStates.ActivityState; +import algorithms.StatesContainer.State; import basics.Job; import basics.Service; import basics.costs.VehicleRoutingActivityCosts; @@ -28,8 +27,8 @@ import basics.route.Start; import basics.route.TourActivities; import basics.route.TourActivity; import basics.route.Vehicle; -import basics.route.VehicleRoute; import basics.route.VehicleImpl.NoVehicle; +import basics.route.VehicleRoute; @@ -37,7 +36,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ private static final Logger logger = Logger.getLogger(CalculatesServiceInsertion.class); - private RouteStates routeStates; + private StatesContainer states; private VehicleRoutingTransportCosts routingCosts; @@ -62,12 +61,8 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ logger.info("initialise neighborhood " + neighborhood); } - public void setActivityStates(RouteStates actStates){ - this.routeStates = actStates; - } - - public ActivityState state(TourActivity act){ - return routeStates.getState(act); + public void setActivityStates(StatesContainer activityStates2){ + this.states = activityStates2; } public CalculatesServiceInsertion(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) { @@ -96,21 +91,25 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ double bestCost = bestKnownCosts; Service service = (Service)jobToInsert; - if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){ + int currentLoad = (int) states.getRouteState(currentRoute, StateTypes.LOAD).toDouble(); + if(currentLoad + service.getCapacityDemand() > newVehicle.getCapacity()){ return InsertionData.noInsertionFound(); } int insertionIndex = InsertionData.NO_INDEX; TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service); -// TourActivity deliveryAct2Insert = actStates.getActivity(service, true); initialiseStartAndEnd(newVehicle, newVehicleDepartureTime); TourActivity prevAct = start; double prevCostInOriginalTour = 0.0; int actIndex = 0; +// logger.debug(prevAct.toString()); for(TourActivity nextAct : tour.getActivities()){ - double nextCostInOriginalTour = state(nextAct).getCurrentCost(); +// logger.debug(prevAct.toString() + " arrTime=" + prevAct.getArrTime() + " endTime=" + prevAct.getEndTime()); +// logger.debug(deliveryAct2Insert.toString() + " arrTime=" + deliveryAct2Insert.getArrTime() + " endTime=" + deliveryAct2Insert.getEndTime()); +// logger.debug(nextAct.toString() + " arrTime=" + nextAct.getArrTime() + " endTime=" + nextAct.getEndTime()); + double nextCostInOriginalTour = states.getActivityState(nextAct,StateTypes.COSTS).toDouble(); if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour); if(mc < bestCost){ @@ -123,8 +122,12 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ actIndex++; } End nextAct = end; +// logger.debug(prevAct.toString() + " arrTime=" + prevAct.getArrTime() + " endTime=" + prevAct.getEndTime()); +// logger.debug(deliveryAct2Insert.toString() + " arrTime=" + deliveryAct2Insert.getArrTime() + " endTime=" + deliveryAct2Insert.getEndTime()); +// logger.debug(nextAct.toString() + " arrTime=" + nextAct.getArrTime() + " endTime=" + nextAct.getEndTime()); if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ - double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, routeStates.getRouteState(currentRoute).getCosts() - prevCostInOriginalTour); + double oldRouteCosts = states.getRouteState(currentRoute, StateTypes.COSTS).toDouble(); + double mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, oldRouteCosts - prevCostInOriginalTour); if(mc < bestCost){ bestCost = mc; insertionIndex = actIndex; @@ -139,8 +142,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ return insertionData; } - private void initialiseStartAndEnd(final Vehicle newVehicle, - double newVehicleDepartureTime) { + private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) { if(start == null){ start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival()); start.setEndTime(newVehicleDepartureTime); @@ -159,6 +161,7 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ end.setLocationId(newVehicle.getLocationId()); end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime); end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival()); + end.setEndTime(newVehicle.getLatestArrival()); } } @@ -174,9 +177,9 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle); - if((tp_costs_prevAct_newAct + act_costs_newAct - costWithoutNewJob) > bestKnownCosts){ - return Double.MAX_VALUE; - } +// if((tp_costs_prevAct_newAct + act_costs_newAct - costWithoutNewJob) > bestKnownCosts){ +// return Double.MAX_VALUE; +// } double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle); double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, driver, vehicle); @@ -184,26 +187,25 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle); - double activityInsertionCosts; +// logger.debug("nextActArrTime="+nextAct_arrTime); double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct; if(totalCosts - costWithoutNewJob > bestKnownCosts){ - activityInsertionCosts = Double.MAX_VALUE; + return Double.MAX_VALUE; } if(nextAct_arrTime > getLatestOperationStart(nextAct)){ - activityInsertionCosts = Double.MAX_VALUE; + return Double.MAX_VALUE; } - else{ - activityInsertionCosts = totalCosts - costWithoutNewJob; - } - return activityInsertionCosts; + return totalCosts - costWithoutNewJob; + } private double getLatestOperationStart(TourActivity act) { - if(state(act) != null){ - return state(act).getLatestOperationStart(); + if(act instanceof End) { + return end.getTheoreticalLatestOperationStartTime(); } - return act.getTheoreticalLatestOperationStartTime(); + return states.getActivityState(act, StateTypes.LATEST_OPERATION_START_TIME).toDouble(); + } } diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionConsideringFixCost.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionConsideringFixCost.java index d763a3b7..dd078540 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionConsideringFixCost.java +++ b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionConsideringFixCost.java @@ -23,6 +23,8 @@ package algorithms; import org.apache.log4j.Logger; import algorithms.InsertionData.NoInsertionFound; +import algorithms.StatesContainer.State; +import algorithms.StatesContainer.States; import basics.Job; import basics.route.Driver; import basics.route.Vehicle; @@ -41,12 +43,12 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion private double solution_completeness_ratio = 0.5; - private RouteStates routeStates; + private StatesContainer states; - public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, RouteStates routeStates) { + public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, StatesContainer activityStates2) { super(); this.standardServiceInsertion = standardInsertionCalculator; - this.routeStates = routeStates; + this.states = activityStates2; logger.info("inialise " + this); } @@ -84,7 +86,7 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion } private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) { - double load = routeStates.getRouteState(route).getLoad() + job.getCapacityDemand(); + double load = getCurrentLoad(route) + job.getCapacityDemand(); double currentFix = 0.0; if(route.getVehicle() != null){ if(!(route.getVehicle() instanceof NoVehicle)){ @@ -98,7 +100,7 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion } private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job) { - int currentLoad = routeStates.getRouteState(route).getLoad(); + int currentLoad = getCurrentLoad(route); double load = currentLoad + job.getCapacityDemand(); double currentRelFix = 0.0; if(route.getVehicle() != null){ @@ -113,4 +115,8 @@ final class CalculatesServiceInsertionConsideringFixCost implements JobInsertion return relativeFixCost; } + private int getCurrentLoad(VehicleRoute route) { + return (int) states.getRouteState(route, StateTypes.LOAD).toDouble(); + } + } diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionOnRouteLevel.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionOnRouteLevel.java index 366d5885..3b03dabf 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionOnRouteLevel.java +++ b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionOnRouteLevel.java @@ -31,6 +31,7 @@ import basics.costs.VehicleRoutingActivityCosts; import basics.costs.VehicleRoutingTransportCosts; import basics.route.Driver; import basics.route.End; +import basics.route.ServiceActivity; import basics.route.Start; import basics.route.TourActivities; import basics.route.TourActivity; @@ -50,7 +51,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul private AuxilliaryCostCalculator auxilliaryPathCostCalculator; - private RouteStates routeStates; + private StatesContainer states; private int nuOfActsForwardLooking = 0; @@ -89,14 +90,9 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul logger.info("initialise " + this); } - public void setActivityStates(RouteStates actStates){ - this.routeStates = actStates; + public void setActivityStates(StatesContainer activityStates2){ + this.states = activityStates2; } - - public ActivityState state(TourActivity act){ - return routeStates.getState(act); - } - void setNuOfActsForwardLooking(int nOfActsForwardLooking) { this.nuOfActsForwardLooking = nOfActsForwardLooking; @@ -138,14 +134,14 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul /** * pre-check whether vehicle-capacity of new vehicle is sufficient to load service. */ - if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){ + if(states.getRouteState(currentRoute, StateTypes.LOAD).toDouble() + service.getCapacityDemand() > newVehicle.getCapacity()){ return InsertionData.noInsertionFound(); } /** * some inis */ - TourActivity serviceAct2Insert = routeStates.getActivity(service, true); + TourActivity serviceAct2Insert = ServiceActivity.newInstance(service); int best_insertion_index = InsertionData.NO_INDEX; initialiseStartAndEnd(newVehicle, newVehicleDepartureTime); @@ -262,7 +258,7 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul /** * compute cost-diff of tour with and without new activity --> insertion_costs */ - double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - routeStates.getRouteState(currentRoute).getCosts(); + double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - states.getRouteState(currentRoute,StateTypes.COSTS).toDouble(); /** * if better than best known, make it the best known @@ -307,9 +303,9 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul private double pathCost_oldVehicle(VehicleRoute vehicleRoute, List path) { TourActivity act = path.get(path.size()-1); if(act instanceof End){ - return routeStates.getRouteState(vehicleRoute).getCosts(); + return states.getRouteState(vehicleRoute,StateTypes.COSTS).toDouble(); } - return state(act).getCurrentCost(); + return states.getActivityState(act,StateTypes.COSTS).toDouble(); } /** diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTriangleInequality.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTriangleInequality.java new file mode 100644 index 00000000..65377f39 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionWithTriangleInequality.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2011 Stefan Schroeder. + * eMail: stefan.schroeder@kit.edu + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * Stefan Schroeder - initial API and implementation + ******************************************************************************/ +package algorithms; + +import org.apache.log4j.Logger; + +import util.Neighborhood; + +import algorithms.RouteStates.ActivityState; +import algorithms.StatesContainer.State; +import algorithms.StatesContainer.States; +import basics.Job; +import basics.Service; +import basics.costs.VehicleRoutingActivityCosts; +import basics.costs.VehicleRoutingTransportCosts; +import basics.route.Driver; +import basics.route.End; +import basics.route.ServiceActivity; +import basics.route.Start; +import basics.route.TourActivities; +import basics.route.TourActivity; +import basics.route.Vehicle; +import basics.route.VehicleRoute; +import basics.route.VehicleImpl.NoVehicle; + + + +final class CalculatesServiceInsertionWithTriangleInequality implements JobInsertionCalculator{ + + class Marginals { + private double marginalCosts; + private double marginalTime; + public Marginals(double marginalCosts, double marginalTime) { + super(); + this.marginalCosts = marginalCosts; + this.marginalTime = marginalTime; + } + /** + * @return the marginalCosts + */ + public double getMarginalCosts() { + return marginalCosts; + } + /** + * @return the marginalTime + */ + public double getMarginalTime() { + return marginalTime; + } + + } + + private static final Logger logger = Logger.getLogger(CalculatesServiceInsertionWithTriangleInequality.class); + + private StatesContainer routeStates; + + private VehicleRoutingTransportCosts routingCosts; + + private Start start; + + private End end; + + private HardConstraint hardConstraint = new HardConstraint() { + + @Override + public boolean fulfilled() { return true; } + }; + + public void setHardConstraint(HardConstraint hardConstraint){ + this.hardConstraint = hardConstraint; + } + + private Neighborhood neighborhood = new Neighborhood() { + + @Override + public boolean areNeighbors(String location1, String location2) { + return true; + } + }; + + + + public void setNeighborhood(Neighborhood neighborhood) { + this.neighborhood = neighborhood; + logger.info("initialise neighborhood " + neighborhood); + } + + public void setActivityStates(StatesContainer activityStates2){ + this.routeStates = activityStates2; + } + + public CalculatesServiceInsertionWithTriangleInequality(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) { + super(); + this.routingCosts = vehicleRoutingTransportCosts; + logger.info("initialise " + this); + } + + @Override + public String toString() { + return "[name=calculatesServiceInsertion]"; + } + + /** + * Calculates the marginal cost of inserting job i locally. This is based on the + * assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1. + * + */ + @Override + public InsertionData calculate(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) { + if(jobToInsert == null) throw new IllegalStateException("jobToInsert is missing."); + if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("newVehicle is missing."); + + TourActivities tour = currentRoute.getTourActivities(); + Marginals bestMarginals = new Marginals(bestKnownCosts,Double.MAX_VALUE); + Service service = (Service)jobToInsert; + + if(getCurrentLoad(currentRoute) + service.getCapacityDemand() > newVehicle.getCapacity()){ + return InsertionData.noInsertionFound(); + } + int insertionIndex = InsertionData.NO_INDEX; + + TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service); + + initialiseStartAndEnd(newVehicle, newVehicleDepartureTime); + + TourActivity prevAct = start; + int actIndex = 0; + for(TourActivity nextAct : tour.getActivities()){ + if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ + Marginals mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle); + if(mc.getMarginalCosts() < bestMarginals.getMarginalCosts()){ + bestMarginals = mc; + insertionIndex = actIndex; + } + } + prevAct = nextAct; + actIndex++; + } + End nextAct = end; + if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ + Marginals mc = calculate(prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle); + if(mc.getMarginalCosts() < bestMarginals.getMarginalCosts()){ + bestMarginals = mc; + insertionIndex = actIndex; + } + } + + if(insertionIndex == InsertionData.NO_INDEX) { + return InsertionData.noInsertionFound(); + } + InsertionData insertionData = new InsertionData(bestMarginals.getMarginalCosts(), InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver); + insertionData.setVehicleDepartureTime(newVehicleDepartureTime); + insertionData.setAdditionalTime(bestMarginals.getMarginalTime()); + return insertionData; + } + + private int getCurrentLoad(VehicleRoute currentRoute) { + States thisRoutesStates = routeStates.getRouteStates().get(currentRoute); + if(routeStates.getRouteStates().containsKey(currentRoute)){ + int load = (int) thisRoutesStates.getState(StateTypes.LOAD).toDouble(); + return load; + } + else return 0; + } + + private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) { + if(start == null){ + start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival()); + start.setEndTime(newVehicleDepartureTime); + } + else{ + start.setLocationId(newVehicle.getLocationId()); + start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture()); + start.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival()); + start.setEndTime(newVehicleDepartureTime); + } + + if(end == null){ + end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival()); + } + else{ + end.setLocationId(newVehicle.getLocationId()); + end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime); + end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival()); + } + } + + public Marginals calculate(TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle) { + + double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle); + double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), prevAct.getEndTime(), driver, vehicle); + + double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle); + double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle); + + double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle); + double tp_time_prevAct_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), 0.0, driver, vehicle); + + return new Marginals(tp_costs_prevAct_newAct + tp_costs_newAct_nextAct - tp_costs_prevAct_nextAct, tp_time_prevAct_newAct + tp_time_newAct_nextAct - tp_time_prevAct_nextAct); + } +} diff --git a/jsprit-core/src/main/java/algorithms/CalculatesVehTypeDepServiceInsertion.java b/jsprit-core/src/main/java/algorithms/CalculatesVehTypeDepServiceInsertion.java index 369a359d..264ee753 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatesVehTypeDepServiceInsertion.java +++ b/jsprit-core/src/main/java/algorithms/CalculatesVehTypeDepServiceInsertion.java @@ -67,16 +67,7 @@ final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculat else{ relevantVehicles.addAll(fleetManager.getAvailableVehicles()); } -// -// for(TypeKey typeKey : fleetManager.getAvailableVehicleTypes()){ -// if(!(currentRoute.getVehicle() instanceof NoVehicle)){ -// TypeKey key = makeTypeKey(currentRoute.getVehicle().getType(),currentRoute.getVehicle().getLocationId()); -// if(typeKey.equals(key)){ -// continue; -// } -// } -// relevantVehicles.add(fleetManager.getEmptyVehicle(typeKey)); -// } + for(Vehicle v : relevantVehicles){ double depTime = v.getEarliestDeparture(); InsertionData iData = insertionCalculator.calculate(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_); @@ -92,8 +83,4 @@ final class CalculatesVehTypeDepServiceInsertion implements JobInsertionCalculat return bestIData; } -// private TypeKey makeTypeKey(VehicleType type, String locationId) { -// return new TypeKey(type,locationId); -// } - } diff --git a/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java b/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java index ec278889..346f2c8a 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java +++ b/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java @@ -70,7 +70,7 @@ class CalculatorBuilder { private VehicleRoutingProblem vrp; - private RouteStates activityStates; + private StatesContainer states; private boolean local = true; @@ -107,12 +107,12 @@ class CalculatorBuilder { /** * Sets activityStates. MUST be set. + * @param states TODO * - * @param activityStates * @return */ - public CalculatorBuilder setActivityStates(RouteStates activityStates){ - this.activityStates = activityStates; + public CalculatorBuilder setStates(StatesContainer states){ + this.states = states; return this; } @@ -184,21 +184,21 @@ class CalculatorBuilder { */ public JobInsertionCalculator build(){ if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))"); - if(activityStates == null) throw new IllegalStateException("activity states is null, but is must be set (this.setActivityStates(states))"); + if(states == null) throw new IllegalStateException("states is null, but is must be set (this.setStates(states))"); if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))"); JobInsertionCalculator baseCalculator = null; CalculatorPlusListeners standardLocal = null; if(local){ - standardLocal = createStandardLocal(vrp, activityStates); + standardLocal = createStandardLocal(vrp, states); } else{ - standardLocal = createStandardRoute(vrp, activityStates,forwardLooking,memory); + standardLocal = createStandardRoute(vrp, states,forwardLooking,memory); } baseCalculator = standardLocal.getCalculator(); addAlgorithmListeners(standardLocal.getAlgorithmListener()); addInsertionListeners(standardLocal.getInsertionListener()); if(considerFixedCost){ - CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, activityStates, weightOfFixedCost); + CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost); baseCalculator = withFixed.getCalculator(); addAlgorithmListeners(withFixed.getAlgorithmListener()); addInsertionListeners(withFixed.getInsertionListener()); @@ -206,7 +206,7 @@ class CalculatorBuilder { if(timeScheduling){ baseCalculator = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator,timeSlice,neighbors); } - return createFinalInsertion(fleetManager, baseCalculator, activityStates); + return createFinalInsertion(fleetManager, baseCalculator, states); } private void addInsertionListeners(List list) { @@ -221,35 +221,39 @@ class CalculatorBuilder { } } - private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, RouteStates activityStates){ + private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StatesContainer activityStates2){ JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), vrp.getActivityCosts()); - ((CalculatesServiceInsertion) standardServiceInsertion).setActivityStates(activityStates); +// JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertionWithTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts()); +// ((CalculatesServiceInsertionWithTriangleInequality) standardServiceInsertion).setActivityStates(activityStates2); +// ((CalculatesServiceInsertionWithTriangleInequality) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood()); +// + ((CalculatesServiceInsertion) standardServiceInsertion).setActivityStates(activityStates2); ((CalculatesServiceInsertion) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood()); CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion); return calcPlusListeners; } - private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCalculator baseCalculator, RouteStates activityStates, double weightOfFixedCosts){ - final CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(baseCalculator, activityStates); + private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCalculator baseCalculator, StatesContainer activityStates2, double weightOfFixedCosts){ + final CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(baseCalculator, activityStates2); withFixCost.setWeightOfFixCost(weightOfFixedCosts); CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost); calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost)); return calcPlusListeners; } - private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, RouteStates activityStates, int forwardLooking, int solutionMemory){ + private CalculatorPlusListeners createStandardRoute(VehicleRoutingProblem vrp, StatesContainer activityStates2, int forwardLooking, int solutionMemory){ int after = forwardLooking; JobInsertionCalculator jobInsertionCalculator = new CalculatesServiceInsertionOnRouteLevel(vrp.getTransportCosts(), vrp.getActivityCosts()); ((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNuOfActsForwardLooking(after); ((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setMemorySize(solutionMemory); ((CalculatesServiceInsertionOnRouteLevel)jobInsertionCalculator).setNeighborhood(vrp.getNeighborhood()); - ((CalculatesServiceInsertionOnRouteLevel) jobInsertionCalculator).setActivityStates(activityStates); + ((CalculatesServiceInsertionOnRouteLevel) jobInsertionCalculator).setActivityStates(activityStates2); CalculatorPlusListeners calcPlusListener = new CalculatorPlusListeners(jobInsertionCalculator); return calcPlusListener; } - private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, RouteStates routeStates){ + private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, StatesContainer activityStates2){ return new CalculatesVehTypeDepServiceInsertion(fleetManager, baseCalc); } diff --git a/jsprit-core/src/main/java/algorithms/ConfigureFixCostCalculator.java b/jsprit-core/src/main/java/algorithms/ConfigureFixCostCalculator.java index 650cbedf..08759adf 100644 --- a/jsprit-core/src/main/java/algorithms/ConfigureFixCostCalculator.java +++ b/jsprit-core/src/main/java/algorithms/ConfigureFixCostCalculator.java @@ -65,7 +65,7 @@ final class ConfigureFixCostCalculator implements InsertionStartsListener, JobIn } @Override - public void informJobInserted(Job job2insert, VehicleRoute inRoute) { + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { nuOfJobsToRecreate--; double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size())); calcConsideringFix.setSolutionCompletenessRatio(completenessRatio); diff --git a/jsprit-core/src/main/java/algorithms/FindCheaperVehicleAlgo.java b/jsprit-core/src/main/java/algorithms/FindCheaperVehicleAlgo.java index a154edd5..680a2525 100644 --- a/jsprit-core/src/main/java/algorithms/FindCheaperVehicleAlgo.java +++ b/jsprit-core/src/main/java/algorithms/FindCheaperVehicleAlgo.java @@ -106,7 +106,7 @@ final class FindCheaperVehicleAlgo { throw new IllegalStateException(e); } TourActivities newTour = TourActivities.copyOf(vehicleRoute.getTourActivities()); - tourStateCalculator.updateRoute(vehicleRoute); + tourStateCalculator.iterate(vehicleRoute); return VehicleRoute.newInstance(newTour,vehicleRoute.getDriver(),bestVehicle); } return vehicleRoute; diff --git a/jsprit-core/src/main/java/algorithms/ForwardInTimeListeners.java b/jsprit-core/src/main/java/algorithms/ForwardInTimeListeners.java new file mode 100644 index 00000000..1f5151b3 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/ForwardInTimeListeners.java @@ -0,0 +1,39 @@ +package algorithms; + +import java.util.ArrayList; +import java.util.Collection; + +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class ForwardInTimeListeners { + + interface ForwardInTimeListener{ + + public void start(VehicleRoute route); + + public void nextActivity(TourActivity act, double arrTime,double endTime); + + public void finnish(); + + } + + private Collection listeners = new ArrayList(); + + public void addListener(ForwardInTimeListener l){ + listeners.add(l); + } + + public void start(VehicleRoute route){ + for(ForwardInTimeListener l : listeners){ l.start(route); } + } + + public void nextActivity(TourActivity act, double arrTime, double endTime){ + for(ForwardInTimeListener l : listeners){ l.nextActivity(act,arrTime,endTime); } + } + + public void finnish(){ + for(ForwardInTimeListener l : listeners){ l.finnish(); } + } + +} diff --git a/jsprit-core/src/main/java/algorithms/HardConstraint.java b/jsprit-core/src/main/java/algorithms/HardConstraint.java new file mode 100644 index 00000000..1b754ec4 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/HardConstraint.java @@ -0,0 +1,7 @@ +package algorithms; + +interface HardConstraint { + + public boolean fulfilled(); + +} diff --git a/jsprit-core/src/main/java/algorithms/Inserter.java b/jsprit-core/src/main/java/algorithms/Inserter.java index 4a322790..24845c01 100644 --- a/jsprit-core/src/main/java/algorithms/Inserter.java +++ b/jsprit-core/src/main/java/algorithms/Inserter.java @@ -30,7 +30,7 @@ class Inserter { } else throw new IllegalStateException("neither service nor shipment. this is not supported."); - insertionListeners.informJobInserted(job, vehicleRoute); + insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime()); // updateTour(vehicleRoute); } } diff --git a/jsprit-core/src/main/java/algorithms/InsertionData.java b/jsprit-core/src/main/java/algorithms/InsertionData.java index ddd6507f..462b1f13 100644 --- a/jsprit-core/src/main/java/algorithms/InsertionData.java +++ b/jsprit-core/src/main/java/algorithms/InsertionData.java @@ -55,6 +55,22 @@ class InsertionData { private double departureTime; + private double additionalTime; + + /** + * @return the additionalTime + */ + public double getAdditionalTime() { + return additionalTime; + } + + /** + * @param additionalTime the additionalTime to set + */ + public void setAdditionalTime(double additionalTime) { + this.additionalTime = additionalTime; + } + public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver){ this.insertionCost = insertionCost; this.pickupInsertionIndex = pickupInsertionIndex; diff --git a/jsprit-core/src/main/java/algorithms/InsertionFactory.java b/jsprit-core/src/main/java/algorithms/InsertionFactory.java index 87ac2502..6d592423 100644 --- a/jsprit-core/src/main/java/algorithms/InsertionFactory.java +++ b/jsprit-core/src/main/java/algorithms/InsertionFactory.java @@ -38,7 +38,7 @@ class InsertionFactory { private static Logger log = Logger.getLogger(InsertionFactory.class); public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config, - VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads){ + VehicleFleetManager vehicleFleetManager, StatesContainerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads){ boolean concurrentInsertion = false; if(executorService != null) concurrentInsertion = true; if(config.containsKey("[@name]")){ @@ -51,7 +51,7 @@ class InsertionFactory { List algoListeners = new ArrayList(); CalculatorBuilder calcBuilder = new CalculatorBuilder(insertionListeners, algorithmListeners); - calcBuilder.setActivityStates(activityStates); + calcBuilder.setStates(routeStates); calcBuilder.setVehicleRoutingProblem(vrp); calcBuilder.setVehicleFleetManager(vehicleFleetManager); @@ -94,27 +94,22 @@ class InsertionFactory { } JobInsertionCalculator jic = calcBuilder.build(); - TourStateUpdater tourStateCalculator = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()); - RouteAlgorithm routeAlgorithm = RouteAlgorithmImpl.newInstance(jic, tourStateCalculator); -// routeAlgorithm.getListeners().add(new VehicleSwitched(vehicleFleetManager)); - ((RouteAlgorithmImpl) routeAlgorithm).setStates(activityStates); + if(insertionName.equals("bestInsertion")){ - if(concurrentInsertion){ - insertionStrategy = BestInsertionConcurrent.newInstance(routeAlgorithm,executorService,nuOfThreads); - } - else{ - insertionStrategy = new BestInsertion(jic); - } - } - else if(insertionName.equals("regretInsertion")){ - insertionStrategy = RegretInsertion.newInstance(routeAlgorithm); + insertionStrategy = new BestInsertion(jic); } +// else if(insertionName.equals("regretInsertion")){ +// insertionStrategy = RegretInsertion.newInstance(routeAlgorithm); +// } insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager)); insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager)); insertionStrategy.addListener(new VehicleSwitched(vehicleFleetManager)); - insertionStrategy.addListener(new UpdateRoute(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts())); + +// insertionStrategy.addListener(new UpdateLoadAtRouteLevel(routeStates)); + + insertionStrategy.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); for(InsertionListener l : insertionListeners) insertionStrategy.addListener(l); // insertionStrategy.addListener(new FindCheaperVehicle( // new FindCheaperVehicleAlgoNew(vehicleFleetManager, tourStateCalculator, auxCalculator))); diff --git a/jsprit-core/src/main/java/algorithms/InsertionListeners.java b/jsprit-core/src/main/java/algorithms/InsertionListeners.java index d35e5434..72183a1c 100644 --- a/jsprit-core/src/main/java/algorithms/InsertionListeners.java +++ b/jsprit-core/src/main/java/algorithms/InsertionListeners.java @@ -19,10 +19,10 @@ class InsertionListeners { return listeners; } - public void informJobInserted(Job insertedJob, VehicleRoute inRoute){ + public void informJobInserted(Job insertedJob, VehicleRoute inRoute, double additionalCosts, double additionalTime){ for(InsertionListener l : listeners){ if(l instanceof JobInsertedListener){ - ((JobInsertedListener)l).informJobInserted(insertedJob, inRoute); + ((JobInsertedListener)l).informJobInserted(insertedJob, inRoute, additionalCosts, additionalTime); } } } diff --git a/jsprit-core/src/main/java/algorithms/IterateRouteBackwardInTime.java b/jsprit-core/src/main/java/algorithms/IterateRouteBackwardInTime.java new file mode 100644 index 00000000..56622c5d --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/IterateRouteBackwardInTime.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2011 Stefan Schroeder. + * eMail: stefan.schroeder@kit.edu + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * Stefan Schroeder - initial API and implementation + ******************************************************************************/ +package algorithms; + +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import algorithms.BackwardInTimeListeners.BackwardInTimeListener; +import basics.costs.BackwardTransportTime; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + + +/** + * + * @author stefan schroeder + * + */ + +class IterateRouteBackwardInTime implements VehicleRouteUpdater{ + + private static Logger log = Logger.getLogger(IterateRouteBackwardInTime.class); + + private BackwardTransportTime transportTime; + + private BackwardInTimeListeners listeners; + + public IterateRouteBackwardInTime(BackwardTransportTime transportTime) { + super(); + this.transportTime = transportTime; + listeners = new BackwardInTimeListeners(); + } + + /* + * + */ + public void iterate(VehicleRoute vehicleRoute) { + listeners.start(vehicleRoute); + Iterator reverseActIter = vehicleRoute.getTourActivities().reverseActivityIterator(); + TourActivity prevAct; + prevAct = vehicleRoute.getEnd(); + double startAtPrevAct = prevAct.getTheoreticalLatestOperationStartTime(); + listeners.prevActivity(prevAct, startAtPrevAct, startAtPrevAct); + while(reverseActIter.hasNext()){ + TourActivity currAct = reverseActIter.next(); + double latestDepTimeAtCurrAct = startAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), startAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle()); + double potentialLatestOperationStartTimeAtCurrAct = latestDepTimeAtCurrAct - currAct.getOperationTime(); + double latestOperationStartTime = Math.min(currAct.getTheoreticalLatestOperationStartTime(), potentialLatestOperationStartTimeAtCurrAct); + listeners.prevActivity(currAct, latestDepTimeAtCurrAct, latestOperationStartTime); + prevAct = currAct; + startAtPrevAct = latestOperationStartTime; + } + listeners.finnish(); + } + + public void addListener(BackwardInTimeListener l){ listeners.addListener(l); } + +} diff --git a/jsprit-core/src/main/java/algorithms/IterateRouteForwardInTime.java b/jsprit-core/src/main/java/algorithms/IterateRouteForwardInTime.java new file mode 100644 index 00000000..a0521034 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/IterateRouteForwardInTime.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2011 Stefan Schroeder. + * eMail: stefan.schroeder@kit.edu + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * Stefan Schroeder - initial API and implementation + ******************************************************************************/ +package algorithms; + +import org.apache.log4j.Logger; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import basics.costs.ForwardTransportTime; +import basics.route.Driver; +import basics.route.End; +import basics.route.TourActivity; +import basics.route.Vehicle; +import basics.route.VehicleRoute; + + +/** + * + * @author sschroeder + * + */ + +class IterateRouteForwardInTime implements VehicleRouteUpdater{ + + private static Logger log = Logger.getLogger(IterateRouteForwardInTime.class); + + private ForwardTransportTime transportTime; + + private ForwardInTimeListeners listeners; + + public IterateRouteForwardInTime(ForwardTransportTime transportTime) { + super(); + this.transportTime = transportTime; + listeners = new ForwardInTimeListeners(); + } + + /** + * + * + */ + public void iterate(VehicleRoute vehicleRoute) { + listeners.start(vehicleRoute); + + Vehicle vehicle = vehicleRoute.getVehicle(); + Driver driver = vehicleRoute.getDriver(); + TourActivity prevAct = vehicleRoute.getStart(); + double startAtPrevAct = prevAct.getEndTime(); + + listeners.nextActivity(prevAct,startAtPrevAct,startAtPrevAct); + + for(TourActivity currentAct : vehicleRoute.getTourActivities().getActivities()){ + double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle); + double arrivalTimeAtCurrAct = startAtPrevAct + transportTime; + double operationStartTime = Math.max(currentAct.getTheoreticalEarliestOperationStartTime(), arrivalTimeAtCurrAct); + double operationEndTime = operationStartTime + currentAct.getOperationTime(); + + listeners.nextActivity(currentAct,arrivalTimeAtCurrAct,operationEndTime); + + prevAct = currentAct; + startAtPrevAct = operationEndTime; + } + + End currentAct = vehicleRoute.getEnd(); + double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle); + double arrivalTimeAtCurrAct = startAtPrevAct + transportTime; + + listeners.nextActivity(currentAct,arrivalTimeAtCurrAct,arrivalTimeAtCurrAct); + listeners.finnish(); + + } + + public void addListener(ForwardInTimeListener l){ + listeners.addListener(l); + } + +} diff --git a/jsprit-core/src/main/java/algorithms/JobObserver.java b/jsprit-core/src/main/java/algorithms/JobObserver.java index f45f1799..0643bb36 100644 --- a/jsprit-core/src/main/java/algorithms/JobObserver.java +++ b/jsprit-core/src/main/java/algorithms/JobObserver.java @@ -76,7 +76,7 @@ class JobObserver implements JobInsertedListener, BeforeJobInsertionListener, Al Collection infos = new ArrayList(); @Override - public void informJobInserted(Job job2insert, VehicleRoute inRoute) { + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { if(job2insert instanceof Service){ if(((Service) job2insert).getLocationId().equals(locationId)){ double actualMC = inRoute.getCost()-routeCostBefore; diff --git a/jsprit-core/src/main/java/algorithms/RegretInsertion.java b/jsprit-core/src/main/java/algorithms/RegretInsertion.java index d6eee459..fd8806d7 100644 --- a/jsprit-core/src/main/java/algorithms/RegretInsertion.java +++ b/jsprit-core/src/main/java/algorithms/RegretInsertion.java @@ -1,229 +1,229 @@ -/******************************************************************************* - * Copyright (c) 2011 Stefan Schroeder. - * eMail: stefan.schroeder@kit.edu - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * Contributors: - * Stefan Schroeder - initial API and implementation - ******************************************************************************/ -package algorithms; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.apache.log4j.Logger; - -import algorithms.InsertionData.NoInsertionFound; -import basics.Job; -import basics.Service; -import basics.algo.InsertionListener; -import basics.route.VehicleRoute; - - -/** - * Insertion based an regret approach. - * - *

Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference - * between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction. - * The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this - * customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later. - * - * @author stefan schroeder - * - */ -final class RegretInsertion implements InsertionStrategy{ - - /** - * Scorer to include other impacts on score such as time-window length or distance to depot. - * - * @author schroeder - * - */ - static interface ScoringFunction { - - public double score(Job job); - - } - - /** - * Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score. - * - *

This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job) - * - * @author schroeder - * - */ - static class TimeWindowScorer implements ScoringFunction { - - private double tw_scoringParam = - 0.1; - - @Override - public double score(Job job) { - double twStart = 0.0; - double twEnd = 0.0; -// if(job instanceof Shipment){ -// twStart = ((Shipment) job).getDeliveryTW().getStart(); -// twEnd = ((Shipment) job).getDeliveryTW().getEnd(); +///******************************************************************************* +// * Copyright (c) 2011 Stefan Schroeder. +// * eMail: stefan.schroeder@kit.edu +// * +// * All rights reserved. This program and the accompanying materials +// * are made available under the terms of the GNU Public License v2.0 +// * which accompanies this distribution, and is available at +// * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html +// * +// * Contributors: +// * Stefan Schroeder - initial API and implementation +// ******************************************************************************/ +//package algorithms; +// +//import java.util.ArrayList; +//import java.util.Collection; +//import java.util.List; +// +//import org.apache.log4j.Logger; +// +//import algorithms.InsertionData.NoInsertionFound; +//import basics.Job; +//import basics.Service; +//import basics.algo.InsertionListener; +//import basics.route.VehicleRoute; +// +// +///** +// * Insertion based an regret approach. +// * +// *

Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference +// * between secondBest and firstBest, plus additional scoring variables that can defined in this.ScoringFunction. +// * The idea is that if the cost of the secondBest alternative is way higher than the first best, it seems to be important to insert this +// * customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later. +// * +// * @author stefan schroeder +// * +// */ +//final class RegretInsertion implements InsertionStrategy{ +// +// /** +// * Scorer to include other impacts on score such as time-window length or distance to depot. +// * +// * @author schroeder +// * +// */ +// static interface ScoringFunction { +// +// public double score(Job job); +// +// } +// +// /** +// * Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score. +// * +// *

This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job) +// * +// * @author schroeder +// * +// */ +// static class TimeWindowScorer implements ScoringFunction { +// +// private double tw_scoringParam = - 0.1; +// +// @Override +// public double score(Job job) { +// double twStart = 0.0; +// double twEnd = 0.0; +//// if(job instanceof Shipment){ +//// twStart = ((Shipment) job).getDeliveryTW().getStart(); +//// twEnd = ((Shipment) job).getDeliveryTW().getEnd(); +//// } +//// else +// if(job instanceof Service){ +// twStart = ((Service) job).getTimeWindow().getStart(); +// twEnd = ((Service) job).getTimeWindow().getEnd(); // } -// else - if(job instanceof Service){ - twStart = ((Service) job).getTimeWindow().getStart(); - twEnd = ((Service) job).getTimeWindow().getEnd(); - } - return (twEnd-twStart)*tw_scoringParam; - } - - @Override - public String toString() { - return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]"; - } - - } - - public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) { - return new RegretInsertion(routeAlgorithm); - } - - private Logger logger = Logger.getLogger(RegretInsertion.class); - - private RouteAlgorithm routeAlgorithm; - - private ScoringFunction scoringFunction = new TimeWindowScorer(); - - /** - * Sets the scoring function. - * - *

By default, the this.TimeWindowScorer is used. - * - * @param scoringFunction - */ - public void setScoringFunction(ScoringFunction scoringFunction) { - this.scoringFunction = scoringFunction; - } - - public RegretInsertion(RouteAlgorithm routeAlgorithm) { - super(); - this.routeAlgorithm = routeAlgorithm; - logger.info("initialise " + this); - } - - @Override - public String toString() { - return "[name=regretInsertion][additionalScorer="+scoringFunction+"]"; - } - - public RouteAlgorithm getRouteAlgorithm(){ - return routeAlgorithm; - } - - /** - * Runs insertion. - * - *

Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables. - * - */ - @Override - public void insertJobs(Collection routes, Collection unassignedJobs) { - List jobs = new ArrayList(unassignedJobs); -// informInsertionStarts(routes,unassignedJobs); - int inserted = 0; - while(!jobs.isEmpty()){ - List unassignedJobList = new ArrayList(jobs); - ScoredJob bestScoredJob = null; - double bestScore = -1*Double.MAX_VALUE; - VehicleRoute insertIn = null; - - for(Job unassignedJob : unassignedJobList){ - InsertionData best = null; - InsertionData secondBest = null; - VehicleRoute bestRoute = null; - - double benchmark = Double.MAX_VALUE; - for(VehicleRoute route : routes){ - if(secondBest != null){ - benchmark = secondBest.getInsertionCost(); - } - InsertionData iData = routeAlgorithm.calculateBestInsertion(route, unassignedJob, benchmark); - if(iData instanceof NoInsertionFound) continue; - if(best == null){ - best = iData; - bestRoute = route; - } - else if(iData.getInsertionCost() < best.getInsertionCost()){ - secondBest = best; - best = iData; - bestRoute = route; - } - else if(secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())){ - secondBest = iData; - } - } - if(best == null){ - break; - } - double score = score(unassignedJob,best,secondBest); - if(score > bestScore){ - bestScoredJob = new ScoredJob(unassignedJob,score,best,bestRoute); - bestScore = score; - } - } - Job assignedJob; - if(bestScoredJob == null){ - Job job = unassignedJobList.get(0); - VehicleRoute newRoute = VehicleRoute.emptyRoute(); - InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE); - if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution"); - insertIn=newRoute; - assignedJob=job; - routeAlgorithm.insertJob(job,bestI,newRoute); - routes.add(newRoute); - jobs.remove(job); - - } - else{ - routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); - insertIn=bestScoredJob.getRoute(); - assignedJob=bestScoredJob.getJob(); - jobs.remove(bestScoredJob.getJob()); - } - inserted++; -// informJobInserted(assignedJob, insertIn); - - } - } - - private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) { - if(best == null){ - throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); - } - if(secondBest == null){ - return Double.MAX_VALUE; - } - return (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(unassignedJob); - - } - - @Override - public void removeListener(InsertionListener insertionListener) { - // TODO Auto-generated method stub - - } - - @Override - public Collection getListeners() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void addListener(InsertionListener insertionListener) { - // TODO Auto-generated method stub - - } - -} +// return (twEnd-twStart)*tw_scoringParam; +// } +// +// @Override +// public String toString() { +// return "[name=timeWindowScorer][scoringParam="+tw_scoringParam+"]"; +// } +// +// } +// +// public static RegretInsertion newInstance(RouteAlgorithm routeAlgorithm) { +// return new RegretInsertion(routeAlgorithm); +// } +// +// private Logger logger = Logger.getLogger(RegretInsertion.class); +// +// private RouteAlgorithm routeAlgorithm; +// +// private ScoringFunction scoringFunction = new TimeWindowScorer(); +// +// /** +// * Sets the scoring function. +// * +// *

By default, the this.TimeWindowScorer is used. +// * +// * @param scoringFunction +// */ +// public void setScoringFunction(ScoringFunction scoringFunction) { +// this.scoringFunction = scoringFunction; +// } +// +// public RegretInsertion(RouteAlgorithm routeAlgorithm) { +// super(); +// this.routeAlgorithm = routeAlgorithm; +// logger.info("initialise " + this); +// } +// +// @Override +// public String toString() { +// return "[name=regretInsertion][additionalScorer="+scoringFunction+"]"; +// } +// +// public RouteAlgorithm getRouteAlgorithm(){ +// return routeAlgorithm; +// } +// +// /** +// * Runs insertion. +// * +// *

Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables. +// * +// */ +// @Override +// public void insertJobs(Collection routes, Collection unassignedJobs) { +// List jobs = new ArrayList(unassignedJobs); +//// informInsertionStarts(routes,unassignedJobs); +// int inserted = 0; +// while(!jobs.isEmpty()){ +// List unassignedJobList = new ArrayList(jobs); +// ScoredJob bestScoredJob = null; +// double bestScore = -1*Double.MAX_VALUE; +// VehicleRoute insertIn = null; +// +// for(Job unassignedJob : unassignedJobList){ +// InsertionData best = null; +// InsertionData secondBest = null; +// VehicleRoute bestRoute = null; +// +// double benchmark = Double.MAX_VALUE; +// for(VehicleRoute route : routes){ +// if(secondBest != null){ +// benchmark = secondBest.getInsertionCost(); +// } +// InsertionData iData = routeAlgorithm.calculateBestInsertion(route, unassignedJob, benchmark); +// if(iData instanceof NoInsertionFound) continue; +// if(best == null){ +// best = iData; +// bestRoute = route; +// } +// else if(iData.getInsertionCost() < best.getInsertionCost()){ +// secondBest = best; +// best = iData; +// bestRoute = route; +// } +// else if(secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())){ +// secondBest = iData; +// } +// } +// if(best == null){ +// break; +// } +// double score = score(unassignedJob,best,secondBest); +// if(score > bestScore){ +// bestScoredJob = new ScoredJob(unassignedJob,score,best,bestRoute); +// bestScore = score; +// } +// } +// Job assignedJob; +// if(bestScoredJob == null){ +// Job job = unassignedJobList.get(0); +// VehicleRoute newRoute = VehicleRoute.emptyRoute(); +// InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, job, Double.MAX_VALUE); +// if(bestI instanceof InsertionData.NoInsertionFound) throw new IllegalStateException("given the vehicles, could not create a valid solution"); +// insertIn=newRoute; +// assignedJob=job; +// routeAlgorithm.insertJob(job,bestI,newRoute); +// routes.add(newRoute); +// jobs.remove(job); +// +// } +// else{ +// routeAlgorithm.insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); +// insertIn=bestScoredJob.getRoute(); +// assignedJob=bestScoredJob.getJob(); +// jobs.remove(bestScoredJob.getJob()); +// } +// inserted++; +//// informJobInserted(assignedJob, insertIn); +// +// } +// } +// +// private double score(Job unassignedJob, InsertionData best, InsertionData secondBest) { +// if(best == null){ +// throw new IllegalStateException("cannot insert job " + unassignedJob.getId()); +// } +// if(secondBest == null){ +// return Double.MAX_VALUE; +// } +// return (secondBest.getInsertionCost()-best.getInsertionCost()) + scoringFunction.score(unassignedJob); +// +// } +// +// @Override +// public void removeListener(InsertionListener insertionListener) { +// // TODO Auto-generated method stub +// +// } +// +// @Override +// public Collection getListeners() { +// // TODO Auto-generated method stub +// return null; +// } +// +// @Override +// public void addListener(InsertionListener insertionListener) { +// // TODO Auto-generated method stub +// +// } +// +//} diff --git a/jsprit-core/src/main/java/algorithms/StateTypes.java b/jsprit-core/src/main/java/algorithms/StateTypes.java index 21bdde4e..2306281d 100644 --- a/jsprit-core/src/main/java/algorithms/StateTypes.java +++ b/jsprit-core/src/main/java/algorithms/StateTypes.java @@ -3,5 +3,11 @@ package algorithms; class StateTypes { final static String LOAD = "load"; - final static String DURATION = "duration"; + final static String DURATION = "duration"; + + final static String LATEST_OPERATION_START_TIME = "latestOST"; + + final static String EARLIEST_OPERATION_START_TIME = "earliestOST"; + + public static final String COSTS = "costs"; } diff --git a/jsprit-core/src/main/java/algorithms/StatesContainer.java b/jsprit-core/src/main/java/algorithms/StatesContainer.java index 99a16897..9c312ff2 100644 --- a/jsprit-core/src/main/java/algorithms/StatesContainer.java +++ b/jsprit-core/src/main/java/algorithms/StatesContainer.java @@ -8,7 +8,7 @@ import basics.route.VehicleRoute; interface StatesContainer { interface State { - double getState(); + double toDouble(); } class StateImpl implements State{ @@ -20,7 +20,7 @@ interface StatesContainer { } @Override - public double getState() { + public double toDouble() { return state; } @@ -46,5 +46,9 @@ interface StatesContainer { Map getActivityStates(); // void put(TourActivity act, States states); + + State getActivityState(TourActivity act, String stateType); + + State getRouteState(VehicleRoute route, String stateType); } diff --git a/jsprit-core/src/main/java/algorithms/StatesContainerImpl.java b/jsprit-core/src/main/java/algorithms/StatesContainerImpl.java index b54e939a..d09d7f87 100644 --- a/jsprit-core/src/main/java/algorithms/StatesContainerImpl.java +++ b/jsprit-core/src/main/java/algorithms/StatesContainerImpl.java @@ -7,9 +7,9 @@ import java.util.Map; import basics.route.TourActivity; import basics.route.VehicleRoute; -public class StatesContainerImpl implements StatesContainer{ +class StatesContainerImpl implements StatesContainer{ - class StatesImpl implements States{ + static class StatesImpl implements States{ private Map states = new HashMap(); @@ -24,26 +24,100 @@ public class StatesContainerImpl implements StatesContainer{ } - private Map vehicleRoutes = new HashMap(); + private Map vehicleRouteStates = new HashMap(); - private Map tourActivities = new HashMap(); + private Map activityStates = new HashMap(); @Override public Map getRouteStates() { - return Collections.unmodifiableMap(vehicleRoutes); + return Collections.unmodifiableMap(vehicleRouteStates); + } + + public States getRouteStates(VehicleRoute route){ + return vehicleRouteStates.get(route); } public void put(VehicleRoute route, States states) { - vehicleRoutes.put(route, states); + vehicleRouteStates.put(route, states); } @Override public Map getActivityStates() { - return Collections.unmodifiableMap(tourActivities); + return Collections.unmodifiableMap(activityStates); } - public void put(TourActivity act, States states) { - tourActivities.put(act, states); + public States getActivityStates(TourActivity act){ + return activityStates.get(act); } + + public void put(TourActivity act, States states) { + activityStates.put(act, states); + } + + public void clear(){ + vehicleRouteStates.clear(); + activityStates.clear(); + } + + @Override + public State getActivityState(TourActivity act, String stateType) { + if(!activityStates.containsKey(act)){ + return getDefaultActState(stateType,act); + } + StatesImpl actStates = (StatesImpl) activityStates.get(act); + State state = actStates.getState(stateType); + if(state == null){ + return getDefaultActState(stateType,act); + } + return state; + } + + public void putActivityState(TourActivity act, String stateType, State state){ + if(!activityStates.containsKey(act)){ + activityStates.put(act, new StatesImpl()); + } + StatesImpl actStates = (StatesImpl) activityStates.get(act); + actStates.putState(stateType, state); + } + + + private State getDefaultActState(String stateType, TourActivity act){ + if(stateType.equals(StateTypes.LOAD)) return new StateImpl(0); + if(stateType.equals(StateTypes.COSTS)) return new StateImpl(0); + if(stateType.equals(StateTypes.DURATION)) return new StateImpl(0); + if(stateType.equals(StateTypes.EARLIEST_OPERATION_START_TIME)) return new StateImpl(act.getTheoreticalEarliestOperationStartTime()); + if(stateType.equals(StateTypes.LATEST_OPERATION_START_TIME)) return new StateImpl(act.getTheoreticalLatestOperationStartTime()); + return null; + } + + private State getDefaultRouteState(String stateType, VehicleRoute route){ + if(stateType.equals(StateTypes.LOAD)) return new StateImpl(0); + if(stateType.equals(StateTypes.COSTS)) return new StateImpl(0); + if(stateType.equals(StateTypes.DURATION)) return new StateImpl(0); + return null; + } + + @Override + public State getRouteState(VehicleRoute route, String stateType) { + if(!vehicleRouteStates.containsKey(route)){ + return getDefaultRouteState(stateType,route); + } + StatesImpl routeStates = (StatesImpl) vehicleRouteStates.get(route); + State state = routeStates.getState(stateType); + if(state == null){ + return getDefaultRouteState(stateType, route); + } + return state; + } + + public void putRouteState(VehicleRoute route, String stateType, State state){ + if(!vehicleRouteStates.containsKey(route)){ + vehicleRouteStates.put(route, new StatesImpl()); + } + StatesImpl routeStates = (StatesImpl) vehicleRouteStates.get(route); + routeStates.putState(stateType, state); + } + + } diff --git a/jsprit-core/src/main/java/algorithms/TourStateUpdater.java b/jsprit-core/src/main/java/algorithms/TourStateUpdater.java deleted file mode 100644 index b98e3896..00000000 --- a/jsprit-core/src/main/java/algorithms/TourStateUpdater.java +++ /dev/null @@ -1,91 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Stefan Schroeder. - * eMail: stefan.schroeder@kit.edu - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * Contributors: - * Stefan Schroeder - initial API and implementation - ******************************************************************************/ -package algorithms; - -import org.apache.log4j.Logger; - -import basics.costs.VehicleRoutingActivityCosts; -import basics.costs.VehicleRoutingTransportCosts; -import basics.route.VehicleRoute; - - - - - -/** - * Updates tour state, i.e. the tour as well as each activity in that tour has a state such as currentLoad, currentCost, earliestOperationTime and - * latestOperationTime. Each time the tour is changed (for instance by removing or adding an activity), tour and activity states - * might change, thus this updater updates activity states. - * This includes: - * - update load and totalCost at tour-level - * - update currentLoad and currentCost at activity-level - * - update earliest- and latestOperationStart values at activity-level - * - * If ensureFeasibility is true, then it additionally checks whether the earliestOperationStartTime is higher than the latestOperationStartTime. - * If it is, it returns a false value to indicate that the tour is not feasible. This makes only sense for hard-timewindows. - * - * If softTimeWindow is set to true, latestOperationStartTimes are not updated and the tour is always feasible. - * - * @author stefan schroeder - * - */ - -class TourStateUpdater implements VehicleRouteUpdater{ - -// public final static Counter counter = new Counter("#updateTWProcesses: "); - - private static Logger logger = Logger.getLogger(TourStateUpdater.class); - - private boolean ensureFeasibility = true; - - private UpdateTourStatesForwardInTime forwardUpdate; - - private UpdateTourStatesBackwardInTime backwardUpdate; - - private boolean updateTimeWindows = true; - - private RouteStates actStates; - - public TourStateUpdater(RouteStates activityStates, VehicleRoutingTransportCosts costs, VehicleRoutingActivityCosts costFunction) { - super(); - forwardUpdate = new UpdateTourStatesForwardInTime(costs, costs, costFunction); - backwardUpdate = new UpdateTourStatesBackwardInTime(costs); - actStates=activityStates; - forwardUpdate.setStates(actStates); - backwardUpdate.setStates(actStates); - } - - /* - * - */ - public boolean updateRoute(VehicleRoute vehicleRoute) { - if(updateTimeWindows){ - backwardUpdate.checkFeasibility = ensureFeasibility; - backwardUpdate.updateRoute(vehicleRoute); - } - forwardUpdate.updateRoute(vehicleRoute); - boolean tourIsFeasible = true; - - return tourIsFeasible; - } - - public void setTimeWindowUpdate(boolean updateTimeWindows) { - this.updateTimeWindows = updateTimeWindows; - logger.info("set timeWindowUpdate to " + updateTimeWindows); - } - - public void setEnsureFeasibility(boolean ensureFeasibility) { - this.ensureFeasibility = ensureFeasibility; - } - -} diff --git a/jsprit-core/src/main/java/algorithms/UdateCostsAtRouteLevel.java b/jsprit-core/src/main/java/algorithms/UdateCostsAtRouteLevel.java new file mode 100644 index 00000000..a82040b7 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UdateCostsAtRouteLevel.java @@ -0,0 +1,53 @@ +package algorithms; + +import java.util.Collection; + +import basics.Job; +import basics.algo.InsertionEndsListener; +import basics.algo.InsertionStartsListener; +import basics.algo.JobInsertedListener; +import basics.costs.VehicleRoutingActivityCosts; +import basics.costs.VehicleRoutingTransportCosts; +import basics.route.VehicleRoute; + +class UdateCostsAtRouteLevel implements JobInsertedListener, InsertionStartsListener, InsertionEndsListener{ + + private StatesContainerImpl states; + + private VehicleRoutingTransportCosts tpCosts; + + private VehicleRoutingActivityCosts actCosts; + + public UdateCostsAtRouteLevel(StatesContainerImpl states, VehicleRoutingTransportCosts tpCosts, VehicleRoutingActivityCosts actCosts) { + super(); + this.states = states; + this.tpCosts = tpCosts; + this.actCosts = actCosts; + } + + @Override + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { + inRoute.getVehicleRouteCostCalculator().addTransportCost(additionalCosts); + } + + @Override + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts); + forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states)); + for(VehicleRoute route : vehicleRoutes){ + forwardInTime.iterate(route); + } + + } + + @Override + public void informInsertionEnds(Collection vehicleRoutes) { + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts); + forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states)); + for(VehicleRoute route : vehicleRoutes){ + forwardInTime.iterate(route); + } + + } + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateActivityTimes.java b/jsprit-core/src/main/java/algorithms/UpdateActivityTimes.java new file mode 100644 index 00000000..41a5b251 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateActivityTimes.java @@ -0,0 +1,26 @@ +package algorithms; + +import org.apache.log4j.Logger; + +import basics.route.TourActivity; +import basics.route.VehicleRoute; +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; + +class UpdateActivityTimes implements ForwardInTimeListener{ + + private Logger log = Logger.getLogger(UpdateActivityTimes.class); + + @Override + public void start(VehicleRoute route) {} + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { +// log.debug(act.toString() + " arrTime="+ arrTime + " endTime=" + endTime); + act.setArrTime(arrTime); + act.setEndTime(endTime); + } + + @Override + public void finnish() {} + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java b/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java new file mode 100644 index 00000000..679a294d --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java @@ -0,0 +1,81 @@ +package algorithms; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import algorithms.StatesContainer.StateImpl; +import basics.costs.ForwardTransportCost; +import basics.costs.VehicleRoutingActivityCosts; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class UpdateCostsAtAllLevels implements ForwardInTimeListener{ + + private VehicleRoutingActivityCosts activityCost; + + private ForwardTransportCost transportCost; + + private StatesContainerImpl states; + + private double totalOperationCost = 0.0; + + private VehicleRoute vehicleRoute = null; + + private TourActivity prevAct = null; + + private double startTimeAtPrevAct = 0.0; + + public UpdateCostsAtAllLevels(VehicleRoutingActivityCosts activityCost, ForwardTransportCost transportCost, StatesContainerImpl states) { + super(); + this.activityCost = activityCost; + this.transportCost = transportCost; + this.states = states; + } + + @Override + public void start(VehicleRoute route) { + vehicleRoute = route; + vehicleRoute.getVehicleRouteCostCalculator().reset(); + } + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + if(prevAct == null){ + prevAct = act; + startTimeAtPrevAct = endTime; + } + else{ + double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); + double actCost = activityCost.getActivityCost(act, arrTime, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); + + vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); + vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); + + totalOperationCost += transportCost; + totalOperationCost += actCost; + + if(!(act instanceof End)){ + states.putActivityState(act, StateTypes.COSTS, new StateImpl(totalOperationCost)); + } + + prevAct = act; + startTimeAtPrevAct = endTime; + } + } + + @Override + public void finnish() { + states.putRouteState(vehicleRoute, StateTypes.COSTS, new StateImpl(totalOperationCost)); + + //this is rather strange and likely to change + vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver()); + vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle()); + vehicleRoute.getVehicleRouteCostCalculator().finish(); + + startTimeAtPrevAct = 0.0; + prevAct = null; + vehicleRoute = null; + totalOperationCost = 0.0; + } + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateEarliestStartTimeWindowAtActLocations.java b/jsprit-core/src/main/java/algorithms/UpdateEarliestStartTimeWindowAtActLocations.java new file mode 100644 index 00000000..dee0a67b --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateEarliestStartTimeWindowAtActLocations.java @@ -0,0 +1,31 @@ +package algorithms; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import algorithms.StatesContainer.StateImpl; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class UpdateEarliestStartTimeWindowAtActLocations implements ForwardInTimeListener{ + + private StatesContainerImpl states; + + public UpdateEarliestStartTimeWindowAtActLocations(StatesContainerImpl states) { + super(); + this.states = states; + } + + @Override + public void start(VehicleRoute route) {} + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + if(act instanceof Start || act instanceof End) return; + states.putActivityState(act, StateTypes.EARLIEST_OPERATION_START_TIME, new StateImpl(Math.max(arrTime, act.getTheoreticalEarliestOperationStartTime()))); + } + + @Override + public void finnish() {} + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateLatestOperationStartTimeAtActLocations.java b/jsprit-core/src/main/java/algorithms/UpdateLatestOperationStartTimeAtActLocations.java new file mode 100644 index 00000000..69d6a209 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateLatestOperationStartTimeAtActLocations.java @@ -0,0 +1,32 @@ +package algorithms; + +import algorithms.BackwardInTimeListeners.BackwardInTimeListener; +import algorithms.StatesContainer.StateImpl; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class UpdateLatestOperationStartTimeAtActLocations implements BackwardInTimeListener{ + + private StatesContainerImpl states; + + public UpdateLatestOperationStartTimeAtActLocations(StatesContainerImpl states) { + super(); + this.states = states; + } + + @Override + public void start(VehicleRoute route) {} + + @Override + public void prevActivity(TourActivity act,double latestDepartureTime, double latestOperationStartTime) { +// if(latestOperationStartTime < act.getArrTime()) throw new IllegalStateException(act.toString() + "; latestStart="+latestOperationStartTime+";actArrTime="+act.getArrTime()); + if(act instanceof Start || act instanceof End) return; + states.putActivityState(act, StateTypes.LATEST_OPERATION_START_TIME, new StateImpl(latestOperationStartTime)); + } + + @Override + public void finnish() {} + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateLoadAtAllLevels.java b/jsprit-core/src/main/java/algorithms/UpdateLoadAtAllLevels.java new file mode 100644 index 00000000..d2e43f8f --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateLoadAtAllLevels.java @@ -0,0 +1,46 @@ +package algorithms; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import algorithms.StatesContainer.StateImpl; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +/** + * It does not update start and end activities. + * + * @author stefan + * + */ +class UpdateLoadAtAllLevels implements ForwardInTimeListener{ + + private double load = 0.0; + + private StatesContainerImpl states; + + private VehicleRoute vehicleRoute; + + public UpdateLoadAtAllLevels(StatesContainerImpl states) { + super(); + this.states = states; + } + + @Override + public void start(VehicleRoute route) { vehicleRoute = route; } + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + if(act instanceof Start || act instanceof End){ return; } + load += (double)act.getCapacityDemand(); + states.putActivityState(act, StateTypes.LOAD, new StateImpl(load)); + } + + @Override + public void finnish() { + states.putRouteState(vehicleRoute, StateTypes.LOAD, new StateImpl(load)); + load=0; + vehicleRoute = null; + } + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateLoadAtRouteLevel.java b/jsprit-core/src/main/java/algorithms/UpdateLoadAtRouteLevel.java new file mode 100644 index 00000000..fbfe2d89 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateLoadAtRouteLevel.java @@ -0,0 +1,42 @@ +package algorithms; + +import java.util.Collection; + +import algorithms.StatesContainer.StateImpl; +import basics.Job; +import basics.Service; +import basics.algo.InsertionStartsListener; +import basics.algo.JobInsertedListener; +import basics.route.VehicleRoute; + +class UpdateLoadAtRouteLevel implements JobInsertedListener, InsertionStartsListener{ + + private StatesContainerImpl states; + + public UpdateLoadAtRouteLevel(StatesContainerImpl states) { + super(); + this.states = states; + } + + @Override + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { + if(!(job2insert instanceof Service)){ + return; + } + double oldLoad = states.getRouteState(inRoute, StateTypes.LOAD).toDouble(); + states.putRouteState(inRoute, StateTypes.LOAD, new StateImpl(oldLoad + job2insert.getCapacityDemand())); + } + + @Override + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { + for(VehicleRoute route : vehicleRoutes){ + int load = 0; + for(Job j : route.getTourActivities().getJobs()){ + load += j.getCapacityDemand(); + } + states.putRouteState(route, StateTypes.LOAD, new StateImpl(load)); + } + + } + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateRoute.java b/jsprit-core/src/main/java/algorithms/UpdateRoute.java deleted file mode 100644 index 2fda8f33..00000000 --- a/jsprit-core/src/main/java/algorithms/UpdateRoute.java +++ /dev/null @@ -1,36 +0,0 @@ -package algorithms; - -import java.util.Collection; - -import algorithms.RuinStrategy.RuinListener; -import basics.Job; -import basics.algo.JobInsertedListener; -import basics.costs.VehicleRoutingActivityCosts; -import basics.costs.VehicleRoutingTransportCosts; -import basics.route.VehicleRoute; - -public class UpdateRoute implements JobInsertedListener, RuinListener{ - - private TourStateUpdater routeStateUpdater; - - public UpdateRoute(RouteStates routeStates, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts) { - routeStateUpdater = new TourStateUpdater(routeStates, routingCosts, activityCosts); - } - - @Override - public void informJobInserted(Job job2insert, VehicleRoute inRoute) { - routeStateUpdater.updateRoute(inRoute); - } - - @Override - public void ruinStarts(Collection routes) {} - - @Override - public void ruinEnds(Collection routes,Collection unassignedJobs) { - for(VehicleRoute route : routes) routeStateUpdater.updateRoute(route); - } - - @Override - public void removed(Job job, VehicleRoute fromRoute) {} - -} diff --git a/jsprit-core/src/main/java/algorithms/UpdateStates.java b/jsprit-core/src/main/java/algorithms/UpdateStates.java new file mode 100644 index 00000000..a6d9d0a4 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateStates.java @@ -0,0 +1,55 @@ +package algorithms; + +import java.util.Collection; + +import algorithms.RuinStrategy.RuinListener; +import basics.Job; +import basics.algo.JobInsertedListener; +import basics.costs.VehicleRoutingActivityCosts; +import basics.costs.VehicleRoutingTransportCosts; +import basics.route.VehicleRoute; + +public class UpdateStates implements JobInsertedListener, RuinListener{ + + private IterateRouteForwardInTime iterateForward; + + private IterateRouteBackwardInTime iterateBackward; + + public UpdateStates(StatesContainerImpl states, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts) { + + iterateForward = new IterateRouteForwardInTime(routingCosts); + iterateForward.addListener(new UpdateActivityTimes()); + iterateForward.addListener(new UpdateCostsAtAllLevels(activityCosts, routingCosts, states)); + iterateForward.addListener(new UpdateLoadAtAllLevels(states)); +// iterateForward.addListener(new UpdateEarliestStartTimeWindowAtActLocations(states)); + + iterateBackward = new IterateRouteBackwardInTime(routingCosts); + iterateBackward.addListener(new UpdateLatestOperationStartTimeAtActLocations(states)); + } + + public void update(VehicleRoute route){ + iterateForward.iterate(route); + iterateBackward.iterate(route); + } + + @Override + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { + iterateForward.iterate(inRoute); + iterateBackward.iterate(inRoute); + } + + @Override + public void ruinStarts(Collection routes) {} + + @Override + public void ruinEnds(Collection routes,Collection unassignedJobs) { + for(VehicleRoute route : routes) { + iterateForward.iterate(route); + iterateBackward.iterate(route); + } + } + + @Override + public void removed(Job job, VehicleRoute fromRoute) {} + +} diff --git a/jsprit-core/src/main/java/algorithms/UpdateTourStatesBackwardInTime.java b/jsprit-core/src/main/java/algorithms/UpdateTourStatesBackwardInTime.java deleted file mode 100644 index 8a84a1d6..00000000 --- a/jsprit-core/src/main/java/algorithms/UpdateTourStatesBackwardInTime.java +++ /dev/null @@ -1,105 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Stefan Schroeder. - * eMail: stefan.schroeder@kit.edu - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * Contributors: - * Stefan Schroeder - initial API and implementation - ******************************************************************************/ -package algorithms; - -import java.util.Iterator; - -import org.apache.log4j.Logger; - -import algorithms.RouteStates.ActivityState; -import basics.costs.BackwardTransportTime; -import basics.route.Start; -import basics.route.TourActivities; -import basics.route.TourActivity; -import basics.route.VehicleRoute; - - - - - - -/** - * - * @author stefan schroeder - * - */ - -class UpdateTourStatesBackwardInTime implements VehicleRouteUpdater{ - -// public static Counter counter = new Counter("#updateTWProcesses: "); - - private static Logger log = Logger.getLogger(UpdateTourStatesBackwardInTime.class); - - public boolean checkFeasibility = true; - - private BackwardTransportTime transportTime; - - private RouteStates actStates; - - public void setStates(RouteStates actStates){ - this.actStates = actStates; - } - - public ActivityState state(TourActivity act){ - return actStates.getState(act); - } - - public UpdateTourStatesBackwardInTime(BackwardTransportTime transportTime) { - super(); - this.transportTime = transportTime; - } - - /* - * - */ - public boolean updateRoute(VehicleRoute vehicleRoute) { - boolean ok = update(vehicleRoute); - return ok; - } - - - - private boolean update(VehicleRoute vehicleRoute) { - TourActivities tour = vehicleRoute.getTourActivities(); - int tourSize = tour.getActivities().size(); - Iterator reverseActIter = vehicleRoute.getTourActivities().reverseActivityIterator(); - TourActivity prevAct; - boolean feasible = true; - prevAct = vehicleRoute.getEnd(); - double startAtPrevAct = prevAct.getTheoreticalLatestOperationStartTime(); - int count = 0; - while(reverseActIter.hasNext()){ - TourActivity currAct = reverseActIter.next(); - - double latestOperationStartTime = latestOperationStartTime(vehicleRoute, prevAct, currAct, startAtPrevAct); - ActivityState state = state(currAct); - state.setLatestOperationStart(latestOperationStartTime); - prevAct = currAct; - startAtPrevAct = latestOperationStartTime; - count++; - } -// Start start = vehicleRoute.getStart(); -// double latestOperationStartTime = latestOperationStartTime(vehicleRoute, prevAct, start, startAtPrevAct); - assert count == tourSize; - return feasible; - } - - private double latestOperationStartTime(VehicleRoute vehicleRoute, - TourActivity prevAct, TourActivity currAct, double startAtPrevAct) { - double latestDepTimeAtCurrAct = startAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), startAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle()); - double potentialLatestOperationStartTimeAtCurrAct = latestDepTimeAtCurrAct - currAct.getOperationTime(); - double latestOperationStartTime = Math.min(currAct.getTheoreticalLatestOperationStartTime(), potentialLatestOperationStartTimeAtCurrAct); - return latestOperationStartTime; - } - -} diff --git a/jsprit-core/src/main/java/algorithms/UpdateTourStatesForwardInTime.java b/jsprit-core/src/main/java/algorithms/UpdateTourStatesForwardInTime.java deleted file mode 100644 index 9c534b4a..00000000 --- a/jsprit-core/src/main/java/algorithms/UpdateTourStatesForwardInTime.java +++ /dev/null @@ -1,156 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Stefan Schroeder. - * eMail: stefan.schroeder@kit.edu - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * Contributors: - * Stefan Schroeder - initial API and implementation - ******************************************************************************/ -package algorithms; - -import org.apache.log4j.Logger; - -import algorithms.RouteStates.ActivityState; -import basics.costs.ForwardTransportCost; -import basics.costs.ForwardTransportTime; -import basics.costs.VehicleRoutingActivityCosts; -import basics.route.Driver; -import basics.route.End; -import basics.route.ServiceActivity; -import basics.route.TourActivities; -import basics.route.TourActivity; -import basics.route.Vehicle; -import basics.route.VehicleRoute; - - -/** - * - * @author sschroeder - * - */ - -class UpdateTourStatesForwardInTime implements VehicleRouteUpdater{ - -// public static Counter counter = new Counter("#updateTWProcesses: "); - private static Logger log = Logger.getLogger(UpdateTourStatesForwardInTime.class); - - public boolean checkFeasibility = true; - - private VehicleRoutingActivityCosts activityCost; - - private ForwardTransportTime transportTime; - - private ForwardTransportCost transportCost; - - private RouteStates routeStates; - - private boolean activityStatesSet = false; - - public void setStates(RouteStates actStates){ - this.routeStates = actStates; - activityStatesSet = true; - } - - public ActivityState state(TourActivity act){ - return routeStates.getState(act); - } - - public UpdateTourStatesForwardInTime(ForwardTransportTime transportTime, ForwardTransportCost transportCost, VehicleRoutingActivityCosts activityCost) { - super(); - this.transportTime = transportTime; - this.transportCost = transportCost; - this.activityCost = activityCost; - } - - /** - * - * - */ - public boolean updateRoute(VehicleRoute vehicleRoute) { - vehicleRoute.getVehicleRouteCostCalculator().reset(); - - Vehicle vehicle = vehicleRoute.getVehicle(); - Driver driver = vehicleRoute.getDriver(); - - TourActivity prevAct = vehicleRoute.getStart(); - - double startAtPrevAct = vehicleRoute.getStart().getEndTime(); - - double totalOperationCost = 0.0; - int totalLoadPicked = 0; - int currentLoadState = 0; - - for(TourActivity currentAct : vehicleRoute.getTourActivities().getActivities()){ - totalLoadPicked += getPickedLoad(currentAct); - currentLoadState += getCapDemand(currentAct); - - double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle); - - double arrivalTimeAtCurrAct = startAtPrevAct + transportTime; - double operationStartTime = Math.max(currentAct.getTheoreticalEarliestOperationStartTime(), arrivalTimeAtCurrAct); - - double operationEndTime = operationStartTime + currentAct.getOperationTime(); - - currentAct.setArrTime(arrivalTimeAtCurrAct); - currentAct.setEndTime(operationEndTime); - - double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle); - double actCost = activityCost.getActivityCost(currentAct, arrivalTimeAtCurrAct, driver, vehicle); - - vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); - vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); - - totalOperationCost += transportCost; - totalOperationCost += actCost; - - if(activityStatesSet){ - ActivityState currentState = state(currentAct); - currentState.setEarliestOperationStart(operationStartTime); - currentState.setCurrentLoad(currentLoadState); - currentState.setCurrentCost(totalOperationCost); - } - - prevAct = currentAct; - startAtPrevAct = operationEndTime; - } - - End currentAct = vehicleRoute.getEnd(); - double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle); - double transportTime = this.transportTime.getTransportTime(prevAct.getLocationId(), currentAct.getLocationId(), startAtPrevAct, driver, vehicle); - double arrivalTimeAtCurrAct = startAtPrevAct + transportTime; - - currentAct.setArrTime(arrivalTimeAtCurrAct); - currentAct.setEndTime(arrivalTimeAtCurrAct); - - totalOperationCost += transportCost; - - routeStates.getRouteState(vehicleRoute).setCosts(totalOperationCost); - routeStates.getRouteState(vehicleRoute).setLoad(totalLoadPicked); - - vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); - - vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getDriver()); - vehicleRoute.getVehicleRouteCostCalculator().price(vehicleRoute.getVehicle()); - vehicleRoute.getVehicleRouteCostCalculator().finish(); - return true; - } - - private int getCapDemand(TourActivity currentAct) { - return currentAct.getCapacityDemand(); - } - - private double getPickedLoad(TourActivity currentAct) { - if(currentAct instanceof ServiceActivity){ - return currentAct.getCapacityDemand(); - } -// else if(currentAct instanceof Pickup){ -// return currentAct.getCapacityDemand(); -// } - return 0.0; - } - -} diff --git a/jsprit-core/src/main/java/algorithms/VehicleRouteUpdater.java b/jsprit-core/src/main/java/algorithms/VehicleRouteUpdater.java index ab0efa4e..174bff2a 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleRouteUpdater.java +++ b/jsprit-core/src/main/java/algorithms/VehicleRouteUpdater.java @@ -24,6 +24,6 @@ import basics.route.VehicleRoute; interface VehicleRouteUpdater { - public boolean updateRoute(VehicleRoute vehicleRoute); + public void iterate(VehicleRoute vehicleRoute); } diff --git a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java index b0d5304a..54f1d145 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java @@ -57,6 +57,7 @@ import basics.VehicleRoutingProblem.FleetSize; import basics.VehicleRoutingProblemSolution; import basics.algo.AlgorithmStartsListener; import basics.algo.InsertionListener; +import basics.algo.IterationStartsListener; import basics.algo.IterationWithoutImprovementBreaker; import basics.algo.PrematureAlgorithmBreaker; import basics.algo.SearchStrategy; @@ -447,9 +448,21 @@ public class VehicleRoutingAlgorithms { algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new SolutionVerifier())); - RouteStates routeStates = new RouteStates(); - routeStates.initialiseStateOfJobs(vrp.getJobs().values()); - algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, routeStates)); + final StatesContainerImpl routeStates = new StatesContainerImpl(); + IterationStartsListener resetStates = new IterationStartsListener() { + + @Override + public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { + routeStates.clear(); + } + }; + algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, resetStates)); + +// insertionListeners.add(new UdateCostsAtRouteLevel(routeStates,vrp.getTransportCosts(),vrp.getActivityCosts())); + +// RouteStates routeStates = new RouteStates(); +// routeStates.initialiseStateOfJobs(vrp.getJobs().values()); +// algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, routeStates)); TypedMap definedClasses = new TypedMap(); @@ -557,7 +570,7 @@ public class VehicleRoutingAlgorithms { metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners); } - private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, RouteStates activityStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) { + private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StatesContainerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) { List modConfigs = config.configurationsAt("construction.insertion"); if(modConfigs == null) return null; if(modConfigs.isEmpty()) return null; @@ -572,7 +585,7 @@ public class VehicleRoutingAlgorithms { InsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey); if(insertionStrategy == null){ List prioListeners = new ArrayList(); - insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, activityStates, prioListeners, executorService, nuOfThreads); + insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads); algorithmListeners.addAll(prioListeners); definedClasses.put(insertionStrategyKey,insertionStrategy); } @@ -654,7 +667,7 @@ public class VehicleRoutingAlgorithms { } private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, - final RouteStates activityStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) { + final StatesContainerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) { String moduleName = moduleConfig.getString("[@name]"); if(moduleName == null) throw new IllegalStateException("module(-name) is missing."); String moduleId = moduleConfig.getString("[@id]"); @@ -675,7 +688,7 @@ public class VehicleRoutingAlgorithms { final RuinStrategy ruin; ModKey ruinKey = makeKey(ruin_name,ruin_id); if(ruin_name.equals("randomRuin")){ - ruin = getRandomRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin); + ruin = getRandomRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin); } else if(ruin_name.equals("radialRuin")){ String ruin_distance = moduleConfig.getString("ruin.distance"); @@ -688,7 +701,7 @@ public class VehicleRoutingAlgorithms { else throw new IllegalStateException("does not know ruin.distance " + ruin_distance + ". either ommit ruin.distance then the " + "default is used or use 'euclidean'"); } - ruin = getRadialRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin, jobDistance); + ruin = getRadialRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin, jobDistance); } else throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin."); @@ -703,7 +716,7 @@ public class VehicleRoutingAlgorithms { List insertionConfigs = moduleConfig.configurationsAt("insertion"); if(insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1"); List prioListeners = new ArrayList(); - insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, activityStates, prioListeners, executorService, nuOfThreads); + insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads); algorithmListeners.addAll(prioListeners); } final InsertionStrategy final_insertion = insertion; @@ -758,23 +771,7 @@ public class VehicleRoutingAlgorithms { RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ ruin = new RuinRadial(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts())); - ruin.addListener(new RuinListener() { - - TourStateUpdater updater = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()); - - @Override - public void ruinStarts(Collection routes) {} - - @Override - public void ruinEnds(Collection routes, Collection unassignedJobs) { - for(VehicleRoute route : routes){ - updater.updateRoute(route); - } - } - - @Override - public void removed(Job job, VehicleRoute fromRoute) {} - }); + ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } @@ -789,7 +786,7 @@ public class VehicleRoutingAlgorithms { List insertionConfigs = moduleConfig.configurationsAt("insertion"); if(insertionConfigs.size() != 1) throw new IllegalStateException("this should be 1"); List prioListeners = new ArrayList(); - insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, activityStates, prioListeners, executorService, nuOfThreads); + insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads); algorithmListeners.addAll(prioListeners); } Gendreau gendreau = new Gendreau(vrp, ruin, insertion); @@ -808,62 +805,30 @@ public class VehicleRoutingAlgorithms { "\n\tgendreauPostOpt"); } - private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final RouteStates activityStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) { + private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final StatesContainerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) { RuinStrategyKey stratKey = new RuinStrategyKey(modKey); RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ ruin = new RuinRadial(vrp, shareToRuin, jobDistance); - ruin.addListener(new RuinListener() { - - TourStateUpdater updater = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()); - - @Override - public void ruinStarts(Collection routes) {} - - @Override - public void ruinEnds(Collection routes, Collection unassignedJobs) { - for(VehicleRoute route : routes){ - updater.updateRoute(route); - } - } - - @Override - public void removed(Job job, VehicleRoute fromRoute) {} - }); + ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } return ruin; } - private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final RouteStates activityStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) { + private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final StatesContainerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) { RuinStrategyKey stratKey = new RuinStrategyKey(modKey); RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ ruin = new RuinRandom(vrp, shareToRuin); - ruin.addListener(new RuinListener() { - - TourStateUpdater updater = new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts()); - - @Override - public void ruinStarts(Collection routes) {} - - @Override - public void ruinEnds(Collection routes, Collection unassignedJobs) { - for(VehicleRoute route : routes){ - updater.updateRoute(route); - } - } - - @Override - public void removed(Job job, VehicleRoute fromRoute) {} - }); + ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } return ruin; } - private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads) { - InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, activityStates, algorithmListeners, executorService, nuOfThreads); + private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, StatesContainerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads) { + InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads); return insertion; } diff --git a/jsprit-core/src/main/java/basics/algo/JobInsertedListener.java b/jsprit-core/src/main/java/basics/algo/JobInsertedListener.java index 510a9ded..9df55225 100644 --- a/jsprit-core/src/main/java/basics/algo/JobInsertedListener.java +++ b/jsprit-core/src/main/java/basics/algo/JobInsertedListener.java @@ -30,5 +30,5 @@ import basics.route.VehicleRoute; public interface JobInsertedListener extends InsertionListener{ - public void informJobInserted(Job job2insert, VehicleRoute inRoute); + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime); } diff --git a/jsprit-core/src/main/java/basics/route/End.java b/jsprit-core/src/main/java/basics/route/End.java index 39e585a8..ba3f6f2a 100644 --- a/jsprit-core/src/main/java/basics/route/End.java +++ b/jsprit-core/src/main/java/basics/route/End.java @@ -61,6 +61,7 @@ public final class End implements TourActivity { this.locationId = locationId; theoretical_earliestOperationStartTime = theoreticalStart; theoretical_latestOperationStartTime = theoreticalEnd; + endTime = theoreticalEnd; } public End(End end) { diff --git a/jsprit-core/src/test/java/algorithms/AlgorithmsSuite.java b/jsprit-core/src/test/java/algorithms/AlgorithmsSuite.java index f7e21518..e710161f 100644 --- a/jsprit-core/src/test/java/algorithms/AlgorithmsSuite.java +++ b/jsprit-core/src/test/java/algorithms/AlgorithmsSuite.java @@ -36,7 +36,6 @@ import algorithms.selectors.SelectRandomlyTest; GendreauPostOptTest.class, TestAlgorithmReader.class, // TestAux.class, - TestCalculatesActivityInsertion.class, TestCalculatesServiceInsertion.class, TestCalculatesServiceInsertionOnRouteLevel.class, TestSchrimpf.class, diff --git a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java index dc0ee95a..0f367fd8 100644 --- a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java +++ b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java @@ -41,12 +41,12 @@ import basics.costs.VehicleRoutingActivityCosts; import basics.costs.VehicleRoutingTransportCosts; import basics.route.Driver; import basics.route.DriverImpl; +import basics.route.ServiceActivity; import basics.route.TimeWindow; import basics.route.TourActivities; import basics.route.Vehicle; import basics.route.VehicleImpl; import basics.route.VehicleRoute; -import basics.route.VehicleType; import basics.route.VehicleTypeImpl; public class GendreauPostOptTest { @@ -71,15 +71,11 @@ public class GendreauPostOptTest { Service job3; - private RouteStates states; + private StatesContainerImpl states; private List vehicles; - private TourStateUpdater updater; - private VehicleFleetManagerImpl fleetManager; - - private RouteAlgorithmImpl routeAlgorithm; private JobInsertionCalculator insertionCalc; @@ -151,7 +147,7 @@ public class GendreauPostOptTest { // Collection vehicles = Arrays.asList(lightVehicle1,lightVehicle2, heavyVehicle); fleetManager = new VehicleFleetManagerImpl(vehicles); - states = new RouteStates(); + states = new StatesContainerImpl(); activityCosts = new ExampleActivityCostFunction(); @@ -162,23 +158,7 @@ public class GendreauPostOptTest { insertionCalc = new CalculatesVehTypeDepServiceInsertion(fleetManager, withFixCost); - updater = new TourStateUpdater(states, cost, activityCosts); - -// -// -// routeAlgorithm = RouteAlgorithmImpl.newInstance(insertionCalc, updater); -// routeAlgorithm.setActivityStates(states); -// if(fleetManager != null){ -// routeAlgorithm.getListeners().add(new RouteAlgorithm.VehicleSwitchedListener() { -// -// @Override -// public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) { -// fleetManager.unlock(oldVehicle); -// fleetManager.lock(newVehicle); -// } -// }); -// } - +// updater = new TourStateUpdater(states, cost, activityCosts); } @@ -188,18 +168,19 @@ public class GendreauPostOptTest { jobs.add(job1); jobs.add(job2); - states.initialiseStateOfJobs(jobs); vrp = VehicleRoutingProblem.Builder.newInstance().addAllJobs(jobs).addAllVehicles(vehicles).setRoutingCost(cost).build(); TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(job1, true)); - tour.addActivity(states.getActivity(job2, true)); + tour.addActivity(ServiceActivity.newInstance(job1)); + tour.addActivity(ServiceActivity.newInstance(job2)); VehicleRoute route = VehicleRoute.newInstance(tour,DriverImpl.noDriver(),heavyVehicle); - updater.updateRoute(route); fleetManager.lock(heavyVehicle); + UpdateStates stateUpdater = new UpdateStates(states, vrp.getTransportCosts(), vrp.getActivityCosts()); + stateUpdater.update(route); + Collection routes = new ArrayList(); routes.add(route); // routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); @@ -209,7 +190,6 @@ public class GendreauPostOptTest { assertEquals(110.0, sol.getCost(), 0.5); - UpdateRoute stateUpdater = new UpdateRoute(states, vrp.getTransportCosts(), vrp.getActivityCosts()); RuinRadial radialRuin = new RuinRadial(vrp, 0.2, new JobDistanceAvgCosts(vrp.getTransportCosts())); radialRuin.addListener(stateUpdater); @@ -234,17 +214,17 @@ public class GendreauPostOptTest { jobs.add(job2); jobs.add(job3); - states.initialiseStateOfJobs(jobs); vrp = VehicleRoutingProblem.Builder.newInstance().addAllJobs(jobs).addAllVehicles(vehicles).setRoutingCost(cost).build(); TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(job1, true)); - tour.addActivity(states.getActivity(job2, true)); - tour.addActivity(states.getActivity(job3, true)); - + tour.addActivity(ServiceActivity.newInstance(job1)); + tour.addActivity(ServiceActivity.newInstance(job2)); + tour.addActivity(ServiceActivity.newInstance(job3)); VehicleRoute route = VehicleRoute.newInstance(tour,DriverImpl.noDriver(),heavyVehicle); - updater.updateRoute(route); + + UpdateStates stateUpdater = new UpdateStates(states, vrp.getTransportCosts(), vrp.getActivityCosts()); + stateUpdater.update(route); fleetManager.lock(heavyVehicle); @@ -255,8 +235,6 @@ public class GendreauPostOptTest { assertEquals(110.0, sol.getCost(), 0.5); - UpdateRoute stateUpdater = new UpdateRoute(states, vrp.getTransportCosts(), vrp.getActivityCosts()); - RuinRadial radialRuin = new RuinRadial(vrp, 0.2, new JobDistanceAvgCosts(vrp.getTransportCosts())); InsertionStrategy insertionStrategy = new BestInsertion(insertionCalc); insertionStrategy.addListener(stateUpdater); @@ -272,18 +250,6 @@ public class GendreauPostOptTest { assertEquals(2,newSolution.getRoutes().size()); assertEquals(80.0,newSolution.getCost(),0.5); } - - private Vehicle getNoVehicle() { - return new VehicleImpl.NoVehicle(); - } - - private Driver getDriver() { - return DriverImpl.noDriver(); - } - - private TourActivities getEmptyTour() { - return new TourActivities(); - } private Service getService(String to, double serviceTime) { Service s = Service.Builder.newInstance(to, 0).setLocationId(to).setServiceTime(serviceTime).setTimeWindow(TimeWindow.newInstance(0.0, 20.0)).build(); diff --git a/jsprit-core/src/test/java/algorithms/TestCalculatesActivityInsertion.java b/jsprit-core/src/test/java/algorithms/TestCalculatesActivityInsertion.java deleted file mode 100644 index 23d24618..00000000 --- a/jsprit-core/src/test/java/algorithms/TestCalculatesActivityInsertion.java +++ /dev/null @@ -1,286 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2013 Stefan Schroeder - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributors: - * Stefan Schroeder - initial API and implementation - ******************************************************************************/ -package algorithms; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; - -import algorithms.RouteStates.ActivityState; -import basics.costs.VehicleRoutingTransportCosts; -import basics.route.TourActivities; -import basics.route.TourActivity; -import basics.route.Vehicle; -import basics.route.VehicleRoute; - - - -public class TestCalculatesActivityInsertion { - - VehicleRoutingTransportCosts costs; - - Vehicle newVehicle; - - private RouteStates states; - - private CalculatesActivityInsertionWithHardTimeWindows insertionCalculator; - - @Before - public void setup(){ - costs = mock(VehicleRoutingTransportCosts.class); - newVehicle = mock(Vehicle.class); - - when(costs.getTransportCost("depot", "1", 0.0, null, null)).thenReturn(10.0); - when(costs.getTransportCost("depot", "2", 0.0, null, null)).thenReturn(20.0); - when(costs.getTransportCost("depot", "3", 0.0, null, null)).thenReturn(10.0); - when(costs.getTransportCost("1", "2", 0.0, null, null)).thenReturn(10.0); - when(costs.getTransportCost("1", "3", 0.0, null, null)).thenReturn(20.0); - when(costs.getTransportCost("2", "3", 0.0, null, null)).thenReturn(10.0); - - when(costs.getTransportCost("1", "depot", 0.0, null, null)).thenReturn(10.0); - when(costs.getTransportCost("2", "depot", 0.0, null, null)).thenReturn(20.0); - when(costs.getTransportCost("3", "depot", 0.0, null, null)).thenReturn(10.0); - when(costs.getTransportCost("2", "1", 0.0, null, null)).thenReturn(10.0); - when(costs.getTransportCost("3", "1", 0.0, null, null)).thenReturn(20.0); - when(costs.getTransportCost("3", "2", 0.0, null, null)).thenReturn(10.0); - - when(costs.getTransportCost("depot", "1", 0.0, null, newVehicle)).thenReturn(20.0); - when(costs.getTransportCost("depot", "2", 0.0, null, newVehicle)).thenReturn(40.0); - when(costs.getTransportCost("depot", "3", 0.0, null, newVehicle)).thenReturn(20.0); - when(costs.getTransportCost("1", "2", 0.0, null, newVehicle)).thenReturn(20.0); - when(costs.getTransportCost("1", "3", 0.0, null, newVehicle)).thenReturn(40.0); - when(costs.getTransportCost("2", "3", 0.0, null, newVehicle)).thenReturn(20.0); - - when(costs.getTransportCost("1", "depot", 0.0, null, newVehicle)).thenReturn(20.0); - when(costs.getTransportCost("2", "depot", 0.0, null, newVehicle)).thenReturn(40.0); - when(costs.getTransportCost("3", "depot", 0.0, null, newVehicle)).thenReturn(20.0); - when(costs.getTransportCost("2", "1", 0.0, null, newVehicle)).thenReturn(20.0); - when(costs.getTransportCost("3", "1", 0.0, null, newVehicle)).thenReturn(40.0); - when(costs.getTransportCost("3", "2", 0.0, null, newVehicle)).thenReturn(20.0); - - states = new RouteStates(); - - insertionCalculator = new CalculatesActivityInsertionWithHardTimeWindows(states,costs,activityCosts()); - - } - - private ExampleActivityCostFunction activityCosts() { - return new ExampleActivityCostFunction(); - } - - public TourActivity getActivityMock(String id, double earliestOperationStart, double currCost){ - TourActivity act = mock(TourActivity.class); - when(act.getLocationId()).thenReturn(id); - states.getActivityStates().put(act, new ActivityState(act)); - states.getState(act).setEarliestOperationStart(earliestOperationStart); - states.getState(act).setCurrentCost(currCost); -// when(act.getEarliestOperationStartTime()).thenReturn(earliestOperationStart); -// when(act.getCurrentCost()).thenReturn(currCost); - return act; - } - - @Test - public void whenInsertingANewJob_itCalculatesMarginalCostChanges(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity prevAct = getActivityMock("1", 0.0, 10.0); - TourActivity nextAct = getActivityMock("3", 0.0, 30.0); - TourActivity act2insert = getActivityMock("2", 0.0, 0.0); - TourActivity end = getActivityMock("depot", 0.0, 40.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(prevAct); - vehicleRoute.getTourActivities().addActivity(nextAct); - vehicleRoute.getTourActivities().addActivity(end); - - List activities = Arrays.asList(start,prevAct,nextAct,end); - when(tour.getActivities()).thenReturn(activities); -// when(states.getRouteState(vehicleRoute).getCosts()).thenReturn(40.0); - - double c = insertionCalculator.calculate(vehicleRoute, prevAct, nextAct, act2insert, null, null); - assertEquals(0.0,c,0.2); - } - - @Test - public void whenInsertingANewJob_itCalculatesMarginalCostChanges2(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity act1 = getActivityMock("1", 0.0, 10.0); - TourActivity act3 = getActivityMock("3", 0.0, 0.0); - TourActivity act2 = getActivityMock("2", 0.0, 20.0); - TourActivity end = getActivityMock("depot", 0.0, 40.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(act1); - vehicleRoute.getTourActivities().addActivity(act2); - vehicleRoute.getTourActivities().addActivity(end); - - List activities = Arrays.asList(start,act1,act2,end); - when(tour.getActivities()).thenReturn(activities); - - double c = insertionCalculator.calculate(vehicleRoute, act1, act2, act3, null, null); - assertEquals(20.0,c,0.2); - } - - @Test - public void whenInsertingANewJob_itCalculatesMarginalCostChanges3(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity act1 = getActivityMock("1", 0.0, 10.0); - TourActivity act3 = getActivityMock("3", 0.0, 0.0); - TourActivity act2 = getActivityMock("2", 0.0, 0.0); - TourActivity end = getActivityMock("depot", 0.0, 20.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(act1); - vehicleRoute.getTourActivities().addActivity(end); - - List activities = Arrays.asList(start,act1,end); - when(tour.getActivities()).thenReturn(activities); - - double c = insertionCalculator.calculate(vehicleRoute, start, act1, act3, null, null); - assertEquals(20.0,c,0.2); - } - - @Test - public void whenInsertingANewJobWithANewVehicle_itCalculatesLocalMarginalCostChanges(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity act1 = getActivityMock("1", 0.0, 10.0); - TourActivity act3 = getActivityMock("3", 0.0, 0.0); - TourActivity act2 = getActivityMock("2", 0.0, 20.0); - TourActivity end = getActivityMock("depot", 0.0, 40.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(act1); - vehicleRoute.getTourActivities().addActivity(act2); - vehicleRoute.getTourActivities().addActivity(end); - - - List activities = Arrays.asList(start,act1,act2,end); - when(tour.getActivities()).thenReturn(activities); - - double c = insertionCalculator.calculate(vehicleRoute, act1, act2, act3, null, newVehicle); - assertEquals(50.0,c,0.2); - } - - @Test - public void whenInsertingANewJobWithANewVehicle_itCalculatesLocalMarginalCostChangesAndAfterInsertionCostChanges(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity act1 = getActivityMock("1", 0.0, 10.0); - TourActivity act3 = getActivityMock("3", 0.0, 0.0); - TourActivity act2 = getActivityMock("2", 0.0, 20.0); - TourActivity end = getActivityMock("depot", 0.0, 40.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(act1); - vehicleRoute.getTourActivities().addActivity(act2); - vehicleRoute.getTourActivities().addActivity(end); - - List activities = Arrays.asList(start,act1,act2,end); - when(tour.getActivities()).thenReturn(activities); - - double c = insertionCalculator.calculate(vehicleRoute, act1, act2, act3, null, newVehicle); - assertEquals(50.0,c,0.2); - } - -//already on route-level -// @Test -// public void whenInsertingANewJobWithANewVehicle_itCalculatesTotalMarginalCostChanges(){ -// Tour tour = mock(Tour.class); -// TourActivity start = getActivityMock("depot", 0.0, 0.0); -// TourActivity act1 = getActivityMock("1", 0.0, 10.0); -// TourActivity act3 = getActivityMock("3", 0.0, 0.0); -// TourActivity act2 = getActivityMock("2", 0.0, 20.0); -// TourActivity end = getActivityMock("depot", 0.0, 40.0); -// -// List activities = Arrays.asList(start,act1,act2,end); -// when(tour.getActivities()).thenReturn(activities); -// -// double c = insertionCalculator.calculate(tour, act1, act2, act3, null, newVehicle); -// assertEquals(80.0,c,0.2); -// } - - @Test - public void whenInsertingANewJobWithANewVehicle_itCalculatesTotalMarginalCostChanges2(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity act1 = getActivityMock("1", 0.0, 10.0); - TourActivity act3 = getActivityMock("3", 0.0, 0.0); - TourActivity act2 = getActivityMock("2", 0.0, 20.0); - TourActivity end = getActivityMock("depot", 0.0, 40.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(act1); - vehicleRoute.getTourActivities().addActivity(act2); - vehicleRoute.getTourActivities().addActivity(end); - - List activities = Arrays.asList(start,act1,act2,end); - when(tour.getActivities()).thenReturn(activities); - - double c = insertionCalculator.calculate(vehicleRoute, act2, end, act3, null, newVehicle); - assertEquals(20.0,c,0.2); - } - - @Test - public void whenInsertingANewJobWithANewVehicle_itCalculatesTotalMarginalCostChanges3(){ - VehicleRoute vehicleRoute = VehicleRoute.emptyRoute(); - - TourActivities tour = mock(TourActivities.class); - TourActivity start = getActivityMock("depot", 0.0, 0.0); - TourActivity act1 = getActivityMock("1", 0.0, 10.0); - TourActivity act3 = getActivityMock("3", 0.0, 0.0); - TourActivity act2 = getActivityMock("2", 0.0, 20.0); - TourActivity end = getActivityMock("depot", 0.0, 40.0); - - vehicleRoute.getTourActivities().addActivity(start); - vehicleRoute.getTourActivities().addActivity(act1); - vehicleRoute.getTourActivities().addActivity(act2); - vehicleRoute.getTourActivities().addActivity(end); - - List activities = Arrays.asList(start,act1,act2,end); - when(tour.getActivities()).thenReturn(activities); - - double c = insertionCalculator.calculate(vehicleRoute, start, act1, act3, null, newVehicle); - assertEquals(50.0,c,0.2); - } - -} diff --git a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java index 2f3ee965..7b13d457 100644 --- a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java +++ b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java @@ -36,6 +36,7 @@ import basics.Job; import basics.Service; import basics.costs.VehicleRoutingTransportCosts; import basics.route.DriverImpl; +import basics.route.ServiceActivity; import basics.route.TimeWindow; import basics.route.TourActivities; import basics.route.TourActivity; @@ -61,12 +62,12 @@ public class TestCalculatesServiceInsertion { private Service third; - private RouteStates states; - - private TourStateUpdater tourStateUpdater; + private StatesContainerImpl states; private NoDriver driver; + private UpdateStates stateUpdater; + @Before public void setup(){ Logger.getRootLogger().setLevel(Level.DEBUG); @@ -151,17 +152,14 @@ public class TestCalculatesServiceInsertion { jobs.add(second); jobs.add(third); - states = new RouteStates(); - states.initialiseStateOfJobs(jobs); + states = new StatesContainerImpl(); ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction(); serviceInsertion = new CalculatesServiceInsertion(costs, activityCosts); serviceInsertion.setActivityStates(states); - tourStateUpdater = new TourStateUpdater(states, costs, activityCosts); - - + stateUpdater = new UpdateStates(states, costs, activityCosts); } @@ -176,7 +174,7 @@ public class TestCalculatesServiceInsertion { TourActivities tour = new TourActivities(); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + stateUpdater.update(route); InsertionData iData = serviceInsertion.calculate(route, first, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(20.0, iData.getInsertionCost(), 0.2); @@ -186,10 +184,10 @@ public class TestCalculatesServiceInsertion { @Test public void whenInsertingTheSecondJobInAnNonEmptyTourWithVehicle_itCalculatesMarginalCostChanges(){ TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(first, true)); + tour.addActivity(ServiceActivity.newInstance(first)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + stateUpdater.update(route); InsertionData iData = serviceInsertion.calculate(route, second, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(20.0, iData.getInsertionCost(), 0.2); @@ -199,12 +197,12 @@ public class TestCalculatesServiceInsertion { @Test public void whenInsertingThirdJobWithVehicle_itCalculatesMarginalCostChanges(){ TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(first,true)); - tour.addActivity(states.getActivity(second,true)); + tour.addActivity(ServiceActivity.newInstance(first)); + tour.addActivity(ServiceActivity.newInstance(second)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + stateUpdater.update(route); InsertionData iData = serviceInsertion.calculate(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(0.0, iData.getInsertionCost(), 0.2); @@ -214,12 +212,12 @@ public class TestCalculatesServiceInsertion { @Test public void whenInsertingThirdJobWithNewVehicle_itCalculatesMarginalCostChanges(){ TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(first,true)); - tour.addActivity(states.getActivity(second,true)); + tour.addActivity(ServiceActivity.newInstance(first)); + tour.addActivity(ServiceActivity.newInstance(second)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + stateUpdater.update(route); InsertionData iData = serviceInsertion.calculate(route, third, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(20.0, iData.getInsertionCost(), 0.2); @@ -229,11 +227,11 @@ public class TestCalculatesServiceInsertion { @Test public void whenInsertingASecondJobWithAVehicle_itCalculatesLocalMarginalCostChanges(){ TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(first,true)); - tour.addActivity(states.getActivity(third,true)); + tour.addActivity(ServiceActivity.newInstance(first)); + tour.addActivity(ServiceActivity.newInstance(third)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + stateUpdater.update(route); InsertionData iData = serviceInsertion.calculate(route, second, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(0.0, iData.getInsertionCost(), 0.2); @@ -243,13 +241,13 @@ public class TestCalculatesServiceInsertion { @Test public void whenInsertingASecondJobWithANewVehicle_itCalculatesLocalMarginalCostChanges(){ TourActivities tour = new TourActivities(); - tour.addActivity(states.getActivity(first,true)); - tour.addActivity(states.getActivity(third,true)); + tour.addActivity(ServiceActivity.newInstance(first)); + tour.addActivity(ServiceActivity.newInstance(third)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); // route.addActivity(states.getActivity(first,true)); // route.addActivity(states.getActivity(third,true)); - tourStateUpdater.updateRoute(route); + stateUpdater.update(route); InsertionData iData = serviceInsertion.calculate(route, second, newVehicle, newVehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(20.0, iData.getInsertionCost(), 0.2); diff --git a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertionOnRouteLevel.java b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertionOnRouteLevel.java index 06bc449c..1a9083d2 100644 --- a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertionOnRouteLevel.java +++ b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertionOnRouteLevel.java @@ -64,9 +64,7 @@ public class TestCalculatesServiceInsertionOnRouteLevel { private Service third; - private RouteStates states; - - private TourStateUpdater tourStateUpdater; + private StatesContainerImpl states; private NoDriver driver; @@ -167,7 +165,7 @@ public class TestCalculatesServiceInsertionOnRouteLevel { TourActivities tour = new TourActivities(); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + tourStateUpdater.iterate(route); InsertionData iData = serviceInsertion.calculate(route, first, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(20.0, iData.getInsertionCost(), 0.2); @@ -208,7 +206,7 @@ public class TestCalculatesServiceInsertionOnRouteLevel { VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + tourStateUpdater.iterate(route); InsertionData iData = serviceInsertion.calculate(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(0.0, iData.getInsertionCost(), 0.2); @@ -223,7 +221,7 @@ public class TestCalculatesServiceInsertionOnRouteLevel { VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + tourStateUpdater.iterate(route); InsertionData iData = serviceInsertion.calculate(route, third, newVehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(40.0, iData.getInsertionCost(), 0.2); @@ -237,7 +235,7 @@ public class TestCalculatesServiceInsertionOnRouteLevel { tour.addActivity(states.getActivity(third,true)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + tourStateUpdater.iterate(route); InsertionData iData = serviceInsertion.calculate(route, second, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(0.0, iData.getInsertionCost(), 0.2); @@ -251,7 +249,7 @@ public class TestCalculatesServiceInsertionOnRouteLevel { tour.addActivity(states.getActivity(third,true)); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + tourStateUpdater.iterate(route); InsertionData iData = serviceInsertion.calculate(route, second, newVehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(40.0, iData.getInsertionCost(), 0.2); diff --git a/jsprit-core/src/test/java/algorithms/TestIterateRouteForwardInTime.java b/jsprit-core/src/test/java/algorithms/TestIterateRouteForwardInTime.java new file mode 100644 index 00000000..c987e94e --- /dev/null +++ b/jsprit-core/src/test/java/algorithms/TestIterateRouteForwardInTime.java @@ -0,0 +1,196 @@ +package algorithms; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; + +import util.Coordinate; +import util.ManhattanDistanceCalculator; +import basics.Job; +import basics.Service; +import basics.costs.DefaultVehicleRoutingActivityCosts; +import basics.costs.VehicleRoutingTransportCosts; +import basics.route.Driver; +import basics.route.DriverImpl; +import basics.route.ServiceActivity; +import basics.route.TimeWindow; +import basics.route.TourActivities; +import basics.route.Vehicle; +import basics.route.VehicleImpl; +import basics.route.VehicleRoute; +import basics.route.VehicleTypeImpl; + +public class TestIterateRouteForwardInTime { + + TourActivities tour; + + Driver driver; + + Vehicle vehicle; + + TourActivities anotherTour; + + + + RouteStates states; + + private VehicleRoute vehicleRoute; + + private VehicleRoutingTransportCosts cost; + + ServiceActivity firstAct; + + ServiceActivity secondAct; + + @Before + public void setUp(){ + cost = new VehicleRoutingTransportCosts() { + + @Override + public double getBackwardTransportTime(String fromId, String toId, + double arrivalTime, Driver driver, Vehicle vehicle) { + return getTransportCost(fromId, toId, arrivalTime, driver, vehicle); + } + + @Override + public double getBackwardTransportCost(String fromId, String toId, + double arrivalTime, Driver driver, Vehicle vehicle) { + return getTransportCost(fromId, toId, arrivalTime, driver, vehicle); + } + + @Override + public double getTransportCost(String fromId, String toId, double departureTime, Driver driver, Vehicle vehicle) { + String[] fromTokens = fromId.split(","); + String[] toTokens = toId.split(","); + double fromX = Double.parseDouble(fromTokens[0]); + double fromY = Double.parseDouble(fromTokens[1]); + + double toX = Double.parseDouble(toTokens[0]); + double toY = Double.parseDouble(toTokens[1]); + + return ManhattanDistanceCalculator.calculateDistance(new Coordinate(fromX, fromY), new Coordinate(toX, toY)); + } + + @Override + public double getTransportTime(String fromId, String toId, double departureTime, Driver driver, Vehicle vehicle) { + return getTransportCost(fromId, toId, departureTime, driver, vehicle); + } + }; + + Service firstService = Service.Builder.newInstance("1", 5).setLocationId("10,0").setTimeWindow(TimeWindow.newInstance(0, 20)).build(); + Service secondService = Service.Builder.newInstance("2", 5).setLocationId("0,10").setTimeWindow(TimeWindow.newInstance(0, 50)).build(); + + Collection services = new ArrayList(); + services.add(firstService); + services.add(secondService); + + VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("test", 0).build(); + vehicle = VehicleImpl.Builder.newInstance("testvehicle").setType(type).setLocationId("0,0") + .setEarliestStart(0.0).setLatestArrival(50.0).build(); + + tour = new TourActivities(); + firstAct = ServiceActivity.newInstance(firstService); + tour.addActivity(firstAct); + secondAct = ServiceActivity.newInstance(secondService); + tour.addActivity(secondAct); + + vehicleRoute = VehicleRoute.newInstance(tour,DriverImpl.noDriver(),vehicle); + } + + @Test + public void whenIteratingWithoutUpdate_itShouldUpdateNothing() { + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + forwardInTime.iterate(vehicleRoute); + + assertEquals(0.0,firstAct.getArrTime(),0.1); + assertEquals(0.0,firstAct.getEndTime(),0.1); + + assertEquals(0.0,secondAct.getArrTime(),0.1); + assertEquals(0.0,secondAct.getEndTime(),0.1); + } + + @Test + public void whenIteratingWithActivityTimeUpdater_itShouldUpdateActivityTimes() { + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + forwardInTime.addListener(new UpdateActivityTimes()); + forwardInTime.iterate(vehicleRoute); + + assertEquals(10.0,firstAct.getArrTime(),0.1); + assertEquals(10.0,firstAct.getEndTime(),0.1); + + assertEquals(30.0,secondAct.getArrTime(),0.1); + assertEquals(30.0,secondAct.getEndTime(),0.1); + } + + @Test + public void whenIteratingWithLoadUpdateAtActLocations_itShouldUpdateLoad() { + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + StatesContainerImpl states = new StatesContainerImpl(); + forwardInTime.addListener(new UpdateLoadAtAllLevels(states)); + forwardInTime.iterate(vehicleRoute); + + assertEquals(5.0, states.getActivityStates(firstAct).getState(StateTypes.LOAD).toDouble(), 0.01); + assertEquals(10.0, states.getActivityStates(secondAct).getState(StateTypes.LOAD).toDouble(), 0.01); + } + + + @Test + public void testStatesOfAct0(){ + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + forwardInTime.iterate(vehicleRoute); + + assertEquals(0.0, vehicleRoute.getStart().getEndTime(),0.05); + assertEquals(vehicleRoute.getVehicle().getLocationId(), vehicleRoute.getStart().getLocationId()); + assertEquals(vehicleRoute.getVehicle().getEarliestDeparture(), vehicleRoute.getStart().getTheoreticalEarliestOperationStartTime(),0.05); + assertEquals(vehicleRoute.getVehicle().getLatestArrival(), vehicleRoute.getStart().getTheoreticalLatestOperationStartTime(),0.05); + + } + + @Test + public void testStatesOfAct1(){ + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + StatesContainerImpl states = new StatesContainerImpl(); + forwardInTime.addListener(new UpdateLoadAtAllLevels(states)); + forwardInTime.addListener(new UpdateEarliestStartTimeWindowAtActLocations(states)); + forwardInTime.addListener(new UpdateCostsAtAllLevels(new DefaultVehicleRoutingActivityCosts(), cost, states)); + forwardInTime.iterate(vehicleRoute); + + assertEquals(10.0, states.getActivityStates(firstAct).getState(StateTypes.COSTS).toDouble(),0.05); + assertEquals(5.0, states.getActivityStates(firstAct).getState(StateTypes.LOAD).toDouble(),0.05); + assertEquals(10.0, states.getActivityStates(firstAct).getState(StateTypes.EARLIEST_OPERATION_START_TIME).toDouble(),0.05); +// assertEquals(20.0, states.getState(tour.getActivities().get(0)).getLatestOperationStart(),0.05); + } + + @Test + public void testStatesOfAct2(){ + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + StatesContainerImpl states = new StatesContainerImpl(); + forwardInTime.addListener(new UpdateLoadAtAllLevels(states)); + forwardInTime.addListener(new UpdateEarliestStartTimeWindowAtActLocations(states)); + forwardInTime.addListener(new UpdateCostsAtAllLevels(new DefaultVehicleRoutingActivityCosts(), cost, states)); + forwardInTime.iterate(vehicleRoute); + + assertEquals(30.0, states.getActivityStates(secondAct).getState(StateTypes.COSTS).toDouble(),0.05); + assertEquals(10.0, states.getActivityStates(secondAct).getState(StateTypes.LOAD).toDouble(),0.05); + assertEquals(30.0, states.getActivityStates(secondAct).getState(StateTypes.EARLIEST_OPERATION_START_TIME).toDouble(),0.05); +// assertEquals(40.0, states.getState(tour.getActivities().get(1)).getLatestOperationStart(),0.05); + } + + @Test + public void testStatesOfAct3(){ + IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(cost); + StatesContainerImpl states = new StatesContainerImpl(); + forwardInTime.addListener(new UpdateActivityTimes()); + forwardInTime.addListener(new UpdateCostsAtAllLevels(new DefaultVehicleRoutingActivityCosts(), cost, states)); + forwardInTime.iterate(vehicleRoute); + + assertEquals(40.0, states.getRouteStates(vehicleRoute).getState(StateTypes.COSTS).toDouble(), 0.05); + assertEquals(40.0, vehicleRoute.getEnd().getEndTime(),0.05); + assertEquals(50.0, vehicleRoute.getEnd().getTheoreticalLatestOperationStartTime(),0.05); + } + +} diff --git a/jsprit-core/src/test/java/algorithms/TestTourStateUpdaterWithService.java b/jsprit-core/src/test/java/algorithms/TestTourStateUpdaterWithService.java index 33f4aa4e..08f9f570 100644 --- a/jsprit-core/src/test/java/algorithms/TestTourStateUpdaterWithService.java +++ b/jsprit-core/src/test/java/algorithms/TestTourStateUpdaterWithService.java @@ -119,14 +119,14 @@ public class TestTourStateUpdaterWithService { @Test public void testCalculatedCost() { - tdTourStatusProcessor.updateRoute(vehicleRoute); + tdTourStatusProcessor.iterate(vehicleRoute); assertEquals(40.0, states.getRouteState(vehicleRoute).getCosts(), 0.05); assertEquals(10, states.getRouteState(vehicleRoute).getLoad()); } @Test public void testStatesOfAct0(){ - tdTourStatusProcessor.updateRoute(vehicleRoute); + tdTourStatusProcessor.iterate(vehicleRoute); assertEquals(0.0, vehicleRoute.getStart().getEndTime(),0.05); assertEquals(vehicleRoute.getVehicle().getLocationId(), vehicleRoute.getStart().getLocationId()); assertEquals(vehicleRoute.getVehicle().getEarliestDeparture(), vehicleRoute.getStart().getTheoreticalEarliestOperationStartTime(),0.05); @@ -136,7 +136,7 @@ public class TestTourStateUpdaterWithService { @Test public void testStatesOfAct1(){ - tdTourStatusProcessor.updateRoute(vehicleRoute); + tdTourStatusProcessor.iterate(vehicleRoute); assertEquals(10.0, states.getState(tour.getActivities().get(0)).getCurrentCost(),0.05); assertEquals(5.0, states.getState(tour.getActivities().get(0)).getCurrentLoad(),0.05); assertEquals(10.0, states.getState(tour.getActivities().get(0)).getEarliestOperationStart(),0.05); @@ -145,7 +145,7 @@ public class TestTourStateUpdaterWithService { @Test public void testStatesOfAct2(){ - tdTourStatusProcessor.updateRoute(vehicleRoute); + tdTourStatusProcessor.iterate(vehicleRoute); assertEquals(30.0, states.getState(tour.getActivities().get(1)).getCurrentCost(),0.05); assertEquals(10.0, states.getState(tour.getActivities().get(1)).getCurrentLoad(),0.05); assertEquals(30.0, states.getState(tour.getActivities().get(1)).getEarliestOperationStart(),0.05); @@ -154,7 +154,7 @@ public class TestTourStateUpdaterWithService { @Test public void testStatesOfAct3(){ - tdTourStatusProcessor.updateRoute(vehicleRoute); + tdTourStatusProcessor.iterate(vehicleRoute); assertEquals(40.0, states.getRouteState(vehicleRoute).getCosts(), 0.05); assertEquals(40.0, vehicleRoute.getEnd().getEndTime(),0.05); assertEquals(50.0, vehicleRoute.getEnd().getTheoreticalLatestOperationStartTime(),0.05); diff --git a/jsprit-examples/input/algorithmConfig.xml b/jsprit-examples/input/algorithmConfig.xml index dd27c419..5c495768 100755 --- a/jsprit-examples/input/algorithmConfig.xml +++ b/jsprit-examples/input/algorithmConfig.xml @@ -25,7 +25,9 @@ 10000 - + + route +