diff --git a/README.md b/README.md index 5b77fca7..bc154757 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ It is lightweight and easy-to-use, and based on heuristics currently solving - Multiple Depot VRP - VRP with Time Windows - VRP with Backhauls -- VRP with Pickups and Deliveries - VRP with Heterogeneous Fleet - Time-dependent VRP - Various combination of these types @@ -21,6 +20,8 @@ can be used, and a dynamic and interactive visualiser greatly enhances the analy ##In Development - continues improvement of code, handling and performance - stable API to easily build algorithms from scratch +- VRP with pickups and deliveries +- release 1.0.0 ##Documentation diff --git a/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java b/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java index 01476de8..77de2a5a 100644 --- a/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java +++ b/jsprit-analysis/src/main/java/analysis/SolutionPrinter.java @@ -65,7 +65,10 @@ public class SolutionPrinter { * * @param solution * @param level + * + * @deprecated is not going to work anymore */ + @Deprecated public static void print(VehicleRoutingProblemSolution solution, Print level){ if(level.equals(Print.CONCISE)){ print(solution); diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index 39ad5986..80a1cd52 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -50,6 +50,7 @@ xerces xerces 2.4.0 + compile diff --git a/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java b/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java new file mode 100644 index 00000000..04f9cc8d --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * 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 + ******************************************************************************/ +/* *********************************************************************** * + * project: org.matsim.* + * IniSolution.java + * * + * *********************************************************************** * + * * + * copyright : (C) 2011 by the members listed in the COPYING, * + * LICENSE and WARRANTY file. * + * email : info at matsim dot org * + * * + * *********************************************************************** * + * * + * 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. * + * See also COPYING, LICENSE and WARRANTY file * + * * + * *********************************************************************** */ + +package algorithms; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import basics.Job; +import basics.VehicleRoutingProblem; +import basics.VehicleRoutingProblemSolution; +import basics.algo.SolutionCostCalculator; +import basics.route.DriverImpl; +import basics.route.TourActivities; +import basics.route.Vehicle; +import basics.route.VehicleRoute; + + + +final class CreateInitialSolution implements InitialSolutionFactory { + + private static final Logger logger = Logger.getLogger(CreateInitialSolution.class); + + private final InsertionStrategy insertion; + + private SolutionCostCalculator solutionCostCalculator; + + private boolean generateAsMuchAsRoutesAsVehiclesExist = false; + + public void setGenerateAsMuchAsRoutesAsVehiclesExist(boolean generateAsMuchAsRoutesAsVehiclesExist) { + this.generateAsMuchAsRoutesAsVehiclesExist = generateAsMuchAsRoutesAsVehiclesExist; + } + + public CreateInitialSolution(InsertionStrategy insertionStrategy, SolutionCostCalculator solutionCostCalculator) { + super(); + this.insertion = insertionStrategy; + this.solutionCostCalculator = solutionCostCalculator; + } + + @Override + public VehicleRoutingProblemSolution createSolution(final VehicleRoutingProblem vrp) { + logger.info("create initial solution."); + List vehicleRoutes = new ArrayList(); + if(generateAsMuchAsRoutesAsVehiclesExist){ + for(Vehicle vehicle : vrp.getVehicles()){ + vehicleRoutes.add(VehicleRoute.newInstance(TourActivities.emptyTour(), DriverImpl.noDriver(), vehicle)); + } + } + insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp)); +// double totalCost = getTotalCost(vehicleRoutes); + logger.info("creation done"); + VehicleRoutingProblemSolution vehicleRoutingProblemSolution = new VehicleRoutingProblemSolution(vehicleRoutes, 0.0); + solutionCostCalculator.calculateCosts(vehicleRoutingProblemSolution); + return vehicleRoutingProblemSolution; + } + + private List getUnassignedJobs(VehicleRoutingProblem vrp) { + List jobs = new ArrayList(vrp.getJobs().values()); + return jobs; + } + +} diff --git a/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java b/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java index 23741a97..effdc414 100644 --- a/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java +++ b/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java @@ -49,13 +49,8 @@ public class RuinAndRecreateModule implements SearchStrategyModule{ public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { Collection ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs); - scoreSolution(vrpSolution); return vrpSolution; - } - private void scoreSolution(VehicleRoutingProblemSolution vrpSolution) { - double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); - vrpSolution.setCost(totalCost); } @Override diff --git a/jsprit-core/src/main/java/algorithms/StateManager.java b/jsprit-core/src/main/java/algorithms/StateManager.java index b3438681..3324ca48 100644 --- a/jsprit-core/src/main/java/algorithms/StateManager.java +++ b/jsprit-core/src/main/java/algorithms/StateManager.java @@ -33,8 +33,10 @@ public interface StateManager { double toDouble(); } + State getActivityState(TourActivity act, StateId stateId); - + State getRouteState(VehicleRoute route, StateId stateId); + } diff --git a/jsprit-core/src/main/java/algorithms/StateUpdates.java b/jsprit-core/src/main/java/algorithms/StateUpdates.java index c85d7d92..303553a5 100644 --- a/jsprit-core/src/main/java/algorithms/StateUpdates.java +++ b/jsprit-core/src/main/java/algorithms/StateUpdates.java @@ -20,24 +20,332 @@ ******************************************************************************/ package algorithms; -import java.util.ArrayList; import java.util.Collection; - import basics.Job; -import basics.VehicleRoutingProblem; -import basics.VehicleRoutingProblemSolution; -import basics.algo.InsertionStartsListener; -import basics.algo.IterationStartsListener; import basics.algo.JobInsertedListener; import basics.algo.RuinListener; import basics.costs.VehicleRoutingActivityCosts; import basics.costs.VehicleRoutingTransportCosts; import basics.route.VehicleRoute; -public class StateUpdates { + +class StateUpdates { - public static class UpdateStates implements JobInsertedListener, RuinListener{ +// static class UpdateCostsAtRouteLevel implements JobInsertedListener, InsertionStartsListener, InsertionEndsListener{ +// +// private StateManagerImpl states; +// +// private VehicleRoutingTransportCosts tpCosts; +// +// private VehicleRoutingActivityCosts actCosts; +// +// public UpdateCostsAtRouteLevel(StateManagerImpl 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); +// double oldCosts = states.getRouteState(inRoute, StateTypes.COSTS).toDouble(); +// oldCosts += additionalCosts; +// states.putRouteState(inRoute, StateTypes.COSTS, new StateImpl(oldCosts)); +// } +// +// @Override +// public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { +// RouteActivityVisitor forwardInTime = new RouteActivityVisitor(); +// forwardInTime.addActivityVisitor(new UpdateCostsAtAllLevels(actCosts, tpCosts, states)); +// for(VehicleRoute route : vehicleRoutes){ +// forwardInTime.visit(route); +// } +// +// } +// +// @Override +// public void informInsertionEnds(Collection vehicleRoutes) { +// +//// IterateRouteForwardInTime forwardInTime = new IterateRouteForwardInTime(tpCosts); +//// forwardInTime.addListener(new UpdateCostsAtAllLevels(actCosts, tpCosts, states)); +//// for(VehicleRoute route : vehicleRoutes){ +//// if(route.isEmpty()) continue; +//// route.getVehicleRouteCostCalculator().reset(); +//// route.getVehicleRouteCostCalculator().addOtherCost(states.getRouteState(route, StateTypes.COSTS).toDouble()); +//// route.getVehicleRouteCostCalculator().price(route.getVehicle()); +//// forwardInTime.iterate(route); +//// } +// +// } +// +// } +// +// static class UpdateActivityTimes implements ActivityVisitor{ +// +// private Logger log = Logger.getLogger(UpdateActivityTimes.class); +// +// private ActivityTimeTracker timeTracker; +// +// private VehicleRoute route; +// +// public UpdateActivityTimes(ForwardTransportTime transportTime) { +// super(); +// timeTracker = new ActivityTimeTracker(transportTime); +// } +// +// @Override +// public void begin(VehicleRoute route) { +// timeTracker.begin(route); +// this.route = route; +// route.getStart().setEndTime(timeTracker.getActEndTime()); +// } +// +// @Override +// public void visit(TourActivity activity) { +// timeTracker.visit(activity); +// activity.setArrTime(timeTracker.getActArrTime()); +// activity.setEndTime(timeTracker.getActEndTime()); +// } +// +// @Override +// public void finish() { +// timeTracker.finish(); +// route.getEnd().setArrTime(timeTracker.getActArrTime()); +// } +// +// } +// +// static class UpdateCostsAtAllLevels implements ActivityVisitor{ +// +// private static Logger log = Logger.getLogger(UpdateCostsAtAllLevels.class); +// +// private VehicleRoutingActivityCosts activityCost; +// +// private ForwardTransportCost transportCost; +// +// private StateManagerImpl states; +// +// private double totalOperationCost = 0.0; +// +// private VehicleRoute vehicleRoute = null; +// +// private TourActivity prevAct = null; +// +// private double startTimeAtPrevAct = 0.0; +// +// private ActivityTimeTracker timeTracker; +// +// public UpdateCostsAtAllLevels(VehicleRoutingActivityCosts activityCost, VehicleRoutingTransportCosts transportCost, StateManagerImpl states) { +// super(); +// this.activityCost = activityCost; +// this.transportCost = transportCost; +// this.states = states; +// timeTracker = new ActivityTimeTracker(transportCost); +// } +// +// @Override +// public void begin(VehicleRoute route) { +// vehicleRoute = route; +// vehicleRoute.getVehicleRouteCostCalculator().reset(); +// timeTracker.begin(route); +// prevAct = route.getStart(); +// startTimeAtPrevAct = timeTracker.getActEndTime(); +// } +// +// @Override +// public void visit(TourActivity act) { +// timeTracker.visit(act); +// +// double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), act.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); +// double actCost = activityCost.getActivityCost(act, timeTracker.getActArrTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle()); +// +//// vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); +//// vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); +// +// totalOperationCost += transportCost; +// totalOperationCost += actCost; +// +// states.putActivityState(act, StateTypes.COSTS, new StateImpl(totalOperationCost)); +// +// prevAct = act; +// startTimeAtPrevAct = timeTracker.getActEndTime(); +// } +// +// @Override +// public void finish() { +// timeTracker.finish(); +// double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), vehicleRoute.getEnd().getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); +// double actCost = activityCost.getActivityCost(vehicleRoute.getEnd(), timeTracker.getActEndTime(), vehicleRoute.getDriver(), vehicleRoute.getVehicle()); +// +//// vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); +//// vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); +// +// totalOperationCost += transportCost; +// totalOperationCost += actCost; +// totalOperationCost += getFixCosts(); +// +// 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; +// } +// +// private double getFixCosts() { +// Vehicle vehicle = vehicleRoute.getVehicle(); +// if(vehicle == null) return 0.0; +// VehicleType type = vehicle.getType(); +// if(type == null) return 0.0; +// return type.getVehicleCostParams().fix; +// } +// +// } +// +// static class UpdateEarliestStartTimeWindowAtActLocations implements ActivityVisitor{ +// +// private StateManagerImpl states; +// +// private ActivityTimeTracker timeTracker; +// +// public UpdateEarliestStartTimeWindowAtActLocations(StateManagerImpl states, VehicleRoutingTransportCosts transportCosts) { +// super(); +// this.states = states; +// timeTracker = new ActivityTimeTracker(transportCosts); +// } +// +// @Override +// public void begin(VehicleRoute route) { +// timeTracker.begin(route); +// } +// +// @Override +// public void visit(TourActivity activity) { +// timeTracker.visit(activity); +// states.putActivityState(activity, StateTypes.EARLIEST_OPERATION_START_TIME, new StateImpl(Math.max(timeTracker.getActArrTime(), activity.getTheoreticalEarliestOperationStartTime()))); +// +// } +// +// @Override +// public void finish() {} +// +// } +// +// static class UpdateLatestOperationStartTimeAtActLocations implements ReverseActivityVisitor{ +// +// private static Logger log = Logger.getLogger(UpdateLatestOperationStartTimeAtActLocations.class); +// +// private StateManagerImpl states; +// +// private VehicleRoute route; +// +// private VehicleRoutingTransportCosts transportCosts; +// +// private double latestArrTimeAtPrevAct; +// +// private TourActivity prevAct; +// +// public UpdateLatestOperationStartTimeAtActLocations(StateManagerImpl states, VehicleRoutingTransportCosts tpCosts) { +// super(); +// this.states = states; +// this.transportCosts = tpCosts; +// } +// +// @Override +// public void begin(VehicleRoute route) { +// this.route = route; +// latestArrTimeAtPrevAct = route.getEnd().getTheoreticalLatestOperationStartTime(); +// prevAct = route.getEnd(); +// } +// +// @Override +// public void visit(TourActivity activity) { +// double potentialLatestArrivalTimeAtCurrAct = latestArrTimeAtPrevAct - transportCosts.getBackwardTransportTime(activity.getLocationId(), prevAct.getLocationId(), latestArrTimeAtPrevAct, route.getDriver(),route.getVehicle()) - activity.getOperationTime(); +// double latestArrivalTime = Math.min(activity.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct); +// +// states.putActivityState(activity, StateTypes.LATEST_OPERATION_START_TIME, new StateImpl(latestArrivalTime)); +// +// latestArrTimeAtPrevAct = latestArrivalTime; +// prevAct = activity; +// } +// +// @Override +// public void finish() {} +// } +// +// static class UpdateLoadAtAllLevels implements ActivityVisitor{ +// +// private double load = 0.0; +// +// private StateManagerImpl states; +// +// private VehicleRoute vehicleRoute; +// +// public UpdateLoadAtAllLevels(StateManagerImpl states) { +// super(); +// this.states = states; +// } +// +// @Override +// public void begin(VehicleRoute route) { +// vehicleRoute = route; +// } +// +// @Override +// public void visit(TourActivity activity) { +// load += (double)activity.getCapacityDemand(); +// states.putActivityState(activity, StateTypes.LOAD, new StateImpl(load)); +// } +// +// @Override +// public void finish() { +// states.putRouteState(vehicleRoute, StateTypes.LOAD, new StateImpl(load)); +// load=0; +// vehicleRoute = null; +// } +// +// } +// +// static class UpdateLoadAtRouteLevel implements JobInsertedListener, InsertionStartsListener{ +// +// private StateManagerImpl states; +// +// public UpdateLoadAtRouteLevel(StateManagerImpl 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)); +// } +// +// } +// +// } +// + static class UpdateStates implements JobInsertedListener, RuinListener{ private RouteActivityVisitor routeActivityVisitor; @@ -80,78 +388,157 @@ public class StateUpdates { public void removed(Job job, VehicleRoute fromRoute) {} } +// +// static class UpdateFuturePickupsAtActivityLevel implements ReverseActivityVisitor { +// private StateManagerImpl stateManager; +// private int futurePicks = 0; +// private VehicleRoute route; +// +// public UpdateFuturePickupsAtActivityLevel(StateManagerImpl stateManager) { +// super(); +// this.stateManager = stateManager; +// } +// +// @Override +// public void begin(VehicleRoute route) { +// this.route = route; +// } +// +// @Override +// public void visit(TourActivity act) { +// stateManager.putActivityState(act, StateTypes.FUTURE_PICKS, new StateImpl(futurePicks)); +// if(act instanceof PickupActivity || act instanceof ServiceActivity){ +// futurePicks += act.getCapacityDemand(); +// } +// assert futurePicks <= route.getVehicle().getCapacity() : "sum of pickups must not be > vehicleCap"; +// assert futurePicks >= 0 : "sum of pickups must not < 0"; +// } +// +// @Override +// public void finish() { +// futurePicks = 0; +// route = null; +// } +// } +// +// static class UpdateOccuredDeliveriesAtActivityLevel implements ActivityVisitor { +// private StateManagerImpl stateManager; +// private int deliveries = 0; +// private VehicleRoute route; +// +// public UpdateOccuredDeliveriesAtActivityLevel(StateManagerImpl stateManager) { +// super(); +// this.stateManager = stateManager; +// } +// +// @Override +// public void begin(VehicleRoute route) { +// this.route = route; +// } +// +// @Override +// public void visit(TourActivity act) { +// if(act instanceof DeliveryActivity){ +// deliveries += Math.abs(act.getCapacityDemand()); +// } +// stateManager.putActivityState(act, StateTypes.PAST_DELIVERIES, new StateImpl(deliveries)); +// assert deliveries >= 0 : "deliveries < 0"; +// assert deliveries <= route.getVehicle().getCapacity() : "deliveries > vehicleCap"; +// } +// +// @Override +// public void finish() { +// deliveries = 0; +// route = null; +// } +// } +// +// /** +// * Updates load at activity level. Note that this assumed that StateTypes.LOAD_AT_DEPOT is already updated, i.e. it starts by setting loadAtDepot to StateTypes.LOAD_AT_DEPOT. +// * If StateTypes.LOAD_AT_DEPOT is not set, it starts with 0 load at depot. +// * +// * @author stefan +// * +// */ +// static class UpdateLoadAtActivityLevel implements ActivityVisitor { +// private StateManagerImpl stateManager; +// private int currentLoad = 0; +// private VehicleRoute route; +// +// public UpdateLoadAtActivityLevel(StateManagerImpl stateManager) { +// super(); +// this.stateManager = stateManager; +// } +// +// @Override +// public void begin(VehicleRoute route) { +// currentLoad = (int) stateManager.getRouteState(route, StateTypes.LOAD_AT_DEPOT).toDouble(); +// this.route = route; +// } +// +// @Override +// public void visit(TourActivity act) { +// currentLoad += act.getCapacityDemand(); +// stateManager.putActivityState(act, StateTypes.LOAD, new StateImpl(currentLoad)); +// assert currentLoad <= route.getVehicle().getCapacity() : "currentLoad at activity must not be > vehicleCapacity"; +// assert currentLoad >= 0 : "currentLoad at act must not be < 0"; +// } +// +// @Override +// public void finish() { +// currentLoad = 0; +// } +// } +// +// static class ResetStateManager implements IterationStartsListener { +// +// private StateManagerImpl stateManager; +// +// public ResetStateManager(StateManagerImpl stateManager) { +// super(); +// this.stateManager = stateManager; +// } +// +// @Override +// public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { +// stateManager.clear(); +// } +// } +// +// static interface InsertionStarts { +// +// void insertionStarts(VehicleRoute route); +// +// } +// +// static class UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts implements InsertionStarts { +// +// private StateManagerImpl stateManager; +// +// public UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(StateManagerImpl stateManager) { +// super(); +// this.stateManager = stateManager; +// } +// +// @Override +// public void insertionStarts(VehicleRoute route) { +// int loadAtDepot = 0; +// int loadAtEnd = 0; +// for(Job j : route.getTourActivities().getJobs()){ +// if(j instanceof Delivery){ +// loadAtDepot += j.getCapacityDemand(); +// } +// else if(j instanceof Pickup || j instanceof Service){ +// loadAtEnd += j.getCapacityDemand(); +// } +// } +// stateManager.putRouteState(route, StateTypes.LOAD_AT_DEPOT, new StateImpl(loadAtDepot)); +// stateManager.putRouteState(route, StateTypes.LOAD, new StateImpl(loadAtEnd)); +// } +// +// } +// - static class ResetStateManager implements IterationStartsListener { - - private StateManagerImpl stateManager; - - public ResetStateManager(StateManagerImpl stateManager) { - super(); - this.stateManager = stateManager; - } - - @Override - public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { - stateManager.clear(); - } - } - static interface InsertionStarts { - - void insertionStarts(VehicleRoute route); - - } - static class UpdateRouteStatesOnceTheRouteHasBeenChanged implements InsertionStartsListener, JobInsertedListener { - - private RouteActivityVisitor forwardInTimeIterator; - - private ReverseRouteActivityVisitor backwardInTimeIterator; - - private Collection insertionStartsListeners; - - private Collection jobInsertionListeners; - - public UpdateRouteStatesOnceTheRouteHasBeenChanged(VehicleRoutingTransportCosts routingCosts) { - forwardInTimeIterator = new RouteActivityVisitor(); - backwardInTimeIterator = new ReverseRouteActivityVisitor(); - insertionStartsListeners = new ArrayList(); - jobInsertionListeners = new ArrayList(); - } - - void addVisitor(ActivityVisitor vis){ - forwardInTimeIterator.addActivityVisitor(vis); - } - - void addVisitor(ReverseActivityVisitor revVis){ - backwardInTimeIterator.addActivityVisitor(revVis); - } - - void addInsertionStartsListener(InsertionStarts insertionStartListener){ - insertionStartsListeners.add(insertionStartListener); - } - - void addJobInsertedListener(JobInsertedListener jobInsertedListener){ - jobInsertionListeners.add(jobInsertedListener); - } - - @Override - public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { - for(JobInsertedListener l : jobInsertionListeners){ l.informJobInserted(job2insert, inRoute, additionalCosts, additionalTime); } - forwardInTimeIterator.visit(inRoute); - backwardInTimeIterator.visit(inRoute); - } - - @Override - public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { - for(VehicleRoute route : vehicleRoutes){ - for(InsertionStarts insertionsStartsHandler : insertionStartsListeners){ - insertionsStartsHandler.insertionStarts(route); - } - forwardInTimeIterator.visit(route); - backwardInTimeIterator.visit(route); - } - } - - } } diff --git a/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java b/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java index 87a2bd85..329cfe9a 100644 --- a/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java +++ b/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java @@ -7,6 +7,7 @@ import basics.costs.ForwardTransportCost; import basics.costs.VehicleRoutingActivityCosts; import basics.costs.VehicleRoutingTransportCosts; import basics.route.TourActivity; +import basics.route.Vehicle; import basics.route.VehicleRoute; /** @@ -98,6 +99,7 @@ public class UpdateCostsAtAllLevels implements ActivityVisitor{ totalOperationCost += transportCost; totalOperationCost += actCost; + totalOperationCost += getFixCosts(vehicleRoute.getVehicle()); states.putRouteState(vehicleRoute, StateIdFactory.COSTS, new StateImpl(totalOperationCost)); @@ -112,4 +114,10 @@ public class UpdateCostsAtAllLevels implements ActivityVisitor{ totalOperationCost = 0.0; } + private double getFixCosts(Vehicle vehicle) { + if(vehicle == null) return 0.0; + if(vehicle.getType() == null) return 0.0; + return vehicle.getType().getVehicleCostParams().fix; + } + } \ No newline at end of file diff --git a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java index 3446d59b..14db0ad1 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java @@ -35,6 +35,8 @@ import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; + + import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.InsertionStrategyKey; @@ -61,12 +63,14 @@ import basics.algo.SearchStrategy; import basics.algo.SearchStrategy.DiscoveredSolution; import basics.algo.SearchStrategyManager; import basics.algo.SearchStrategyModule; +import basics.algo.SolutionCostCalculator; import basics.algo.TimeBreaker; import basics.algo.VariationCoefficientBreaker; import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; import basics.algo.VehicleRoutingAlgorithmListeners.Priority; import basics.io.AlgorithmConfig; import basics.io.AlgorithmConfigXmlReader; +import basics.route.VehicleRoute; @@ -467,7 +471,8 @@ public class VehicleRoutingAlgorithms { String name = getName(strategyConfig); SolutionAcceptor acceptor = getAcceptor(strategyConfig,vrp,algorithmListeners,definedClasses,solutionMemory); SolutionSelector selector = getSelector(strategyConfig,vrp,algorithmListeners,definedClasses); - SearchStrategy strategy = new SearchStrategy(selector, acceptor); + SolutionCostCalculator costCalculator = getCostCalculator(stateManager); + SearchStrategy strategy = new SearchStrategy(selector, acceptor, costCalculator); strategy.setName(name); List modulesConfig = strategyConfig.configurationsAt("modules.module"); for(HierarchicalConfiguration moduleConfig : modulesConfig){ @@ -540,6 +545,21 @@ public class VehicleRoutingAlgorithms { return metaAlgorithm; } + private static SolutionCostCalculator getCostCalculator(final StateManagerImpl stateManager) { + SolutionCostCalculator calc = new SolutionCostCalculator() { + + @Override + public void calculateCosts(VehicleRoutingProblemSolution solution) { + double costs = 0.0; + for(VehicleRoute route : solution.getRoutes()){ + costs += stateManager.getRouteState(route, StateIdFactory.COSTS).toDouble(); + } + solution.setCost(costs); + } + }; + return calc; + } + private static VehicleFleetManager createFleetManager(final VehicleRoutingProblem vrp) { if(vrp.getFleetSize().equals(FleetSize.INFINITE)){ return new InfiniteVehicles(vrp.getVehicles()); @@ -619,7 +639,7 @@ public class VehicleRoutingAlgorithms { metaAlgorithm.getAlgorithmListeners().addAll(algorithmListeners); } - private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) { + private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, final StateManagerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) { List modConfigs = config.configurationsAt("construction.insertion"); if(modConfigs == null) return null; if(modConfigs.isEmpty()) return null; @@ -645,11 +665,11 @@ public class VehicleRoutingAlgorithms { @Override public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection solutions) { - BestInsertionInitialSolutionFactory createInitialSolution = new BestInsertionInitialSolutionFactory(finalInsertionStrategy); + CreateInitialSolution createInitialSolution = new CreateInitialSolution(finalInsertionStrategy, getCostCalculator(routeStates)); + createInitialSolution.setGenerateAsMuchAsRoutesAsVehiclesExist(false); VehicleRoutingProblemSolution vrpSol = createInitialSolution.createSolution(vrp); solutions.add(vrpSol); - } }; diff --git a/jsprit-core/src/main/java/basics/algo/SearchStrategy.java b/jsprit-core/src/main/java/basics/algo/SearchStrategy.java index 1140f5d0..a13ba263 100644 --- a/jsprit-core/src/main/java/basics/algo/SearchStrategy.java +++ b/jsprit-core/src/main/java/basics/algo/SearchStrategy.java @@ -68,15 +68,18 @@ public class SearchStrategy { private Collection searchStrategyModules = new ArrayList(); private SolutionSelector solutionSelector; + + private SolutionCostCalculator solutionCostCalculator; private SolutionAcceptor solutionAcceptor; private String name; - public SearchStrategy(SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor) { + public SearchStrategy(SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor, SolutionCostCalculator solutionCostCalculator) { super(); this.solutionSelector = solutionSelector; this.solutionAcceptor = solutionAcceptor; + this.solutionCostCalculator = solutionCostCalculator; logger.info("initialise " + this); } @@ -126,6 +129,7 @@ public class SearchStrategy { VehicleRoutingProblemSolution newSolution = module.runAndGetSolution(lastSolution); lastSolution = newSolution; } + solutionCostCalculator.calculateCosts(lastSolution); boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution); DiscoveredSolution discoveredSolution = new DiscoveredSolution(lastSolution, solutionAccepted, getName()); return discoveredSolution; diff --git a/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java b/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java new file mode 100644 index 00000000..0e7a148c --- /dev/null +++ b/jsprit-core/src/main/java/basics/algo/SolutionCostCalculator.java @@ -0,0 +1,14 @@ +package basics.algo; + +import basics.VehicleRoutingProblemSolution; + +public interface SolutionCostCalculator { + + /** + * This assumes that the solution is modified by setting its costs
+ * solution.setCost(costs); + * @param solution + */ + public void calculateCosts(VehicleRoutingProblemSolution solution); + +} diff --git a/jsprit-core/src/main/java/basics/route/VehicleRoute.java b/jsprit-core/src/main/java/basics/route/VehicleRoute.java index 95c8f3e0..7c1bb271 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/basics/route/VehicleRoute.java @@ -84,23 +84,14 @@ public class VehicleRoute { private End end; + @Deprecated private VehicleRouteCostCalculator costCalculator = new DefaultVehicleRouteCostCalculator(); - public void setVehicleRouteCostCalculator(VehicleRouteCostCalculator costAccumulator){ - this.costCalculator = costAccumulator; - } - + @Deprecated public VehicleRouteCostCalculator getVehicleRouteCostCalculator(){ return costCalculator; } - public double getCost() { - if(tourActivities.isEmpty()){ - return 0.0; - } - return costCalculator.getCosts(); - } - private VehicleRoute(VehicleRoute route){ this.start = Start.copyOf(route.getStart()); this.end = End.copyOf(route.getEnd()); @@ -192,5 +183,18 @@ public class VehicleRoute { public End getEnd() { return end; } + + @Deprecated + public void setVehicleRouteCostCalculator(VehicleRouteCostCalculator costAccumulator){ + this.costCalculator = costAccumulator; + } + + @Deprecated + public double getCost() { + if(tourActivities.isEmpty()){ + return 0.0; + } + return costCalculator.getCosts(); + } } diff --git a/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java b/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java index 5d956265..80ffa2aa 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java +++ b/jsprit-core/src/main/java/basics/route/VehicleRouteCostCalculator.java @@ -20,7 +20,7 @@ ******************************************************************************/ package basics.route; - +@Deprecated public interface VehicleRouteCostCalculator { public void addTransportCost(double cost); diff --git a/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java index aaef52e0..efae6259 100644 --- a/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java +++ b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java @@ -36,8 +36,10 @@ import basics.VehicleRoutingProblemSolution; import basics.algo.IterationStartsListener; import basics.algo.SearchStrategy; import basics.algo.SearchStrategyManager; +import basics.algo.SolutionCostCalculator; import basics.io.VrpXMLReader; import basics.route.TourActivity; +import basics.route.VehicleRoute; public class BuildCVRPAlgoFromScratchTest { @@ -70,11 +72,23 @@ public class BuildCVRPAlgoFromScratchTest { RuinRadial radial = new RuinRadial(vrp, 0.15, new JobDistanceAvgCosts(vrp.getTransportCosts())); RuinRandom random = new RuinRandom(vrp, 0.25); - SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() { + + @Override + public void calculateCosts(VehicleRoutingProblemSolution solution) { + double costs = 0.0; + for(VehicleRoute route : solution.getRoutes()){ + costs += stateManager.getRouteState(route, StateIdFactory.COSTS).toDouble(); + } + solution.setCost(costs); + } + }; + + SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule randomModule = new RuinAndRecreateModule("randomRuin_bestInsertion", bestInsertion, random); randomStrategy.addModule(randomModule); - SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule radialModule = new RuinAndRecreateModule("radialRuin_bestInsertion", bestInsertion, radial); radialStrategy.addModule(radialModule); @@ -98,7 +112,9 @@ public class BuildCVRPAlgoFromScratchTest { vra.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateCostsAtRouteLevel(stateManager, vrp.getTransportCosts(), vrp.getActivityCosts())); vra.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateLoadAtRouteLevel(stateManager)); - VehicleRoutingProblemSolution iniSolution = new BestInsertionInitialSolutionFactory(bestInsertion).createSolution(vrp); + + VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion, solutionCostCalculator).createSolution(vrp); + // System.out.println("ini: costs="+iniSolution.getCost()+";#routes="+iniSolution.getRoutes().size()); vra.addInitialSolution(iniSolution); diff --git a/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java index b97dddab..e404655c 100644 --- a/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java +++ b/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java @@ -39,6 +39,7 @@ import basics.algo.InsertionStartsListener; import basics.algo.JobInsertedListener; import basics.algo.SearchStrategy; import basics.algo.SearchStrategyManager; +import basics.algo.SolutionCostCalculator; import basics.io.VrpXMLReader; import basics.route.VehicleRoute; @@ -76,11 +77,23 @@ public class BuildPDVRPAlgoFromScratchTest { RuinRadial radial = new RuinRadial(vrp, 0.15, new JobDistanceAvgCosts(vrp.getTransportCosts())); RuinRandom random = new RuinRandom(vrp, 0.25); - SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() { + + @Override + public void calculateCosts(VehicleRoutingProblemSolution solution) { + double costs = 0.0; + for(VehicleRoute route : solution.getRoutes()){ + costs += stateManager.getRouteState(route, StateIdFactory.COSTS).toDouble(); + } + solution.setCost(costs); + } + }; + + SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule randomModule = new RuinAndRecreateModule("randomRuin_bestInsertion", bestInsertion, random); randomStrategy.addModule(randomModule); - SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1), solutionCostCalculator); RuinAndRecreateModule radialModule = new RuinAndRecreateModule("radialRuin_bestInsertion", bestInsertion, radial); radialStrategy.addModule(radialModule); @@ -156,7 +169,8 @@ public class BuildPDVRPAlgoFromScratchTest { bestInsertion.addListener(loadVehicleInDepot); bestInsertion.addListener(updateLoadAfterJobHasBeenInserted); - VehicleRoutingProblemSolution iniSolution = new BestInsertionInitialSolutionFactory(bestInsertion).createSolution(vrp); + VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion, solutionCostCalculator).createSolution(vrp); + // System.out.println("ini: costs="+iniSolution.getCost()+";#routes="+iniSolution.getRoutes().size()); vra.addInitialSolution(iniSolution); diff --git a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java index 64dc15b2..70edcf6c 100644 --- a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java +++ b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java @@ -187,7 +187,7 @@ public class GendreauPostOptTest { // routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); // routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); - VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, route.getCost()); + VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, states.getRouteState(route, StateIdFactory.COSTS).toDouble()); assertEquals(110.0, sol.getCost(), 0.5); @@ -202,12 +202,21 @@ public class GendreauPostOptTest { postOpt.setFleetManager(fleetManager); VehicleRoutingProblemSolution newSolution = postOpt.runAndGetSolution(sol); + newSolution.setCost(getCosts(newSolution,states)); assertEquals(2,RouteUtils.getNuOfActiveRoutes(newSolution.getRoutes())); assertEquals(2,newSolution.getRoutes().size()); assertEquals(80.0,newSolution.getCost(),0.5); } + private double getCosts(VehicleRoutingProblemSolution newSolution, StateManagerImpl states) { + double c = 0.0; + for(VehicleRoute r : newSolution.getRoutes()){ + c += states.getRouteState(r, StateIdFactory.COSTS).toDouble(); + } + return c; + } + @Test public void whenPostOpt_optsRoutesWithMoreThanTwoJobs_oneRouteBecomesTwoRoutes(){ Collection jobs = new ArrayList(); @@ -233,6 +242,7 @@ public class GendreauPostOptTest { routes.add(route); VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, route.getCost()); + sol.setCost(getCosts(sol,states)); assertEquals(110.0, sol.getCost(), 0.5); @@ -246,6 +256,7 @@ public class GendreauPostOptTest { postOpt.setFleetManager(fleetManager); // postOpt.setWithFix(withFixCost); VehicleRoutingProblemSolution newSolution = postOpt.runAndGetSolution(sol); + newSolution.setCost(getCosts(newSolution,states)); assertEquals(2,RouteUtils.getNuOfActiveRoutes(newSolution.getRoutes())); assertEquals(2,newSolution.getRoutes().size()); diff --git a/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java b/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java index 183f245b..abc56317 100644 --- a/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java +++ b/jsprit-core/src/test/java/basics/algo/SearchStrategyTest.java @@ -46,8 +46,9 @@ public class SearchStrategyTest { public void whenANullModule_IsAdded_throwException(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); strat.addModule(null); } @@ -56,6 +57,7 @@ public class SearchStrategyTest { public void whenStratRunsWithOneModule_runItOnes(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); final VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); final VehicleRoutingProblemSolution newSol = mock(VehicleRoutingProblemSolution.class); @@ -64,7 +66,7 @@ public class SearchStrategyTest { final Collection runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); SearchStrategyModule mod = new SearchStrategyModule() { @Override @@ -96,6 +98,7 @@ public class SearchStrategyTest { public void whenStratRunsWithTwoModule_runItTwice(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); final VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); final VehicleRoutingProblemSolution newSol = mock(VehicleRoutingProblemSolution.class); @@ -104,7 +107,7 @@ public class SearchStrategyTest { final Collection runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); SearchStrategyModule mod = new SearchStrategyModule() { @@ -159,6 +162,7 @@ public class SearchStrategyTest { public void whenStratRunsWithNModule_runItNTimes(){ SolutionSelector select = mock(SolutionSelector.class); SolutionAcceptor accept = mock(SolutionAcceptor.class); + SolutionCostCalculator calc = mock(SolutionCostCalculator.class); final VehicleRoutingProblem vrp = mock(VehicleRoutingProblem.class); final VehicleRoutingProblemSolution newSol = mock(VehicleRoutingProblemSolution.class); @@ -169,7 +173,7 @@ public class SearchStrategyTest { final Collection runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); for(int i=0;i runs = new ArrayList(); - SearchStrategy strat = new SearchStrategy(select, accept); + SearchStrategy strat = new SearchStrategy(select, accept, calc); for(int i=0;i