From 26219aa3a1af99efef3436a707b9ba211dbef4f9 Mon Sep 17 00:00:00 2001 From: Stefan Schroeder <4sschroeder@gmail.com> Date: Mon, 2 Sep 2013 17:21:51 +0200 Subject: [PATCH] modify classes such than they can cope with pickup and deliveries --- .../java/algorithms/CalculatorBuilder.java | 15 +- .../src/main/java/algorithms/Gendreau.java | 19 +- .../main/java/algorithms/HardConstraints.java | 74 +++++-- .../java/algorithms/InsertionFactory.java | 12 +- .../main/java/algorithms/StateUpdates.java | 94 ++++++++- .../algorithms/VehicleRoutingAlgorithms.java | 182 +++++++++--------- .../BuildPDVRPAlgoFromScratchTest.java | 4 +- .../java/algorithms/GendreauPostOptTest.java | 2 +- .../TestCalculatesServiceInsertion.java | 2 +- .../examples/RefuseCollectionExample.java | 2 +- 10 files changed, 283 insertions(+), 123 deletions(-) diff --git a/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java b/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java index 97e8fba6..0a3898a2 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java +++ b/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java @@ -23,6 +23,7 @@ package algorithms; import java.util.ArrayList; import java.util.List; +import algorithms.HardConstraints.ConstraintManager; import basics.VehicleRoutingProblem; import basics.algo.InsertionListener; import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; @@ -81,6 +82,8 @@ class CalculatorBuilder { private double timeSlice; private int neighbors; + + private ConstraintManager constraintManager; /** * Constructs the builder. @@ -213,9 +216,11 @@ class CalculatorBuilder { } } - private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager activityStates2){ - MarginalsCalculus defaultCalc = new MarginalsCalculusTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts(), new HardConstraints.HardTimeWindowConstraint(activityStates2, vrp.getTransportCosts()) ); - JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), defaultCalc, new HardConstraints.HardLoadConstraint(activityStates2)); + private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager statesManager){ + if(constraintManager == null) throw new IllegalStateException("constraint-manager is null"); + + MarginalsCalculus defaultCalc = new MarginalsCalculusTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts(), constraintManager); + JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), defaultCalc, constraintManager); ((CalculatesServiceInsertion) standardServiceInsertion).setNeighborhood(vrp.getNeighborhood()); CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(standardServiceInsertion); @@ -246,6 +251,10 @@ class CalculatorBuilder { return new CalculatesVehTypeDepServiceInsertion(fleetManager, baseCalc); } + public void setConstraintManager(ConstraintManager constraintManager) { + this.constraintManager = constraintManager; + } + } diff --git a/jsprit-core/src/main/java/algorithms/Gendreau.java b/jsprit-core/src/main/java/algorithms/Gendreau.java index 70125dc4..183b9a1e 100644 --- a/jsprit-core/src/main/java/algorithms/Gendreau.java +++ b/jsprit-core/src/main/java/algorithms/Gendreau.java @@ -32,9 +32,11 @@ import java.util.Set; import org.apache.log4j.Logger; import util.RandomNumberGeneration; +import algorithms.RuinStrategy.RuinListener; import basics.Job; import basics.VehicleRoutingProblem; import basics.VehicleRoutingProblemSolution; +import basics.algo.InsertionListener; import basics.algo.SearchStrategyModule; import basics.algo.SearchStrategyModuleListener; import basics.route.TourActivity; @@ -53,8 +55,6 @@ final class Gendreau implements SearchStrategyModule{ private final InsertionStrategy insertionStrategy; - private final Inserter inserter; - private VehicleFleetManager fleetManager; private Random random = RandomNumberGeneration.getRandom(); @@ -71,7 +71,7 @@ final class Gendreau implements SearchStrategyModule{ super(); InsertionListeners insertionListeners = new InsertionListeners(); insertionListeners.addAllListeners(insertionStrategy.getListeners()); - inserter = new Inserter(insertionListeners); + new Inserter(insertionListeners); this.ruin = ruin; this.vrp = vrp; this.insertionStrategy = insertionStrategy; @@ -205,7 +205,18 @@ final class Gendreau implements SearchStrategyModule{ @Override public void addModuleListener(SearchStrategyModuleListener moduleListener) { - // TODO Auto-generated method stub + if(moduleListener instanceof InsertionListener){ + InsertionListener iListener = (InsertionListener) moduleListener; + if(!insertionStrategy.getListeners().contains(iListener)){ + insertionStrategy.addListener(iListener); + } + } + if(moduleListener instanceof RuinListener){ + RuinListener rListener = (RuinListener) moduleListener; + if(!ruin.getListeners().contains(rListener)){ + ruin.addListener(rListener); + } + } } } diff --git a/jsprit-core/src/main/java/algorithms/HardConstraints.java b/jsprit-core/src/main/java/algorithms/HardConstraints.java index 656dbad1..17b18676 100644 --- a/jsprit-core/src/main/java/algorithms/HardConstraints.java +++ b/jsprit-core/src/main/java/algorithms/HardConstraints.java @@ -11,9 +11,24 @@ import basics.Service; import basics.costs.VehicleRoutingTransportCosts; import basics.route.DeliveryActivity; import basics.route.PickupActivity; +import basics.route.ServiceActivity; import basics.route.Start; import basics.route.TourActivity; +/** + * collection of hard constrainters bot at activity and at route level. + * + *

HardPickupAndDeliveryLoadConstraint requires LOAD_AT_DEPOT and LOAD (i.e. load at end) at route-level + * + *

HardTimeWindowConstraint requires LATEST_OPERATION_START_TIME + * + *

HardPickupAndDeliveryConstraint requires LOAD_AT_DEPOT and LOAD at route-level and FUTURE_PICKS and PAST_DELIVIERS on activity-level + * + *

HardPickupAndDeliveryBackhaulConstraint requires LOAD_AT_DEPOT and LOAD at route-level and FUTURE_PICKS and PAST_DELIVIERS on activity-level + * + * @author stefan + * + */ class HardConstraints { interface HardRouteLevelConstraint { @@ -48,7 +63,31 @@ class HardConstraints { } - + static class ConstraintManager implements HardActivityLevelConstraint, HardRouteLevelConstraint{ + + private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager(); + + private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager(); + + public void addConstraint(HardActivityLevelConstraint actLevelConstraint){ + actLevelConstraintManager.addConstraint(actLevelConstraint); + } + + public void addConstraint(HardRouteLevelConstraint routeLevelConstraint){ + routeLevelConstraintManager.addConstraint(routeLevelConstraint); + } + + @Override + public boolean fulfilled(InsertionContext insertionContext) { + return routeLevelConstraintManager.fulfilled(insertionContext); + } + + @Override + public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + return actLevelConstraintManager.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); + } + + } static class HardActivityLevelConstraintManager implements HardActivityLevelConstraint { @@ -90,6 +129,12 @@ class HardConstraints { } } + /** + * lsjdfjsdlfjsa + * + * @author stefan + * + */ static class HardPickupAndDeliveryLoadConstraint implements HardRouteLevelConstraint { private StateManager stateManager; @@ -107,7 +152,7 @@ class HardConstraints { return false; } } - else if(insertionContext.getJob() instanceof Pickup){ + else if(insertionContext.getJob() instanceof Pickup || insertionContext.getJob() instanceof Service){ int loadAtEnd = (int) stateManager.getRouteState(insertionContext.getRoute(), StateTypes.LOAD).toDouble(); if(loadAtEnd + insertionContext.getJob().getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){ return false; @@ -118,15 +163,20 @@ class HardConstraints { } - static class HardTimeWindowConstraint implements HardActivityLevelConstraint { + /** + * ljsljslfjs + * @author stefan + * + */ + public static class HardTimeWindowActivityLevelConstraint implements HardActivityLevelConstraint { - private static Logger log = Logger.getLogger(HardTimeWindowConstraint.class); + private static Logger log = Logger.getLogger(HardTimeWindowActivityLevelConstraint.class); private StateManager states; private VehicleRoutingTransportCosts routingCosts; - public HardTimeWindowConstraint(StateManager states, VehicleRoutingTransportCosts routingCosts) { + public HardTimeWindowActivityLevelConstraint(StateManager states, VehicleRoutingTransportCosts routingCosts) { super(); this.states = states; this.routingCosts = routingCosts; @@ -152,11 +202,11 @@ class HardConstraints { } } - static class HardPickupAndDeliveryConstraint implements HardActivityLevelConstraint { + static class HardPickupAndDeliveryActivityLevelConstraint implements HardActivityLevelConstraint { private StateManager stateManager; - public HardPickupAndDeliveryConstraint(StateManager stateManager) { + public HardPickupAndDeliveryActivityLevelConstraint(StateManager stateManager) { super(); this.stateManager = stateManager; } @@ -176,7 +226,7 @@ class HardConstraints { futurePicks = (int) stateManager.getActivityState(prevAct, StateTypes.FUTURE_PICKS).toDouble(); pastDeliveries = (int) stateManager.getActivityState(prevAct, StateTypes.PAST_DELIVERIES).toDouble(); } - if(newAct instanceof PickupActivity){ + if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){ if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){ return false; } @@ -192,11 +242,11 @@ class HardConstraints { } - static class HardPickupAndDeliveryBackhaulConstraint implements HardActivityLevelConstraint { + static class HardPickupAndDeliveryBackhaulActivityLevelConstraint implements HardActivityLevelConstraint { private StateManager stateManager; - public HardPickupAndDeliveryBackhaulConstraint(StateManager stateManager) { + public HardPickupAndDeliveryBackhaulActivityLevelConstraint(StateManager stateManager) { super(); this.stateManager = stateManager; } @@ -204,7 +254,9 @@ class HardConstraints { @Override public boolean fulfilled(InsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { if(newAct instanceof PickupActivity && nextAct instanceof DeliveryActivity){ return false; } + if(newAct instanceof ServiceActivity && nextAct instanceof DeliveryActivity){ return false; } if(newAct instanceof DeliveryActivity && prevAct instanceof PickupActivity){ return false; } + if(newAct instanceof DeliveryActivity && prevAct instanceof ServiceActivity){ return false; } int loadAtPrevAct; int futurePicks; int pastDeliveries; @@ -218,7 +270,7 @@ class HardConstraints { futurePicks = (int) stateManager.getActivityState(prevAct, StateTypes.FUTURE_PICKS).toDouble(); pastDeliveries = (int) stateManager.getActivityState(prevAct, StateTypes.PAST_DELIVERIES).toDouble(); } - if(newAct instanceof PickupActivity){ + if(newAct instanceof PickupActivity || newAct instanceof ServiceActivity){ if(loadAtPrevAct + newAct.getCapacityDemand() + futurePicks > iFacts.getNewVehicle().getCapacity()){ return false; } diff --git a/jsprit-core/src/main/java/algorithms/InsertionFactory.java b/jsprit-core/src/main/java/algorithms/InsertionFactory.java index 402d0e98..182efa0f 100644 --- a/jsprit-core/src/main/java/algorithms/InsertionFactory.java +++ b/jsprit-core/src/main/java/algorithms/InsertionFactory.java @@ -27,6 +27,7 @@ import java.util.concurrent.ExecutorService; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.log4j.Logger; +import algorithms.HardConstraints.ConstraintManager; import algorithms.StateUpdates.UpdateStates; import basics.VehicleRoutingProblem; import basics.algo.InsertionListener; @@ -37,7 +38,7 @@ class InsertionFactory { private static Logger log = Logger.getLogger(InsertionFactory.class); public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config, - VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads){ + VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager){ boolean concurrentInsertion = false; if(executorService != null) concurrentInsertion = true; if(config.containsKey("[@name]")){ @@ -53,6 +54,7 @@ class InsertionFactory { calcBuilder.setStates(routeStates); calcBuilder.setVehicleRoutingProblem(vrp); calcBuilder.setVehicleFleetManager(vehicleFleetManager); + calcBuilder.setConstraintManager(constraintManager); if(config.containsKey("level")){ String level = config.getString("level"); @@ -102,13 +104,13 @@ class InsertionFactory { // insertionStrategy = RegretInsertion.newInstance(routeAlgorithm); // } - insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager)); - insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager)); - insertionStrategy.addListener(new VehicleSwitched(vehicleFleetManager)); +// insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager)); +// insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager)); +// insertionStrategy.addListener(new VehicleSwitched(vehicleFleetManager)); // insertionStrategy.addListener(new UpdateLoadAtRouteLevel(routeStates)); - insertionStrategy.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); +// 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/StateUpdates.java b/jsprit-core/src/main/java/algorithms/StateUpdates.java index 9c7d4054..23a6e836 100644 --- a/jsprit-core/src/main/java/algorithms/StateUpdates.java +++ b/jsprit-core/src/main/java/algorithms/StateUpdates.java @@ -11,7 +11,9 @@ import algorithms.BackwardInTimeListeners.BackwardInTimeListener; import algorithms.ForwardInTimeListeners.ForwardInTimeListener; import algorithms.RuinStrategy.RuinListener; import algorithms.StateManager.StateImpl; +import basics.Delivery; import basics.Job; +import basics.Pickup; import basics.Service; import basics.VehicleRoutingProblem; import basics.VehicleRoutingProblemSolution; @@ -27,6 +29,7 @@ import basics.costs.VehicleRoutingTransportCosts; import basics.route.DeliveryActivity; import basics.route.End; import basics.route.PickupActivity; +import basics.route.ServiceActivity; import basics.route.Start; import basics.route.TourActivity; import basics.route.VehicleRoute; @@ -444,7 +447,7 @@ class StateUpdates { @Override public void prevActivity(TourActivity act, double latestDepartureTime, double latestOperationStartTime) { stateManager.putActivityState(act, StateTypes.FUTURE_PICKS, new StateImpl(futurePicks)); - if(act instanceof PickupActivity){ + if(act instanceof PickupActivity || act instanceof ServiceActivity){ futurePicks += act.getCapacityDemand(); } assert futurePicks <= route.getVehicle().getCapacity() : "sum of pickups must not be > vehicleCap"; @@ -542,15 +545,79 @@ class StateUpdates { } } - static class WalkThroughAndUpdateRoutesOnceTheyChanged implements InsertionStartsListener, JobInsertedListener { + 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 UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted implements JobInsertedListener { + + private StateManagerImpl stateManager; + + public UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(StateManagerImpl stateManager) { + super(); + this.stateManager = stateManager; + } + + @Override + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { + if(job2insert instanceof Delivery){ + int loadAtDepot = (int) stateManager.getRouteState(inRoute, StateTypes.LOAD_AT_DEPOT).toDouble(); +// log.info("loadAtDepot="+loadAtDepot); + stateManager.putRouteState(inRoute, StateTypes.LOAD_AT_DEPOT, new StateImpl(loadAtDepot + job2insert.getCapacityDemand())); + } + else if(job2insert instanceof Pickup || job2insert instanceof Service){ + int loadAtEnd = (int) stateManager.getRouteState(inRoute, StateTypes.LOAD).toDouble(); +// log.info("loadAtEnd="+loadAtEnd); + stateManager.putRouteState(inRoute, StateTypes.LOAD, new StateImpl(loadAtEnd + job2insert.getCapacityDemand())); + } + } + + } + + static class UpdateRouteStatesOnceTheRouteHasBeenChanged implements InsertionStartsListener, JobInsertedListener { private IterateRouteForwardInTime forwardInTimeIterator; private IterateRouteBackwardInTime backwardInTimeIterator; - public WalkThroughAndUpdateRoutesOnceTheyChanged(VehicleRoutingTransportCosts routingCosts) { + private Collection insertionStartsListeners; + + private Collection jobInsertionListeners; + + public UpdateRouteStatesOnceTheRouteHasBeenChanged(VehicleRoutingTransportCosts routingCosts) { forwardInTimeIterator = new IterateRouteForwardInTime(routingCosts); backwardInTimeIterator = new IterateRouteBackwardInTime(routingCosts); + insertionStartsListeners = new ArrayList(); + jobInsertionListeners = new ArrayList(); } void addListener(ForwardInTimeListener l){ @@ -560,16 +627,31 @@ class StateUpdates { void addListener(BackwardInTimeListener l){ backwardInTimeIterator.addListener(l); } + + 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.iterate(inRoute); + backwardInTimeIterator.iterate(inRoute); } @Override public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { - // TODO Auto-generated method stub - + for(VehicleRoute route : vehicleRoutes){ + for(InsertionStarts insertionsStartsHandler : insertionStartsListeners){ + insertionsStartsHandler.insertionStarts(route); + } + forwardInTimeIterator.iterate(route); + backwardInTimeIterator.iterate(route); + } } } diff --git a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java index ad9fa4aa..d3c77390 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java @@ -35,7 +35,12 @@ import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; -import util.RouteUtils; +import algorithms.HardConstraints.ConstraintManager; +import algorithms.HardConstraints.HardTimeWindowActivityLevelConstraint; +import algorithms.StateUpdates.UpdateActivityTimes; +import algorithms.StateUpdates.UpdateCostsAtAllLevels; +import algorithms.StateUpdates.UpdateEarliestStartTimeWindowAtActLocations; +import algorithms.StateUpdates.UpdateLatestOperationStartTimeAtActLocations; import algorithms.StateUpdates.UpdateStates; import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey; @@ -50,21 +55,19 @@ import algorithms.acceptors.SolutionAcceptor; import algorithms.selectors.SelectBest; import algorithms.selectors.SelectRandomly; import algorithms.selectors.SolutionSelector; -import basics.Job; import basics.VehicleRoutingAlgorithm; import basics.VehicleRoutingProblem; +import basics.VehicleRoutingProblem.Constraint; 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; import basics.algo.SearchStrategy.DiscoveredSolution; import basics.algo.SearchStrategyManager; import basics.algo.SearchStrategyModule; -import basics.algo.SearchStrategyModuleListener; import basics.algo.TimeBreaker; import basics.algo.VariationCoefficientBreaker; import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; @@ -427,50 +430,43 @@ public class VehicleRoutingAlgorithms { } private static VehicleRoutingAlgorithm createAlgo(final VehicleRoutingProblem vrp, XMLConfiguration config, ExecutorService executorService, int nuOfThreads){ - - //fleetmanager - final VehicleFleetManager vehicleFleetManager; - if(vrp.getFleetSize().equals(FleetSize.INFINITE)){ - vehicleFleetManager = new InfiniteVehicles(vrp.getVehicles()); - - } - else if(vrp.getFleetSize().equals(FleetSize.FINITE)){ - vehicleFleetManager = new VehicleFleetManagerImpl(vrp.getVehicles()); - } - else{ - throw new IllegalStateException("fleet size can only be infinite or finite. " + - "makes sure your config file contains one of these options"); - } - + + // map to store constructed modules + TypedMap definedClasses = new TypedMap(); + + // algorithm listeners Set algorithmListeners = new HashSet(); + + // insertion listeners List insertionListeners = new ArrayList(); - algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new SolutionVerifier())); - - final StateManagerImpl routeStates = new StateManagerImpl(); - IterationStartsListener resetStates = new IterationStartsListener() { - - @Override - public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { - routeStates.clear(); - } - }; - algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, resetStates)); + //create fleetmanager + final VehicleFleetManager vehicleFleetManager = createFleetManager(vrp); -// insertionListeners.add(new UdateCostsAtRouteLevel(routeStates,vrp.getTransportCosts(),vrp.getActivityCosts())); + //create state-manager + final StateManagerImpl stateManager = new StateManagerImpl(); -// RouteStates routeStates = new RouteStates(); -// routeStates.initialiseStateOfJobs(vrp.getJobs().values()); -// algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, routeStates)); - - TypedMap definedClasses = new TypedMap(); - /* - * initial solution - construction + * define constraints */ - AlgorithmStartsListener createInitialSolution = createInitialSolution(config,vrp,vehicleFleetManager,routeStates,algorithmListeners,definedClasses,executorService,nuOfThreads); + //constraint manager + ConstraintManager constraintManager = new ConstraintManager(); + constraintManager.addConstraint(new HardConstraints.HardTimeWindowActivityLevelConstraint(stateManager, vrp.getTransportCosts())); + + if(vrp.getProblemConstraints().contains(Constraint.DELIVERIES_FIRST)){ + constraintManager.addConstraint(new HardConstraints.HardPickupAndDeliveryBackhaulActivityLevelConstraint(stateManager)); + } + else{ + constraintManager.addConstraint(new HardConstraints.HardPickupAndDeliveryActivityLevelConstraint(stateManager)); + } + + constraintManager.addConstraint(new HardConstraints.HardPickupAndDeliveryLoadConstraint(stateManager)); + + //construct initial solution creator + AlgorithmStartsListener createInitialSolution = createInitialSolution(config,vrp,vehicleFleetManager,stateManager,algorithmListeners,definedClasses,executorService,nuOfThreads,constraintManager); if(createInitialSolution != null) algorithmListeners.add(new PrioritizedVRAListener(Priority.MEDIUM, createInitialSolution)); + //construct algorithm, i.e. search-strategies and its modules int solutionMemory = config.getInt("strategy.memory"); SearchStrategyManager searchStratManager = new SearchStrategyManager(); List strategyConfigs = config.configurationsAt("strategy.searchStrategies.searchStrategy"); @@ -482,26 +478,72 @@ public class VehicleRoutingAlgorithms { strategy.setName(name); List modulesConfig = strategyConfig.configurationsAt("modules.module"); for(HierarchicalConfiguration moduleConfig : modulesConfig){ - SearchStrategyModule module = buildModule(moduleConfig,vrp,vehicleFleetManager,routeStates,algorithmListeners,definedClasses,executorService,nuOfThreads); + SearchStrategyModule module = buildModule(moduleConfig,vrp,vehicleFleetManager,stateManager,algorithmListeners,definedClasses,executorService,nuOfThreads, constraintManager); strategy.addModule(module); } searchStratManager.addStrategy(strategy, strategyConfig.getDouble("probability")); } + + //construct algorithm VehicleRoutingAlgorithm metaAlgorithm = new VehicleRoutingAlgorithm(vrp, searchStratManager); if(config.containsKey("iterations")){ int iter = config.getInt("iterations"); metaAlgorithm.setNuOfIterations(iter); log.info("set nuOfIterations to " + iter); } - //prematureBreak + + + /* + * define stateUpdates + */ + + //reset stateManager + algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new StateUpdates.ResetStateManager(stateManager))); + //update states +// metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateStates(stateManager, vrp.getTransportCosts(), vrp.getActivityCosts())); + StateUpdates.UpdateRouteStatesOnceTheRouteHasBeenChanged routeChangedListener = new StateUpdates.UpdateRouteStatesOnceTheRouteHasBeenChanged(vrp.getTransportCosts()); + + routeChangedListener.addInsertionStartsListener(new StateUpdates.UpdateLoadsAtStartAndEndOfRouteWhenInsertionStarts(stateManager)); + routeChangedListener.addJobInsertedListener(new StateUpdates.UpdateLoadsAtStartAndEndOfRouteWhenJobHasBeenInserted(stateManager)); + + routeChangedListener.addListener(new StateUpdates.UpdateActivityTimes()); + routeChangedListener.addListener(new StateUpdates.UpdateLoadAtActivityLevel(stateManager)); + routeChangedListener.addListener(new StateUpdates.UpdateCostsAtAllLevels(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager)); + + routeChangedListener.addListener(new StateUpdates.UpdateOccuredDeliveriesAtActivityLevel(stateManager)); + routeChangedListener.addListener(new StateUpdates.UpdateLatestOperationStartTimeAtActLocations(stateManager)); + routeChangedListener.addListener(new StateUpdates.UpdateFuturePickupsAtActivityLevel(stateManager)); + + metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(routeChangedListener); + metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new RemoveEmptyVehicles(vehicleFleetManager)); + metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new ResetAndIniFleetManager(vehicleFleetManager)); + metaAlgorithm.getSearchStrategyManager().addSearchStrategyModuleListener(new VehicleSwitched(vehicleFleetManager)); + + //define prematureBreak PrematureAlgorithmBreaker prematureAlgoBreaker = getPrematureBreaker(config,algorithmListeners); metaAlgorithm.setPrematureAlgorithmBreaker(prematureAlgoBreaker); + //misc + algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, new SolutionVerifier())); + + //register listeners registerListeners(metaAlgorithm,algorithmListeners); registerInsertionListeners(definedClasses,insertionListeners); return metaAlgorithm; } + private static VehicleFleetManager createFleetManager(final VehicleRoutingProblem vrp) { + if(vrp.getFleetSize().equals(FleetSize.INFINITE)){ + return new InfiniteVehicles(vrp.getVehicles()); + + } + else if(vrp.getFleetSize().equals(FleetSize.FINITE)){ + return new VehicleFleetManagerImpl(vrp.getVehicles()); + } + throw new IllegalStateException("fleet size can only be infinite or finite. " + + "makes sure your config file contains one of these options"); + } + private static PrematureAlgorithmBreaker getPrematureBreaker(XMLConfiguration config, Set algorithmListeners) { String basedOn = config.getString("prematureBreak[@basedOn]"); if(basedOn == null){ @@ -569,7 +611,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) { + private static AlgorithmStartsListener createInitialSolution(XMLConfiguration config, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, 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; @@ -584,7 +626,7 @@ public class VehicleRoutingAlgorithms { InsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey); if(insertionStrategy == null){ List prioListeners = new ArrayList(); - insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads); + insertionStrategy = createInsertionStrategy(modConfig, vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads, constraintManager); algorithmListeners.addAll(prioListeners); definedClasses.put(insertionStrategyKey,insertionStrategy); } @@ -666,7 +708,7 @@ public class VehicleRoutingAlgorithms { } private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, - final StateManagerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) { + final StateManagerImpl routeStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) { String moduleName = moduleConfig.getString("[@name]"); if(moduleName == null) throw new IllegalStateException("module(-name) is missing."); String moduleId = moduleConfig.getString("[@id]"); @@ -715,49 +757,14 @@ 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, routeStates, prioListeners, executorService, nuOfThreads); + insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads, constraintManager); algorithmListeners.addAll(prioListeners); } final InsertionStrategy final_insertion = insertion; - SearchStrategyModule module = new SearchStrategyModule() { - - private Logger logger = Logger.getLogger(SearchStrategyModule.class); - - @Override - public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { - Collection ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); - final_insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs); - double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); - vrpSolution.setCost(totalCost); - return vrpSolution; - } - - @Override - public String toString() { - return getName(); - } - - @Override - public String getName() { - return "[name=ruin_and_recreate][ruin="+ruin+"][recreate="+final_insertion+"]"; - } - - @Override - public void addModuleListener(SearchStrategyModuleListener moduleListener) { - if(moduleListener instanceof InsertionListener){ - InsertionListener iListener = (InsertionListener) moduleListener; - if(!final_insertion.getListeners().contains(iListener)){ - logger.info("register moduleListener " + moduleListener); - final_insertion.addListener(iListener); - } - - } - - } - }; - return module; + + RuinAndRecreateModule rrModule = new RuinAndRecreateModule("ruin_and_recreate", final_insertion, ruin); + return rrModule; } - if(moduleName.equals("gendreau")){ int iterations = moduleConfig.getInt("iterations"); double share = moduleConfig.getDouble("share"); @@ -770,7 +777,6 @@ public class VehicleRoutingAlgorithms { RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ ruin = new RuinRadial(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts())); - ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } @@ -785,7 +791,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, routeStates, prioListeners, executorService, nuOfThreads); + insertion = createInsertionStrategy(insertionConfigs.get(0), vrp, vehicleFleetManager, routeStates, prioListeners, executorService, nuOfThreads, constraintManager); algorithmListeners.addAll(prioListeners); } Gendreau gendreau = new Gendreau(vrp, ruin, insertion); @@ -809,7 +815,6 @@ public class VehicleRoutingAlgorithms { RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ ruin = new RuinRadial(vrp, shareToRuin, jobDistance); - ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } return ruin; @@ -820,14 +825,13 @@ public class VehicleRoutingAlgorithms { RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ ruin = new RuinRandom(vrp, shareToRuin); - 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, StateManagerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads) { - InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads); + private static InsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager) { + InsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, routeStates, algorithmListeners, executorService, nuOfThreads, constraintManager); return insertion; } diff --git a/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java index fa3242d0..8150e095 100644 --- a/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java +++ b/jsprit-core/src/test/java/algorithms/BuildPDVRPAlgoFromScratchTest.java @@ -55,8 +55,8 @@ public class BuildPDVRPAlgoFromScratchTest { final StateManagerImpl stateManager = new StateManagerImpl(); HardActivityLevelConstraintManager actLevelConstraintAccumulator = new HardActivityLevelConstraintManager(); - actLevelConstraintAccumulator.addConstraint(new HardConstraints.HardPickupAndDeliveryConstraint(stateManager)); - actLevelConstraintAccumulator.addConstraint(new HardConstraints.HardTimeWindowConstraint(stateManager, vrp.getTransportCosts())); + actLevelConstraintAccumulator.addConstraint(new HardConstraints.HardPickupAndDeliveryActivityLevelConstraint(stateManager)); + actLevelConstraintAccumulator.addConstraint(new HardConstraints.HardTimeWindowActivityLevelConstraint(stateManager, vrp.getTransportCosts())); MarginalsCalculus marginalCalculus = new MarginalsCalculusTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts(), actLevelConstraintAccumulator); diff --git a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java index a82b670c..7642b043 100644 --- a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java +++ b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java @@ -152,7 +152,7 @@ public class GendreauPostOptTest { activityCosts = new ExampleActivityCostFunction(); - CalculatesServiceInsertion standardServiceInsertion = new CalculatesServiceInsertion(cost, new MarginalsCalculusTriangleInequality(cost, activityCosts, new HardConstraints.HardTimeWindowConstraint(states, cost)), new HardConstraints.HardLoadConstraint(states)); + CalculatesServiceInsertion standardServiceInsertion = new CalculatesServiceInsertion(cost, new MarginalsCalculusTriangleInequality(cost, activityCosts, new HardConstraints.HardTimeWindowActivityLevelConstraint(states, cost)), new HardConstraints.HardLoadConstraint(states)); CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(standardServiceInsertion, states); withFixCost.setWeightOfFixCost(1.2); diff --git a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java index ebd5a30b..8ab72ed7 100644 --- a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java +++ b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertion.java @@ -157,7 +157,7 @@ public class TestCalculatesServiceInsertion { ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction(); - serviceInsertion = new CalculatesServiceInsertion(costs, new MarginalsCalculusTriangleInequality(costs, activityCosts, new HardConstraints.HardTimeWindowConstraint(states, costs)), new HardConstraints.HardLoadConstraint(states)); + serviceInsertion = new CalculatesServiceInsertion(costs, new MarginalsCalculusTriangleInequality(costs, activityCosts, new HardConstraints.HardTimeWindowActivityLevelConstraint(states, costs)), new HardConstraints.HardLoadConstraint(states)); stateUpdater = new UpdateStates(states, costs, activityCosts); diff --git a/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java b/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java index 58a3133d..61d9db1b 100644 --- a/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java +++ b/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java @@ -201,7 +201,7 @@ public class RefuseCollectionExample { VehicleRoutingProblem vrp = vrpBuilder.build(); VehicleRoutingAlgorithm vra = new GreedySchrimpfFactory().createAlgorithm(vrp); - vra.setPrematureBreak(10); + vra.setPrematureBreak(100); Collection solutions = vra.searchSolutions(); SolutionPrinter.print(Solutions.getBest(solutions),Print.VERBOSE);