diff --git a/README.md b/README.md index 81598599..e5999392 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,14 @@ It is lightweight and easy-to-use, and based on heuristics currently solving Modifying the algorithms and visualising the discovered solutions is as easy and handy as reading classical VRP instances to benchmark your algorithm. +Additionally, jsprit can be used along with MATSim +to solve the above problem-types in real networks (i.e. without preprocessing transport times and costs). A variety of least cost path algorithms such as Dijkstra and A* +can be used, and a dynamic and interactive visualiser greatly enhances the analysis. + +##In Development +- VRP with Backhauls +- Pickup and Delivery + ##License This program is free software; you can redistribute it and/or @@ -29,6 +37,15 @@ Please visit [jsprit-wiki](https://github.com/jsprit/jsprit/wiki) to learn more. [Add the latest snapshot to your pom](https://github.com/jsprit/jsprit/wiki/Add-latest-snapshot-to-your-pom). -##[About](https://github.com/jsprit/jsprit/wiki/About) +##About +The jsprit-project is created and maintained by Stefan Schröder. It is motivated by two issues. -[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/ba53806a8cc8ff439c1a51d152245dee "githalytics.com")](http://githalytics.com/jsprit/jsprit) +First, there is an almost endless list of papers and algorithms to tackle vehicle routing problems, **BUT** there are (as far as I know) only a [very few open source implementations](https://github.com/jsprit/jsprit/wiki/Other-Projects) of one of these thousands algorithms. + +Second, it is motivated by my PhD-project at [KIT](http://www.kit.edu/english/index.php) where I apply vehicle routing algorithms to solve behavioural models of freight agents to assess (freight) transport policy measures. + +It is mainly inspired by my research group at [KIT-ECON](http://netze.econ.kit.edu/21.php), and by an awesome open-source project called [MATSim](www.matsim.org) and its developers. + +Email: jsprit.vehicle.routing@gmail.com + +[![](https://cruel-carlota.pagodabox.com/ba53806a8cc8ff439c1a51d152245dee "githalytics.com")](http://githalytics.com/jsprit/jsprit) diff --git a/jsprit-analysis/src/main/java/analysis/SolutionPlotter.java b/jsprit-analysis/src/main/java/analysis/SolutionPlotter.java index 69ccd03f..3e7fab1e 100644 --- a/jsprit-analysis/src/main/java/analysis/SolutionPlotter.java +++ b/jsprit-analysis/src/main/java/analysis/SolutionPlotter.java @@ -41,7 +41,9 @@ import org.jfree.data.xy.XYSeriesCollection; import util.Coordinate; import util.Locations; +import basics.Delivery; import basics.Job; +import basics.Pickup; import basics.Service; import basics.VehicleRoutingProblem; import basics.VehicleRoutingProblemSolution; @@ -264,13 +266,33 @@ public class SolutionPlotter { } coll.addSeries(vehicleSeries); - XYSeries jobSeries = new XYSeries("service", false, true); + XYSeries serviceSeries = new XYSeries("service", false, true); + XYSeries pickupSeries = new XYSeries("pickup", false, true); + XYSeries deliverySeries = new XYSeries("delivery", false, true); for(Job job : services){ - Service service = (Service)job; - Coordinate coord = service.getCoord(); - jobSeries.add(coord.getX(), coord.getY()); + if(job instanceof Pickup){ + Pickup service = (Pickup)job; + Coordinate coord = service.getCoord(); + pickupSeries.add(coord.getX(), coord.getY()); + } + else if(job instanceof Delivery){ + Delivery service = (Delivery)job; + Coordinate coord = service.getCoord(); + deliverySeries.add(coord.getX(), coord.getY()); + } + else if(job instanceof Service){ + Service service = (Service)job; + Coordinate coord = service.getCoord(); + serviceSeries.add(coord.getX(), coord.getY()); + } + else{ + throw new IllegalStateException("job instanceof " + job.getClass().toString() + ". this is not supported."); + } + } - coll.addSeries(jobSeries); + if(!serviceSeries.isEmpty()) coll.addSeries(serviceSeries); + if(!pickupSeries.isEmpty()) coll.addSeries(pickupSeries); + if(!deliverySeries.isEmpty()) coll.addSeries(deliverySeries); return coll; } diff --git a/jsprit-core/src/main/java/algorithms/AbstractInsertionStrategy.java b/jsprit-core/src/main/java/algorithms/AbstractInsertionStrategy.java deleted file mode 100644 index f2dfca54..00000000 --- a/jsprit-core/src/main/java/algorithms/AbstractInsertionStrategy.java +++ /dev/null @@ -1,95 +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 java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import org.apache.log4j.Logger; - -import basics.Job; -import basics.algo.InsertionEndsListener; -import basics.algo.InsertionListener; -import basics.algo.InsertionStartsListener; -import basics.algo.JobInsertedListener; -import basics.route.VehicleRoute; - - - - -abstract class AbstractInsertionStrategy implements InsertionStrategy{ - - private static Logger log = Logger.getLogger(AbstractInsertionStrategy.class); - - private Collection listener = new ArrayList(); - - public abstract RouteAlgorithm getRouteAlgorithm(); - - public void informJobInserted(int nOfJobs2Recreate, Job insertedJob, VehicleRoute insertedIn){ - for(InsertionListener l : listener){ - if(l instanceof JobInsertedListener){ - ((JobInsertedListener)l).informJobInserted(nOfJobs2Recreate, insertedJob, insertedIn); - } - } - } - - public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route){ - for(InsertionListener l : listener){ - if(l instanceof BeforeJobInsertionListener){ - ((BeforeJobInsertionListener)l).informBeforeJobInsertion(job, data, route); - } - } - } - - public void informInsertionStarts(Collection vehicleRoutes, int nOfJobs2Recreate){ - for(InsertionListener l : listener){ - if(l instanceof InsertionStartsListener){ - ((InsertionStartsListener)l).informInsertionStarts(vehicleRoutes,nOfJobs2Recreate); - } - } - } - - public void informInsertionEndsListeners(Collection vehicleRoutes) { - for(InsertionListener l : listener){ - if(l instanceof InsertionEndsListener){ - ((InsertionEndsListener)l).informInsertionEnds(vehicleRoutes); - } - } - } - - public Collection getListener() { - return Collections.unmodifiableCollection(listener); - } - - public void addListener(InsertionListener l){ - log.info("add insertion-listener " + l); - listener.add(l); - } - - public void addAllListener(List list) { - for(InsertionListener l : list) addListener(l); - } - - - -} 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..effaa07a --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/BackwardInTimeListeners.java @@ -0,0 +1,52 @@ +package algorithms; + +import java.util.ArrayList; +import java.util.Collection; + +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class BackwardInTimeListeners { + + interface BackwardInTimeListener{ + + public void start(VehicleRoute route, End end, double latestArrivalTime); + + public void prevActivity(TourActivity act, double latestDepartureTime, double latestOperationStartTime); + + public void end(Start start, double latestDepartureTime); + + } + + private Collection listeners = new ArrayList(); + + public void addListener(BackwardInTimeListener l){ + listeners.add(l); + } + + public void start(VehicleRoute route, End end, double latestArrivalTime){ + for(BackwardInTimeListener l : listeners){ l.start(route, end, latestArrivalTime); } + } + + /** + * 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 latestArrivalTime + */ + public void prevActivity(TourActivity act, double latestDepartureTime, double latestArrivalTime){ + for(BackwardInTimeListener l : listeners){ l.prevActivity(act,latestDepartureTime,latestArrivalTime); } + } + + public void end(Start start, double latestDepartureTime){ + for(BackwardInTimeListener l : listeners){ l.end(start, latestDepartureTime); } + } + +} diff --git a/jsprit-core/src/main/java/algorithms/BestInsertion.java b/jsprit-core/src/main/java/algorithms/BestInsertion.java index aec62ea0..bee3394b 100644 --- a/jsprit-core/src/main/java/algorithms/BestInsertion.java +++ b/jsprit-core/src/main/java/algorithms/BestInsertion.java @@ -15,9 +15,7 @@ package algorithms; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Random; import org.apache.log4j.Logger; @@ -25,6 +23,9 @@ import org.apache.log4j.Logger; import util.RandomNumberGeneration; import algorithms.InsertionData.NoInsertionFound; import basics.Job; +import basics.algo.InsertionListener; +import basics.route.Driver; +import basics.route.Vehicle; import basics.route.VehicleRoute; @@ -35,44 +36,37 @@ import basics.route.VehicleRoute; * */ -final class BestInsertion extends AbstractInsertionStrategy{ - - public static BestInsertion newInstance(RouteAlgorithm routeAlgorithm){ - return new BestInsertion(routeAlgorithm); - } +final class BestInsertion implements InsertionStrategy{ private static Logger logger = Logger.getLogger(BestInsertion.class); private Random random = RandomNumberGeneration.getRandom(); - private RouteAlgorithm routeAlgorithm; + private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345; - public void setExperimentalPreferredRoute(Map experimentalPreferredRoute) { - } + private final static Vehicle NO_NEW_VEHICLE_YET = null; + + private final static Driver NO_NEW_DRIVER_YET = null; + + private InsertionListeners insertionsListeners; + + private Inserter inserter; + + private JobInsertionCalculator bestInsertionCostCalculator; - private boolean allowUnassignedJobs = false; - - private boolean fixRouteSet = false; - private boolean minVehiclesFirst = false; - - public void setFixRouteSet(boolean fixRouteSet) { - this.fixRouteSet = fixRouteSet; - } public void setRandom(Random random) { this.random = random; } - public BestInsertion(RouteAlgorithm routeAlgorithm) { + public BestInsertion(JobInsertionCalculator jobInsertionCalculator) { super(); - this.routeAlgorithm = routeAlgorithm; + this.insertionsListeners = new InsertionListeners(); + inserter = new Inserter(insertionsListeners); + bestInsertionCostCalculator = jobInsertionCalculator; logger.info("initialise " + this); } - - public RouteAlgorithm getRouteAlgorithm(){ - return routeAlgorithm; - } @Override public String toString() { @@ -80,19 +74,15 @@ final class BestInsertion extends AbstractInsertionStrategy{ } @Override - public void run(Collection vehicleRoutes, Collection unassignedJobs, double result2beat) { + public void insertJobs(Collection vehicleRoutes, Collection unassignedJobs) { + insertionsListeners.informInsertionStarts(vehicleRoutes,unassignedJobs); List unassignedJobList = new ArrayList(unassignedJobs); Collections.shuffle(unassignedJobList, random); - informInsertionStarts(vehicleRoutes,unassignedJobs.size()); - int inserted = 0; - List reasons = new ArrayList(); - for(Job unassignedJob : unassignedJobList){ - - VehicleRoute insertIn = null; + for(Job unassignedJob : unassignedJobList){ Insertion bestInsertion = null; double bestInsertionCost = Double.MAX_VALUE; for(VehicleRoute vehicleRoute : vehicleRoutes){ - InsertionData iData = routeAlgorithm.calculateBestInsertion(vehicleRoute, unassignedJob, bestInsertionCost); + InsertionData iData = bestInsertionCostCalculator.calculate(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost); if(iData instanceof NoInsertionFound) { continue; } @@ -103,56 +93,54 @@ final class BestInsertion extends AbstractInsertionStrategy{ } if(!minVehiclesFirst){ VehicleRoute newRoute = VehicleRoute.emptyRoute(); - InsertionData newIData = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE); + InsertionData newIData = bestInsertionCostCalculator.calculate(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost); if(newIData.getInsertionCost() < bestInsertionCost){ bestInsertion = new Insertion(newRoute,newIData); bestInsertionCost = newIData.getInsertionCost(); vehicleRoutes.add(newRoute); } - } - 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 { - if(fixRouteSet){ - if(allowUnassignedJobs) logger.warn("cannot insert job yet " + unassignedJob); - else throw new IllegalStateException("given the vehicles, could not insert job\n"); + } + if(bestInsertion == null){ + VehicleRoute newRoute = VehicleRoute.emptyRoute(); + InsertionData bestI = bestInsertionCostCalculator.calculate(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE); + if(bestI instanceof InsertionData.NoInsertionFound){ + throw new IllegalStateException(getErrorMsg(unassignedJob)); } else{ - VehicleRoute newRoute = VehicleRoute.emptyRoute(); - InsertionData bestI = routeAlgorithm.calculateBestInsertion(newRoute, unassignedJob, Double.MAX_VALUE); - if(bestI instanceof InsertionData.NoInsertionFound){ - if(allowUnassignedJobs){ - logger.warn("cannot insert job yet " + unassignedJob); - } - else { - for(String s : reasons){ - System.out.println("reason="+s); - } - throw new IllegalStateException("given the vehicles, could not insert job\n" + - "\t" + unassignedJob + - "\n\tthis might have the following reasons:\n" + - "\t- no vehicle has the capacity to transport the job [check whether there is at least one vehicle that is capable to transport the job]\n" + - "\t- the time-window cannot be met, even in a commuter tour the time-window is missed [check whether it is possible to reach the time-window on the shortest path or make hard time-windows soft]\n" + - "\t- if you deal with finite vehicles, and the available vehicles are already fully employed, no vehicle can be found anymore to transport the job [add penalty-vehicles]" - ); - } - } - else{ - insertIn = newRoute; - informBeforeJobInsertion(unassignedJob,bestI,newRoute); - routeAlgorithm.insertJob(unassignedJob,bestI,newRoute); - vehicleRoutes.add(newRoute); - } + bestInsertion = new Insertion(newRoute,bestI); + vehicleRoutes.add(newRoute); } } - inserted++; - informJobInserted((unassignedJobList.size()-inserted), unassignedJob, insertIn); + + inserter.insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); + } - informInsertionEndsListeners(vehicleRoutes); + insertionsListeners.informInsertionEndsListeners(vehicleRoutes); + } + + private String getErrorMsg(Job unassignedJob) { + return "given the vehicles, could not insert job\n" + + "\t" + unassignedJob + + "\n\tthis might have the following reasons:\n" + + "\t- no vehicle has the capacity to transport the job [check whether there is at least one vehicle that is capable to transport the job]\n" + + "\t- the time-window cannot be met, even in a commuter tour the time-window is missed [check whether it is possible to reach the time-window on the shortest path or make hard time-windows soft]\n" + + "\t- if you deal with finite vehicles, and the available vehicles are already fully employed, no vehicle can be found anymore to transport the job [add penalty-vehicles]"; + } + + @Override + public void removeListener(InsertionListener insertionListener) { + insertionsListeners.removeListener(insertionListener); + } + + @Override + public Collection getListeners() { + return Collections.unmodifiableCollection(insertionsListeners.getListeners()); + } + + @Override + public void addListener(InsertionListener insertionListener) { + insertionsListeners.addListener(insertionListener); + } } diff --git a/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java b/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java index cfe56404..4f41d2e0 100644 --- a/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java +++ b/jsprit-core/src/main/java/algorithms/BestInsertionConcurrent.java @@ -30,170 +30,185 @@ import org.apache.log4j.Logger; import util.RandomNumberGeneration; import algorithms.InsertionData.NoInsertionFound; import basics.Job; +import basics.algo.InsertionListener; import basics.route.VehicleRoute; - - -/** - * - * @author stefan schroeder - * - */ - -final class BestInsertionConcurrent extends AbstractInsertionStrategy{ - - 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 run(Collection vehicleRoutes, Collection unassignedJobs, double result2beat) { - 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 +// +// } +// +//} diff --git a/jsprit-core/src/main/java/algorithms/CalcUtils.java b/jsprit-core/src/main/java/algorithms/CalcUtils.java new file mode 100644 index 00000000..c295881f --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/CalcUtils.java @@ -0,0 +1,14 @@ +package algorithms; + +import basics.route.TourActivity; + +class CalcUtils { + + static double getStartTimeAtAct(double startTimeAtPrevAct, double tpTime_prevAct_nextAct, TourActivity nextAct){ + return Math.max(startTimeAtPrevAct + tpTime_prevAct_nextAct, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime(); + } + + static double getStartTimeAtAct(double nextActArrTime, TourActivity nextAct){ + return Math.max(nextActArrTime, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime(); + } +} diff --git a/jsprit-core/src/main/java/algorithms/CalculatesActivityInsertionWithHardTimeWindows.java b/jsprit-core/src/main/java/algorithms/CalculatesActivityInsertionWithHardTimeWindows.java deleted file mode 100644 index 3eaf5dc6..00000000 --- a/jsprit-core/src/main/java/algorithms/CalculatesActivityInsertionWithHardTimeWindows.java +++ /dev/null @@ -1,107 +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.VehicleRoutingActivityCosts; -import basics.costs.VehicleRoutingTransportCosts; -import basics.route.Driver; -import basics.route.End; -import basics.route.Start; -import basics.route.TourActivity; -import basics.route.Vehicle; -import basics.route.VehicleRoute; - - - -final class CalculatesActivityInsertionWithHardTimeWindows { - - private static Logger logger = Logger.getLogger(CalculatesActivityInsertionWithHardTimeWindows.class); - - private RouteStates routeStates; - - private VehicleRoutingTransportCosts routingCosts; - - private VehicleRoutingActivityCosts activityCosts; - - public CalculatesActivityInsertionWithHardTimeWindows(RouteStates activityStates, VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts){ - this.routeStates = activityStates; - this.routingCosts = routingCosts; - this.activityCosts = activityCosts; - logger.info("initialise " + this); - } - - public double calculate(VehicleRoute vehicleRoute, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle) { - boolean prevIsStart = false; - - if(prevAct instanceof Start){ - prevIsStart = true; - } - - 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 newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct; - double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime()); - - double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime(); - - double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, driver, vehicle); - - 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); - - double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; - double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle); - - double activityInsertionCosts; - - double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct; - - if(nextAct_arrTime > getLatestOperationStart(nextAct)){ - activityInsertionCosts = Double.MAX_VALUE; - } - else if(vehicleRoute.isEmpty()){ - activityInsertionCosts = totalCosts; - } - else{ - double oldCostOfPrevAct; - if(prevIsStart) oldCostOfPrevAct = 0.0; - else oldCostOfPrevAct = state(prevAct).getCurrentCost(); - double oldCostOfNextAct; - if(nextAct instanceof End) oldCostOfNextAct = routeStates.getRouteState(vehicleRoute).getCosts(); - else oldCostOfNextAct = state(nextAct).getCurrentCost(); - activityInsertionCosts = (totalCosts) - (oldCostOfNextAct-oldCostOfPrevAct); - } - return activityInsertionCosts; - } - - private ActivityState state(TourActivity act) { - return routeStates.getState(act); - } - - private double getLatestOperationStart(TourActivity act) { - if(state(act) != null){ - return state(act).getLatestOperationStart(); - } - return act.getTheoreticalLatestOperationStartTime(); - } - - @Override - public String toString() { - return "[name=calculatesHardTimeWindowActivityInsertion]"; - } - -} diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java index c2c133a2..ed8dc4e9 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java +++ b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertion.java @@ -15,37 +15,27 @@ package algorithms; import org.apache.log4j.Logger; import util.Neighborhood; - -import algorithms.RouteStates.ActivityState; +import algorithms.HardConstraints.HardRouteLevelConstraint; +import algorithms.MarginalsCalculus.Marginals; 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; +import basics.route.VehicleRoute; final class CalculatesServiceInsertion implements JobInsertionCalculator{ - + private static final Logger logger = Logger.getLogger(CalculatesServiceInsertion.class); - - private RouteStates routeStates; - - private VehicleRoutingTransportCosts routingCosts; - - private VehicleRoutingActivityCosts activityCosts; - - private Start start; - - private End end; + + private HardRouteLevelConstraint hardRouteLevelConstraint; private Neighborhood neighborhood = new Neighborhood() { @@ -55,25 +45,20 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ } }; + private MarginalsCalculus marginalCalculus; + private VehicleRoutingTransportCosts transportCosts; public void setNeighborhood(Neighborhood neighborhood) { this.neighborhood = neighborhood; logger.info("initialise neighborhood " + neighborhood); } - - public void setActivityStates(RouteStates actStates){ - this.routeStates = actStates; - } - - public ActivityState state(TourActivity act){ - return routeStates.getState(act); - } - public CalculatesServiceInsertion(VehicleRoutingTransportCosts vehicleRoutingTransportCosts, VehicleRoutingActivityCosts vehicleRoutingActivityCosts) { + public CalculatesServiceInsertion(VehicleRoutingTransportCosts routingCosts, MarginalsCalculus marginalsCalculus, HardRouteLevelConstraint hardRouteLevelConstraint) { super(); - this.routingCosts = vehicleRoutingTransportCosts; - this.activityCosts = vehicleRoutingActivityCosts; + this.marginalCalculus = marginalsCalculus; + this.hardRouteLevelConstraint = hardRouteLevelConstraint; + this.transportCosts = routingCosts; logger.info("initialise " + this); } @@ -92,42 +77,53 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ 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(); - double bestCost = bestKnownCosts; - Service service = (Service)jobToInsert; - - if(routeStates.getRouteState(currentRoute).getLoad() + service.getCapacityDemand() > newVehicle.getCapacity()){ + InsertionContext insertionContext = new InsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime); + if(!hardRouteLevelConstraint.fulfilled(insertionContext)){ return InsertionData.noInsertionFound(); } + + double bestCost = bestKnownCosts; + Marginals bestMarginals = null; + Service service = (Service)jobToInsert; int insertionIndex = InsertionData.NO_INDEX; - TourActivity deliveryAct2Insert = ServiceActivity.newInstance(service); -// TourActivity deliveryAct2Insert = actStates.getActivity(service, true); - initialiseStartAndEnd(newVehicle, newVehicleDepartureTime); + Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival()); + start.setEndTime(newVehicleDepartureTime); + + End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival()); TourActivity prevAct = start; - double prevCostInOriginalTour = 0.0; + double prevActStartTime = newVehicleDepartureTime; int actIndex = 0; - for(TourActivity nextAct : tour.getActivities()){ - double nextCostInOriginalTour = state(nextAct).getCurrentCost(); + + for(TourActivity nextAct : currentRoute.getTourActivities().getActivities()){ + if(deliveryAct2Insert.getTheoreticalLatestOperationStartTime() < prevAct.getTheoreticalEarliestOperationStartTime()){ + break; + } if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ - double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, nextCostInOriginalTour - prevCostInOriginalTour); - if(mc < bestCost){ - bestCost = mc; - insertionIndex = actIndex; + Marginals mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); + if(mc != null){ + if(mc.getAdditionalCosts() < bestCost){ + bestCost = mc.getAdditionalCosts(); + bestMarginals = mc; + insertionIndex = actIndex; + } } } - prevCostInOriginalTour = nextCostInOriginalTour; prevAct = nextAct; + prevActStartTime = CalcUtils.getStartTimeAtAct(prevActStartTime, transportCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevActStartTime, newDriver, newVehicle), nextAct); actIndex++; } End nextAct = end; if(neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), prevAct.getLocationId()) && neighborhood.areNeighbors(deliveryAct2Insert.getLocationId(), nextAct.getLocationId())){ - double mc = calculate(tour, prevAct, nextAct, deliveryAct2Insert, newDriver, newVehicle, bestCost, routeStates.getRouteState(currentRoute).getCosts() - prevCostInOriginalTour); - if(mc < bestCost){ - bestCost = mc; - insertionIndex = actIndex; + Marginals mc = calculate(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); + if(mc != null) { + if(mc.getAdditionalCosts() < bestCost){ + bestCost = mc.getAdditionalCosts(); + bestMarginals = mc; + insertionIndex = actIndex; + } } } @@ -136,74 +132,12 @@ final class CalculatesServiceInsertion implements JobInsertionCalculator{ } InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver); insertionData.setVehicleDepartureTime(newVehicleDepartureTime); + insertionData.setAdditionalTime(bestMarginals.getAdditionalTime()); return insertionData; } - 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); - } + public Marginals calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double departureTimeAtPrevAct) { + return marginalCalculus.calculate(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct); - 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 double calculate(TourActivities tour, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, Driver driver, Vehicle vehicle, double bestKnownCosts, double costWithoutNewJob) { - - 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 newAct_arrTime = prevAct.getEndTime() + tp_time_prevAct_newAct; - double newAct_operationStartTime = Math.max(newAct_arrTime, newAct.getTheoreticalEarliestOperationStartTime()); - - double newAct_endTime = newAct_operationStartTime + newAct.getOperationTime(); - - 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; - } - - 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); - - double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; - double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, driver, vehicle); - - double activityInsertionCosts; - - double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct; - - if(totalCosts - costWithoutNewJob > bestKnownCosts){ - activityInsertionCosts = Double.MAX_VALUE; - } - if(nextAct_arrTime > getLatestOperationStart(nextAct)){ - activityInsertionCosts = Double.MAX_VALUE; - } - else{ - activityInsertionCosts = totalCosts - costWithoutNewJob; - } - return activityInsertionCosts; - } - - private double getLatestOperationStart(TourActivity act) { - if(state(act) != null){ - return state(act).getLatestOperationStart(); - } - return act.getTheoreticalLatestOperationStartTime(); } } diff --git a/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionConsideringFixCost.java b/jsprit-core/src/main/java/algorithms/CalculatesServiceInsertionConsideringFixCost.java index d763a3b7..1961ec84 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.StateManager.State; +import algorithms.StateManager.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 StateManager states; - public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, RouteStates routeStates) { + public CalculatesServiceInsertionConsideringFixCost(final JobInsertionCalculator standardInsertionCalculator, StateManager 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..1d0d900c 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 StateManager states; private int nuOfActsForwardLooking = 0; @@ -89,14 +90,10 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul logger.info("initialise " + this); } - public void setActivityStates(RouteStates actStates){ - this.routeStates = actStates; - } - public ActivityState state(TourActivity act){ - return routeStates.getState(act); + public void setStates(StateManager activityStates2){ + this.states = activityStates2; } - void setNuOfActsForwardLooking(int nOfActsForwardLooking) { this.nuOfActsForwardLooking = nOfActsForwardLooking; @@ -138,14 +135,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); @@ -245,6 +242,14 @@ final class CalculatesServiceInsertionOnRouteLevel implements JobInsertionCalcul * */ + if(memorySize==0){ + InsertionData insertion = bestInsertionsQueue.poll(); + if(insertion != null){ + best_insertion_index = insertion.getDeliveryInsertionIndex(); + best_insertion_costs = insertion.getInsertionCost(); + } + } + for(int i=0;i 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 +312,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/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..6ab8e4c0 100644 --- a/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java +++ b/jsprit-core/src/main/java/algorithms/CalculatorBuilder.java @@ -22,18 +22,10 @@ package algorithms; import java.util.ArrayList; import java.util.List; -import java.util.Set; - -import org.apache.commons.configuration.XMLConfiguration; - -import util.NeighborhoodImpl; import basics.VehicleRoutingProblem; -import basics.VehicleRoutingProblem.FleetComposition; import basics.algo.InsertionListener; import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; -import basics.algo.VehicleRoutingAlgorithmListeners.Priority; -import basics.costs.VehicleRoutingActivityCosts; @@ -70,7 +62,7 @@ class CalculatorBuilder { private VehicleRoutingProblem vrp; - private RouteStates activityStates; + private StateManager states; private boolean local = true; @@ -107,12 +99,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(StateManager states){ + this.states = states; return this; } @@ -184,21 +176,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 +198,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 +213,36 @@ class CalculatorBuilder { } } - private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, RouteStates activityStates){ - JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), vrp.getActivityCosts()); - ((CalculatesServiceInsertion) standardServiceInsertion).setActivityStates(activityStates); + private CalculatorPlusListeners createStandardLocal(VehicleRoutingProblem vrp, StateManager activityStates2){ + MarginalsCalculus defaultCalc = new MarginalsCalculusTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts(), new HardConstraints.HardTimeWindowConstraint(activityStates2) ); + JobInsertionCalculator standardServiceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), defaultCalc, new HardConstraints.HardLoadConstraint(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, StateManager 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, StateManager 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).setStates(activityStates2); CalculatorPlusListeners calcPlusListener = new CalculatorPlusListeners(jobInsertionCalculator); return calcPlusListener; } - private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, RouteStates routeStates){ + private JobInsertionCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCalculator baseCalc, StateManager 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 179164da..08759adf 100644 --- a/jsprit-core/src/main/java/algorithms/ConfigureFixCostCalculator.java +++ b/jsprit-core/src/main/java/algorithms/ConfigureFixCostCalculator.java @@ -42,6 +42,8 @@ final class ConfigureFixCostCalculator implements InsertionStartsListener, JobIn VehicleRoutingProblem vrp; CalculatesServiceInsertionConsideringFixCost calcConsideringFix; + + private int nuOfJobsToRecreate; public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, CalculatesServiceInsertionConsideringFixCost calcConsideringFix) { super(); @@ -55,15 +57,17 @@ final class ConfigureFixCostCalculator implements InsertionStartsListener, JobIn } @Override - public void informInsertionStarts(Collection routes, int nOfJobs2Recreate) { - double completenessRatio = (1-((double)nOfJobs2Recreate/(double)vrp.getJobs().values().size())); + public void informInsertionStarts(Collection routes, Collection unassignedJobs) { + this.nuOfJobsToRecreate = unassignedJobs.size(); + double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size())); calcConsideringFix.setSolutionCompletenessRatio(completenessRatio); // log.debug("initialise completenessRatio to " + completenessRatio); } @Override - public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn) { - double completenessRatio = (1-((double)nOfJobsStill2Recreate/(double)vrp.getJobs().values().size())); + 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); // log.debug("set completenessRatio to " + completenessRatio); } diff --git a/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java b/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java index dcaee915..e0b1cd6d 100644 --- a/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java +++ b/jsprit-core/src/main/java/algorithms/CreateInitialSolution.java @@ -51,7 +51,7 @@ final class CreateInitialSolution implements InitialSolutionFactory { private static final Logger logger = Logger.getLogger(CreateInitialSolution.class); - private final AbstractInsertionStrategy insertion; + private final InsertionStrategy insertion; private boolean generateAsMuchAsRoutesAsVehiclesExist = false; @@ -59,9 +59,9 @@ final class CreateInitialSolution implements InitialSolutionFactory { this.generateAsMuchAsRoutesAsVehiclesExist = generateAsMuchAsRoutesAsVehiclesExist; } - public CreateInitialSolution(AbstractInsertionStrategy insertion) { + public CreateInitialSolution(InsertionStrategy insertionStrategy) { super(); - this.insertion = insertion; + this.insertion = insertionStrategy; } @Override @@ -73,7 +73,7 @@ final class CreateInitialSolution implements InitialSolutionFactory { vehicleRoutes.add(VehicleRoute.newInstance(TourActivities.emptyTour(), DriverImpl.noDriver(), vehicle)); } } - insertion.run(vehicleRoutes, getUnassignedJobs(vrp), Double.MAX_VALUE); + insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp)); double totalCost = getTotalCost(vehicleRoutes); logger.info("creation done"); return new VehicleRoutingProblemSolution(vehicleRoutes, totalCost); diff --git a/jsprit-core/src/main/java/algorithms/FindCheaperVehicle.java b/jsprit-core/src/main/java/algorithms/FindCheaperVehicle.java index 9a19f579..807cc36a 100644 --- a/jsprit-core/src/main/java/algorithms/FindCheaperVehicle.java +++ b/jsprit-core/src/main/java/algorithms/FindCheaperVehicle.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import basics.Job; import basics.algo.InsertionStartsListener; import basics.route.VehicleRoute; @@ -37,7 +38,7 @@ class FindCheaperVehicle implements InsertionStartsListener{ } @Override - public void informInsertionStarts(Collection vehicleRoutes, int nOfJobs2Recreate) { + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { List newRoutes = new ArrayList(); for(VehicleRoute route : vehicleRoutes){ if(route.isEmpty()) continue; 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..0f8b68d6 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/ForwardInTimeListeners.java @@ -0,0 +1,41 @@ +package algorithms; + +import java.util.ArrayList; +import java.util.Collection; + +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class ForwardInTimeListeners { + + interface ForwardInTimeListener{ + + public void start(VehicleRoute route, Start start, double departureTime); + + public void nextActivity(TourActivity act, double arrTime,double endTime); + + public void end(End end, double arrivalTime); + + } + + private Collection listeners = new ArrayList(); + + public void addListener(ForwardInTimeListener l){ + listeners.add(l); + } + + public void start(VehicleRoute route, Start start, double departureTime){ + for(ForwardInTimeListener l : listeners){ l.start(route, start, departureTime); } + } + + public void nextActivity(TourActivity act, double arrTime, double endTime){ + for(ForwardInTimeListener l : listeners){ l.nextActivity(act,arrTime,endTime); } + } + + public void end(End end, double arrivalTime){ + for(ForwardInTimeListener l : listeners){ l.end(end, arrivalTime); } + } + +} diff --git a/jsprit-core/src/main/java/algorithms/GendreauPostOpt.java b/jsprit-core/src/main/java/algorithms/Gendreau.java similarity index 83% rename from jsprit-core/src/main/java/algorithms/GendreauPostOpt.java rename to jsprit-core/src/main/java/algorithms/Gendreau.java index c7560cee..70125dc4 100644 --- a/jsprit-core/src/main/java/algorithms/GendreauPostOpt.java +++ b/jsprit-core/src/main/java/algorithms/Gendreau.java @@ -21,6 +21,7 @@ package algorithms; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -30,20 +31,19 @@ import java.util.Set; import org.apache.log4j.Logger; +import util.RandomNumberGeneration; import basics.Job; import basics.VehicleRoutingProblem; import basics.VehicleRoutingProblemSolution; import basics.algo.SearchStrategyModule; import basics.algo.SearchStrategyModuleListener; import basics.route.TourActivity; -import basics.route.VehicleRoute; import basics.route.TourActivity.JobActivity; +import basics.route.VehicleRoute; -import util.RandomNumberGeneration; +final class Gendreau implements SearchStrategyModule{ -final class GendreauPostOpt implements SearchStrategyModule{ - - private final static Logger log = Logger.getLogger(GendreauPostOpt.class); + private final static Logger log = Logger.getLogger(Gendreau.class); private final static String NAME = "gendreauPostOpt"; @@ -51,9 +51,9 @@ final class GendreauPostOpt implements SearchStrategyModule{ private final VehicleRoutingProblem vrp; - private final AbstractInsertionStrategy insertionStrategy; + private final InsertionStrategy insertionStrategy; - private final RouteAlgorithm routeAlgorithm; + private final Inserter inserter; private VehicleFleetManager fleetManager; @@ -67,9 +67,11 @@ final class GendreauPostOpt implements SearchStrategyModule{ this.shareOfJobsToRuin = shareOfJobsToRuin; } - public GendreauPostOpt(VehicleRoutingProblem vrp, RuinStrategy ruin, AbstractInsertionStrategy insertionStrategy) { + public Gendreau(VehicleRoutingProblem vrp, RuinStrategy ruin, InsertionStrategy insertionStrategy) { super(); - this.routeAlgorithm = insertionStrategy.getRouteAlgorithm(); + InsertionListeners insertionListeners = new InsertionListeners(); + insertionListeners.addAllListeners(insertionStrategy.getListeners()); + inserter = new Inserter(insertionListeners); this.ruin = ruin; this.vrp = vrp; this.insertionStrategy = insertionStrategy; @@ -77,7 +79,7 @@ final class GendreauPostOpt implements SearchStrategyModule{ @Override public String toString() { - return "[name=gendreauPostOpt][iterations="+nOfIterations+"][share2ruin="+shareOfJobsToRuin+"]"; + return "[name=gendreau][iterations="+nOfIterations+"][share2ruin="+shareOfJobsToRuin+"]"; } public void setRandom(Random random) { @@ -119,16 +121,18 @@ final class GendreauPostOpt implements SearchStrategyModule{ VehicleRoute emptyRoute1 = VehicleRoute.emptyRoute(); copiedRoutes.add(emptyRoute1); - routeAlgorithm.insertJob(targetJob, routeAlgorithm.calculateBestInsertion(emptyRoute1, targetJob, Double.MAX_VALUE), emptyRoute1); + insertionStrategy.insertJobs(Arrays.asList(emptyRoute1), Arrays.asList(targetJob)); +// routeAlgorithm.insertJob(targetJob, routeAlgorithm.calculateBestInsertion(emptyRoute1, targetJob, Double.MAX_VALUE), emptyRoute1); unassignedJobs.remove(targetJob); VehicleRoute emptyRoute2 = VehicleRoute.emptyRoute(); copiedRoutes.add(emptyRoute2); Job job2 = jobsInRoute.get(1); - routeAlgorithm.insertJob(job2, routeAlgorithm.calculateBestInsertion(emptyRoute2, job2, Double.MAX_VALUE), emptyRoute2); + insertionStrategy.insertJobs(Arrays.asList(emptyRoute2), Arrays.asList(job2)); +// routeAlgorithm.insertJob(job2, routeAlgorithm.calculateBestInsertion(emptyRoute2, job2, Double.MAX_VALUE), emptyRoute2); unassignedJobs.remove(job2); - insertionStrategy.run(copiedRoutes, unassignedJobs, Double.MAX_VALUE); + insertionStrategy.insertJobs(copiedRoutes, unassignedJobs); double cost = getCost(copiedRoutes); if(cost < bestSolution.getCost()){ diff --git a/jsprit-core/src/main/java/algorithms/HardConstraints.java b/jsprit-core/src/main/java/algorithms/HardConstraints.java new file mode 100644 index 00000000..28caccfb --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/HardConstraints.java @@ -0,0 +1,59 @@ +package algorithms; + +import basics.Service; +import basics.route.TourActivity; + +class HardConstraints { + + interface HardRouteLevelConstraint { + + public boolean fulfilled(InsertionContext insertionContext); + + } + + interface HardActivityLevelConstraint { + + public boolean fulfilled(InsertionContext iFacts, TourActivity act, double arrTime); + + } + + static class HardLoadConstraint implements HardRouteLevelConstraint{ + + private StateManager states; + + public HardLoadConstraint(StateManager states) { + super(); + this.states = states; + } + + @Override + public boolean fulfilled(InsertionContext insertionContext) { + int currentLoad = (int) states.getRouteState(insertionContext.getRoute(), StateTypes.LOAD).toDouble(); + Service service = (Service) insertionContext.getJob(); + if(currentLoad + service.getCapacityDemand() > insertionContext.getNewVehicle().getCapacity()){ + return false; + } + return true; + } + } + + static class HardTimeWindowConstraint implements HardActivityLevelConstraint { + + private StateManager states; + + public HardTimeWindowConstraint(StateManager states) { + super(); + this.states = states; + } + + @Override + public boolean fulfilled(InsertionContext iFacts, TourActivity act, double arrTime) { + if(arrTime > states.getActivityState(act, StateTypes.LATEST_OPERATION_START_TIME).toDouble()){ + return false; + } + return true; + } + + } + +} diff --git a/jsprit-core/src/main/java/algorithms/Inserter.java b/jsprit-core/src/main/java/algorithms/Inserter.java new file mode 100644 index 00000000..24845c01 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/Inserter.java @@ -0,0 +1,36 @@ +package algorithms; + +import algorithms.InsertionData.NoInsertionFound; +import basics.Job; +import basics.Service; +import basics.route.ServiceActivity; +import basics.route.VehicleRoute; + +class Inserter { + + private InsertionListeners insertionListeners; + + public Inserter(InsertionListeners insertionListeners) { + this.insertionListeners = insertionListeners; + } + + public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){ + insertionListeners.informBeforeJobInsertion(job, insertionData, vehicleRoute); + + if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job."); + if(job == null) throw new IllegalStateException("cannot insert null-job"); + if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){ + insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle()); + vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime()); + } +// if(vehicleRoute.getDepartureTime() != vehicleRoute.g) + if(job instanceof Service) { + vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), ServiceActivity.newInstance((Service)job)); + vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime()); + } + else throw new IllegalStateException("neither service nor shipment. this is not supported."); + + insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime()); +// updateTour(vehicleRoute); + } +} diff --git a/jsprit-core/src/main/java/algorithms/InsertionContext.java b/jsprit-core/src/main/java/algorithms/InsertionContext.java new file mode 100644 index 00000000..245ac90a --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/InsertionContext.java @@ -0,0 +1,63 @@ +package algorithms; + +import basics.Job; +import basics.route.Driver; +import basics.route.Vehicle; +import basics.route.VehicleRoute; + +class InsertionContext { + + private VehicleRoute route; + private Job job; + private Vehicle newVehicle; + private Driver newDriver; + private double newDepTime; + + /** + * @return the route + */ + public VehicleRoute getRoute() { + return route; + } + + /** + * @return the job + */ + public Job getJob() { + return job; + } + + /** + * @return the newVehicle + */ + public Vehicle getNewVehicle() { + return newVehicle; + } + + /** + * @return the newDriver + */ + public Driver getNewDriver() { + return newDriver; + } + + /** + * @return the newDepTime + */ + public double getNewDepTime() { + return newDepTime; + } + + public InsertionContext(VehicleRoute route, Job job, Vehicle newVehicle, + Driver newDriver, double newDepTime) { + super(); + this.route = route; + this.job = job; + this.newVehicle = newVehicle; + this.newDriver = newDriver; + this.newDepTime = newDepTime; + } + + + +} 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 b7cc4093..ed82df20 100644 --- a/jsprit-core/src/main/java/algorithms/InsertionFactory.java +++ b/jsprit-core/src/main/java/algorithms/InsertionFactory.java @@ -37,8 +37,8 @@ class InsertionFactory { private static Logger log = Logger.getLogger(InsertionFactory.class); - public static AbstractInsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config, - VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads){ + public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config, + VehicleFleetManager vehicleFleetManager, StateManagerImpl routeStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads){ boolean concurrentInsertion = false; if(executorService != null) concurrentInsertion = true; if(config.containsKey("[@name]")){ @@ -46,12 +46,12 @@ class InsertionFactory { if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){ new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\""); } - AbstractInsertionStrategy insertionStrategy = null; + InsertionStrategy insertionStrategy = null; List insertionListeners = new ArrayList(); List algoListeners = new ArrayList(); CalculatorBuilder calcBuilder = new CalculatorBuilder(insertionListeners, algorithmListeners); - calcBuilder.setActivityStates(activityStates); + calcBuilder.setStates(routeStates); calcBuilder.setVehicleRoutingProblem(vrp); calcBuilder.setVehicleFleetManager(vehicleFleetManager); @@ -94,34 +94,23 @@ 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).setActivityStates(activityStates); + if(insertionName.equals("bestInsertion")){ - if(concurrentInsertion){ - insertionStrategy = BestInsertionConcurrent.newInstance(routeAlgorithm,executorService,nuOfThreads); - } - else{ - insertionStrategy = BestInsertion.newInstance(routeAlgorithm); - } + insertionStrategy = new BestInsertion(jic); } - else if(insertionName.equals("regretInsertion")){ - insertionStrategy = RegretInsertion.newInstance(routeAlgorithm); - } -// else if(insertionName.equals("concurrentBestInsertion")){ -// String processorsString = config.getString("[@processors]"); -// int processors = 1; -// if(processorsString != null) processors = Integer.parseInt(processorsString); -//// BestInsertionConcurrent.newInstance(routeAlgorithm,) -// -// +// else if(insertionName.equals("regretInsertion")){ +// insertionStrategy = RegretInsertion.newInstance(routeAlgorithm); // } -// insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager)); + insertionStrategy.addListener(new RemoveEmptyVehicles(vehicleFleetManager)); insertionStrategy.addListener(new ResetAndIniFleetManager(vehicleFleetManager)); - insertionStrategy.addAllListener(insertionListeners); + insertionStrategy.addListener(new VehicleSwitched(vehicleFleetManager)); + +// 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 new file mode 100644 index 00000000..72183a1c --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/InsertionListeners.java @@ -0,0 +1,74 @@ +package algorithms; + +import java.util.ArrayList; +import java.util.Collection; + +import basics.Job; +import basics.algo.InsertionEndsListener; +import basics.algo.InsertionListener; +import basics.algo.InsertionStartsListener; +import basics.algo.JobInsertedListener; +import basics.route.Vehicle; +import basics.route.VehicleRoute; + +class InsertionListeners { + + private Collection listeners = new ArrayList(); + + public Collection getListeners(){ + return listeners; + } + + public void informJobInserted(Job insertedJob, VehicleRoute inRoute, double additionalCosts, double additionalTime){ + for(InsertionListener l : listeners){ + if(l instanceof JobInsertedListener){ + ((JobInsertedListener)l).informJobInserted(insertedJob, inRoute, additionalCosts, additionalTime); + } + } + } + + public void informVehicleSwitched(VehicleRoute route, Vehicle oldVehicle, Vehicle newVehicle){ + for(InsertionListener l : listeners){ + if(l instanceof VehicleSwitchedListener){ + ((VehicleSwitchedListener) l).vehicleSwitched(route, oldVehicle, newVehicle); + } + } + } + + public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route){ + for(InsertionListener l : listeners){ + if(l instanceof BeforeJobInsertionListener){ + ((BeforeJobInsertionListener)l).informBeforeJobInsertion(job, data, route); + } + } + } + + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs){ + for(InsertionListener l : listeners){ + if(l instanceof InsertionStartsListener){ + ((InsertionStartsListener)l).informInsertionStarts(vehicleRoutes, unassignedJobs); + } + } + } + + public void informInsertionEndsListeners(Collection vehicleRoutes) { + for(InsertionListener l : listeners){ + if(l instanceof InsertionEndsListener){ + ((InsertionEndsListener)l).informInsertionEnds(vehicleRoutes); + } + } + } + + public void addListener(InsertionListener insertionListener){ + listeners.add(insertionListener); + } + + public void removeListener(InsertionListener insertionListener){ + listeners.remove(insertionListener); + } + + public void addAllListeners(Collection listeners) { + for(InsertionListener l : listeners) addListener(l); + } + +} diff --git a/jsprit-core/src/main/java/algorithms/InsertionStrategy.java b/jsprit-core/src/main/java/algorithms/InsertionStrategy.java index 7c56995b..4ebc9ffa 100644 --- a/jsprit-core/src/main/java/algorithms/InsertionStrategy.java +++ b/jsprit-core/src/main/java/algorithms/InsertionStrategy.java @@ -15,6 +15,7 @@ package algorithms; import java.util.Collection; import basics.Job; +import basics.algo.InsertionListener; import basics.route.VehicleRoute; @@ -59,8 +60,13 @@ interface InsertionStrategy { * * @param vehicleRoutes * @param unassignedJobs - * @param result2beat */ - public void run(Collection vehicleRoutes, Collection unassignedJobs, double result2beat); + public void insertJobs(Collection vehicleRoutes, Collection unassignedJobs); + + public void addListener(InsertionListener insertionListener); + + public void removeListener(InsertionListener insertionListener); + + public Collection getListeners(); } 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..afafcde2 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/IterateRouteBackwardInTime.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * 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, vehicleRoute.getEnd(), vehicleRoute.getEnd().getTheoreticalLatestOperationStartTime()); + + Iterator reverseActIter = vehicleRoute.getTourActivities().reverseActivityIterator(); + TourActivity prevAct; + prevAct = vehicleRoute.getEnd(); + double latestArrivalTimeAtPrevAct = prevAct.getTheoreticalLatestOperationStartTime(); + + while(reverseActIter.hasNext()){ + TourActivity currAct = reverseActIter.next(); + double latestDepTimeAtCurrAct = latestArrivalTimeAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), latestArrivalTimeAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle()); + double potentialLatestArrivalTimeAtCurrAct = latestDepTimeAtCurrAct - currAct.getOperationTime(); + double latestArrivalTime = Math.min(currAct.getTheoreticalLatestOperationStartTime(), potentialLatestArrivalTimeAtCurrAct); + + listeners.prevActivity(currAct, latestDepTimeAtCurrAct, latestArrivalTime); + + prevAct = currAct; + latestArrivalTimeAtPrevAct = latestArrivalTime; + } + + TourActivity currAct = vehicleRoute.getStart(); + double latestDepTimeAtCurrAct = latestArrivalTimeAtPrevAct - transportTime.getBackwardTransportTime(currAct.getLocationId(), prevAct.getLocationId(), latestArrivalTimeAtPrevAct, vehicleRoute.getDriver(),vehicleRoute.getVehicle()); + + listeners.end(vehicleRoute.getStart(), latestDepTimeAtCurrAct); + } + + 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..868a84d7 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/IterateRouteForwardInTime.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * 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, vehicleRoute.getStart(), vehicleRoute.getStart().getEndTime()); + + Vehicle vehicle = vehicleRoute.getVehicle(); + Driver driver = vehicleRoute.getDriver(); + TourActivity prevAct = vehicleRoute.getStart(); + double startAtPrevAct = prevAct.getEndTime(); + + 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.end(vehicleRoute.getEnd(), arrivalTimeAtCurrAct); + } + + 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 43641b04..0643bb36 100644 --- a/jsprit-core/src/main/java/algorithms/JobObserver.java +++ b/jsprit-core/src/main/java/algorithms/JobObserver.java @@ -76,14 +76,14 @@ class JobObserver implements JobInsertedListener, BeforeJobInsertionListener, Al Collection infos = new ArrayList(); @Override - public void informJobInserted(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn) { + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { if(job2insert instanceof Service){ if(((Service) job2insert).getLocationId().equals(locationId)){ - double actualMC = insertedIn.getCost()-routeCostBefore; - TourActivity act = getAct(job2insert,insertedIn); + double actualMC = inRoute.getCost()-routeCostBefore; + TourActivity act = getAct(job2insert,inRoute); double error = (estimatedMC-actualMC); - int tourSize = insertedIn.getTourActivities().getActivities().size(); - int insertionIndex = getIndexOf(job2insert, insertedIn); + int tourSize = inRoute.getTourActivities().getActivities().size(); + int insertionIndex = getIndexOf(job2insert, inRoute); // infos.add(new Info()) double depTime = state(act).getEarliestOperationStart()+act.getOperationTime(); infos.add(new Info(depTime,tourSize,insertionIndex,error)); diff --git a/jsprit-core/src/main/java/algorithms/JobRemover.java b/jsprit-core/src/main/java/algorithms/JobRemover.java deleted file mode 100644 index c8d34d15..00000000 --- a/jsprit-core/src/main/java/algorithms/JobRemover.java +++ /dev/null @@ -1,36 +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 basics.Job; -import basics.route.VehicleRoute; - -interface JobRemover { - - /** - * Removes jobs from vehicRoute and return true if job has been successfully removed. - * - * @return true if job removed successfully, otherwise false - */ - public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute); - - -} diff --git a/jsprit-core/src/main/java/algorithms/JobRemoverImpl.java b/jsprit-core/src/main/java/algorithms/JobRemoverImpl.java deleted file mode 100644 index 737fca0a..00000000 --- a/jsprit-core/src/main/java/algorithms/JobRemoverImpl.java +++ /dev/null @@ -1,54 +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 java.util.ArrayList; -import java.util.List; - -import basics.Job; -import basics.route.VehicleRoute; - -class JobRemoverImpl implements JobRemover{ - - interface RemoverListener { - public void informRemovedJob(Job j, VehicleRoute r); - } - - private List remListeners = new ArrayList(); - - @Override - public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) { - boolean jobRemoved = vehicleRoute.getTourActivities().removeJob(job); - if(jobRemoved) informRemovedJob(job,vehicleRoute); - return jobRemoved; - } - - private void informRemovedJob(Job job, VehicleRoute vehicleRoute) { - for(RemoverListener l : remListeners) l.informRemovedJob(job, vehicleRoute); - } - - public List getRemListeners() { - return remListeners; - } - - - -} diff --git a/jsprit-core/src/main/java/algorithms/MarginalsCalculus.java b/jsprit-core/src/main/java/algorithms/MarginalsCalculus.java new file mode 100644 index 00000000..d702de25 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/MarginalsCalculus.java @@ -0,0 +1,35 @@ +package algorithms; + +import basics.route.TourActivity; + +interface MarginalsCalculus { + + class Marginals { + + private double additionalCosts; + private double additionalTime; + public Marginals(double additionalCosts, double additionalTime) { + super(); + this.additionalCosts = additionalCosts; + this.additionalTime = additionalTime; + } + /** + * @return the additionalCosts + */ + public double getAdditionalCosts() { + return additionalCosts; + } + /** + * @return the additionalTime + */ + public double getAdditionalTime() { + return additionalTime; + } + + + + } + + Marginals calculate(InsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct); + +} diff --git a/jsprit-core/src/main/java/algorithms/MarginalsCalculusTriangleInequality.java b/jsprit-core/src/main/java/algorithms/MarginalsCalculusTriangleInequality.java new file mode 100644 index 00000000..aeb6d2e5 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/MarginalsCalculusTriangleInequality.java @@ -0,0 +1,71 @@ +package algorithms; + +import algorithms.HardConstraints.HardActivityLevelConstraint; +import basics.costs.VehicleRoutingActivityCosts; +import basics.costs.VehicleRoutingTransportCosts; +import basics.route.TourActivity; + +class MarginalsCalculusTriangleInequality implements MarginalsCalculus{ + + private HardActivityLevelConstraint hardConstraint; + + private VehicleRoutingTransportCosts routingCosts; + private VehicleRoutingActivityCosts activityCosts; + + public MarginalsCalculusTriangleInequality(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, HardActivityLevelConstraint hardActivityLevelConstraint) { + super(); + this.routingCosts = routingCosts; + this.activityCosts = actCosts; + this.hardConstraint = hardActivityLevelConstraint; + } + + @Override + public Marginals calculate(InsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) { + double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocationId(), newAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocationId(), newAct.getLocationId(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); + + double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct; + + if(!hardConstraint.fulfilled(iFacts, newAct, newAct_arrTime)){ + return null; + } + + double newAct_endTime = CalcUtils.getStartTimeAtAct(newAct_arrTime, newAct); + + double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + + double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocationId(), nextAct.getLocationId(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + + double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; + + if(!hardConstraint.fulfilled(iFacts, nextAct, nextAct_arrTime)){ + return null; + } + + double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); + + double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct; + + double oldCosts; + double oldTime; + if(iFacts.getRoute().isEmpty()){ + oldCosts = 0.0; + oldTime = 0.0; + } + else{ + double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); + double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocationId(), nextAct.getLocationId(), prevAct.getEndTime(), iFacts.getNewDriver(), iFacts.getNewVehicle()); + + double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); + oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct; + oldTime = (nextAct.getArrTime() - iFacts.getRoute().getDepartureTime()); + } + + double additionalCosts = totalCosts - oldCosts; + double additionalTime = (nextAct_arrTime - iFacts.getNewDepTime()) - oldTime; + + return new Marginals(additionalCosts,additionalTime); + } + +} diff --git a/jsprit-core/src/main/java/algorithms/RegretInsertion.java b/jsprit-core/src/main/java/algorithms/RegretInsertion.java index 46ad780b..fd8806d7 100644 --- a/jsprit-core/src/main/java/algorithms/RegretInsertion.java +++ b/jsprit-core/src/main/java/algorithms/RegretInsertion.java @@ -1,210 +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.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 extends AbstractInsertionStrategy{ - - /** - * 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 run(Collection routes, Collection unassignedJobs, double resultToBeat) { - List jobs = new ArrayList(unassignedJobs); - informInsertionStarts(routes,unassignedJobs.size()); - 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((unassignedJobList.size()-inserted), 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); - - } - -} +// 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/RemoveEmptyVehicles.java b/jsprit-core/src/main/java/algorithms/RemoveEmptyVehicles.java index 49d12618..3a1e7f0b 100644 --- a/jsprit-core/src/main/java/algorithms/RemoveEmptyVehicles.java +++ b/jsprit-core/src/main/java/algorithms/RemoveEmptyVehicles.java @@ -26,11 +26,12 @@ import java.util.List; import org.apache.log4j.Logger; +import basics.Job; import basics.algo.InsertionEndsListener; import basics.algo.InsertionStartsListener; import basics.route.VehicleRoute; -class RemoveEmptyVehicles implements InsertionStartsListener, InsertionEndsListener{ +class RemoveEmptyVehicles implements InsertionEndsListener{ private static Logger log = Logger.getLogger(RemoveEmptyVehicles.class); @@ -41,21 +42,6 @@ class RemoveEmptyVehicles implements InsertionStartsListener, InsertionEndsListe this.fleetManager = fleetManager; } - @Override - public void informInsertionStarts(Collection vehicleRoutes, int nOfJobs2Recreate) { -// List routes = new ArrayList(vehicleRoutes); -// for(VehicleRoute route : routes){ -// if(route.isEmpty()) { vehicleRoutes.remove(route); } -// } -// List routes = new ArrayList(vehicleRoutes); -// for(VehicleRoute route : routes){ -// if(route.isEmpty()) { -// fleetManager.unlock(route.getVehicle()); -// vehicleRoutes.remove(route); -// } -// } - } - @Override public String toString() { return "[name=removeEmptyVehicles]"; diff --git a/jsprit-core/src/main/java/algorithms/ResetAndIniFleetManager.java b/jsprit-core/src/main/java/algorithms/ResetAndIniFleetManager.java index be009119..ff94bbbc 100644 --- a/jsprit-core/src/main/java/algorithms/ResetAndIniFleetManager.java +++ b/jsprit-core/src/main/java/algorithms/ResetAndIniFleetManager.java @@ -25,6 +25,7 @@ import java.util.Collection; import org.apache.log4j.Logger; +import basics.Job; import basics.algo.InsertionStartsListener; import basics.route.VehicleRoute; @@ -40,16 +41,16 @@ class ResetAndIniFleetManager implements InsertionStartsListener{ } @Override - public void informInsertionStarts(Collection vehicleRoutes, int nOfJobs2Recreate) { + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs) { vehicleFleetManager.unlockAll(); Collection routes = new ArrayList(vehicleRoutes); for(VehicleRoute route : routes){ - if(route.isEmpty()){ - vehicleRoutes.remove(route); - } - else{ +// if(route.isEmpty()){ +// vehicleRoutes.remove(route); +// } +// else{ vehicleFleetManager.lock(route.getVehicle()); - } +// } } } diff --git a/jsprit-core/src/main/java/algorithms/RouteAlgorithm.java b/jsprit-core/src/main/java/algorithms/RouteAlgorithm.java deleted file mode 100644 index 351a9fa6..00000000 --- a/jsprit-core/src/main/java/algorithms/RouteAlgorithm.java +++ /dev/null @@ -1,92 +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 java.util.Collection; - -import basics.Job; -import basics.route.Vehicle; -import basics.route.VehicleRoute; - - -interface RouteAlgorithm { - - interface RouteAlgorithmListener { - - } - - interface JobRemovedListener extends RouteAlgorithmListener{ - public void removed(VehicleRoute route, Job job); - } - - interface JobInsertedListener extends RouteAlgorithmListener{ - public void inserted(VehicleRoute route, Job job); - } - - interface VehicleSwitchedListener extends RouteAlgorithmListener{ - public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle); - } - - /** - * Calculates the best insertion position and the corresponding marginal costs of inserting the job (according to the insertionCostCalculator). - * This does not affect any input parameter, thus the vehicleRoute and its data will not be changed/affected. - * - * @param VehicleRoute, Job, double - * @return InsertionData - */ - public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownPrice); - - /** - * Removes job from vehicleRoute and does not update the resulting tour. Thus the tour state might not be valid anymore. - * Note that this changes vehicleRoute! - * - * @return true if job removed successfully, otherwise false - */ - public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute); - - /** - * Removes job from input parameter vehicleRoute AND updates the state of the resulting tour with tourStateCalc. - * Note that this changes para vehicleRoute! - */ - public boolean removeJob(Job job, VehicleRoute vehicleRoute); - - /** - * Inserts job into vehicleRoute.getTour(). - * Please note, that this changes the parameter vehicleRoute! - */ - public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData); - - /** - * Inserts job into vehicleRoute.getTour(). - * Please note, that this changes the parameter vehicleRoute! - */ - public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute); - - /** - * Updates vehicleRoute, i.e. uses the tourStateCalculator to update for example timeWindows and loads on vehicleRoute.getTour() - * Note that this changes the parameter vehicleRoute! - */ - public void updateTour(VehicleRoute vehicleRoute); - - public Collection getListeners(); - - -} diff --git a/jsprit-core/src/main/java/algorithms/RouteAlgorithmImpl.java b/jsprit-core/src/main/java/algorithms/RouteAlgorithmImpl.java deleted file mode 100644 index 6510d054..00000000 --- a/jsprit-core/src/main/java/algorithms/RouteAlgorithmImpl.java +++ /dev/null @@ -1,171 +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.ArrayList; -import java.util.Collection; - -import org.apache.log4j.Logger; - -import algorithms.RouteStates.ActivityState; -import algorithms.InsertionData.NoInsertionFound; -import basics.Job; -import basics.Service; -import basics.route.ServiceActivity; -import basics.route.TourActivity; -import basics.route.Vehicle; -import basics.route.VehicleRoute; - - -/** - * - * @author stefan schroeder - * - */ - -final class RouteAlgorithmImpl implements RouteAlgorithm { - - private static Logger logger = Logger.getLogger(RouteAlgorithmImpl.class); - - static double NO_DEPARTURE_TIME = -12345.12345; - - private String algoDescription = "algorithm to remove and insert jobs from vehicleRoutes. it also calculates marginal costs of the best insertion of a " + - "job into the given vehicle route"; - - public static RouteAlgorithmImpl newInstance(JobInsertionCalculator jobInsertionCalculator, VehicleRouteUpdater tourStateCalculator){ - return new RouteAlgorithmImpl(jobInsertionCalculator, tourStateCalculator); - } - - private Collection listeners = new ArrayList(); - - private VehicleRouteUpdater tourCalculator; - - private JobInsertionCalculator insertionCostCalculator; - - private RouteStates actStates; - - public void setActivityStates(RouteStates actStates){ - this.actStates = actStates; - } - - public ActivityState state(TourActivity act){ - return actStates.getState(act); - } - - private RouteAlgorithmImpl(JobInsertionCalculator insertionCostCalculator, VehicleRouteUpdater tourCalculator){ - this.tourCalculator = tourCalculator; - this.insertionCostCalculator = insertionCostCalculator; - } - - - public InsertionData calculateBestInsertion(VehicleRoute vehicleRoute, Job job, double bestKnownCost) { - return insertionCostCalculator.calculate(vehicleRoute, job, null, NO_DEPARTURE_TIME, null, bestKnownCost); - } - - - public boolean removeJobWithoutTourUpdate(Job job, VehicleRoute vehicleRoute) { - boolean removed = vehicleRoute.getTourActivities().removeJob(job); - if(removed){ - jobRemoved(vehicleRoute,job); - } - return removed; - } - - private void jobRemoved(VehicleRoute vehicleRoute, Job job) { - for(RouteAlgorithmListener l : listeners){ - if(l instanceof JobRemovedListener){ - ((JobRemovedListener) l).removed(vehicleRoute, job); - } - } - } - - - public boolean removeJob(Job job, VehicleRoute vehicleRoute){ - boolean removed = removeJobWithoutTourUpdate(job, vehicleRoute); - if(removed) updateTour(vehicleRoute); - return removed; - } - - - public void updateTour(VehicleRoute vehicleRoute){ - boolean tourIsFeasible = tourCalculator.updateRoute(vehicleRoute); - if(!tourIsFeasible){ - throw new IllegalStateException("At this point tour should be feasible. but it is not. \n currentTour=" + vehicleRoute.getTourActivities() + - "\n error sources: check jobInsertionCostCalculators and actInsertionCalculators. somehow an insertion is made, althought a hard constraint is broken. Here, hard constraints refer to \n" + - "hard time-window constraints. If you want to deal with such constraints, make sure a violation is penalized properly (such that it can never be the best insertion position). \n" + - "If you use CalculatesServiceInsertion and CalculatesActivityInsertion, the only hard constraint is the vehicle-capacity constraints. A violation of time-windows must be penalized in \n" + - "the vehicleRouteCostFunction. For example: in handleActivity(....) one can check whether the act start-time is higher than the latestOperationStartTime. If so penalize it with a very high value. \n" + - "For example: \n" + - "public void handleActivity(TourActivity tourAct, double startTime, double endTime) {\n" + - "\tif(startTime > tourAct.getLatestOperationStartTime()){\n" + - "\t\tcost += Double.MAX_VALUE;\n" + - "\t}\n" + - "});"); - } - } - - - @Override - public void insertJobWithoutTourUpdate(VehicleRoute vehicleRoute, Job job, InsertionData insertionData) { - if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job."); - if(job == null) throw new IllegalStateException("cannot insert null-job"); - if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){ - vehicleSwitched(vehicleRoute.getVehicle(),insertionData.getSelectedVehicle()); - vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime()); - } - if(job instanceof Service) { - vehicleRoute.getTourActivities().addActivity(insertionData.getDeliveryInsertionIndex(), ServiceActivity.newInstance((Service)job)); - vehicleRoute.setDepartureTime(insertionData.getVehicleDepartureTime()); - } - else throw new IllegalStateException("neither service nor shipment. this is not supported."); - jobInserted(vehicleRoute,job); - } - - - - private void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) { - for(RouteAlgorithmListener l : listeners){ - if(l instanceof VehicleSwitchedListener){ - ((VehicleSwitchedListener) l).vehicleSwitched(oldVehicle,newVehicle); - } - } - } - - private void jobInserted(VehicleRoute vehicleRoute, Job job) { - for(RouteAlgorithmListener l : listeners){ - if(l instanceof JobInsertedListener){ - ((JobInsertedListener) l).inserted(vehicleRoute, job); - } - } - } - - - public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){ - insertJobWithoutTourUpdate(vehicleRoute, job, insertionData); - updateTour(vehicleRoute); - } - - @Override - public String toString() { - return algoDescription; - } - - public Collection getListeners() { - return listeners; - } - - public void setAlgoDescription(String algoDescription) { - this.algoDescription = algoDescription; - } - -} diff --git a/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java b/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java new file mode 100644 index 00000000..f6d12397 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/RuinAndRecreateModule.java @@ -0,0 +1,59 @@ +package algorithms; + +import java.util.Collection; + +import util.RouteUtils; +import algorithms.RuinStrategy.RuinListener; +import basics.Job; +import basics.VehicleRoutingProblemSolution; +import basics.algo.InsertionListener; +import basics.algo.SearchStrategyModule; +import basics.algo.SearchStrategyModuleListener; + +class RuinAndRecreateModule implements SearchStrategyModule{ + + private InsertionStrategy insertion; + + private RuinStrategy ruin; + + private String moduleName; + + public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) { + super(); + this.insertion = insertion; + this.ruin = ruin; + this.moduleName = moduleName; + } + + @Override + public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { + Collection ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); + insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs); + double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); + vrpSolution.setCost(totalCost); + return vrpSolution; + } + + @Override + public String getName() { + return moduleName; + } + + @Override + public void addModuleListener(SearchStrategyModuleListener moduleListener) { + if(moduleListener instanceof InsertionListener){ + InsertionListener iListener = (InsertionListener) moduleListener; + if(!insertion.getListeners().contains(iListener)){ + insertion.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/RuinListeners.java b/jsprit-core/src/main/java/algorithms/RuinListeners.java new file mode 100644 index 00000000..08b91488 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/RuinListeners.java @@ -0,0 +1,38 @@ +package algorithms; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import algorithms.RuinStrategy.RuinListener; +import basics.Job; +import basics.route.VehicleRoute; + +class RuinListeners { + + private Collection ruinListeners = new ArrayList(); + + void ruinStarts(Collection routes){ + for(RuinListener l : ruinListeners) l.ruinStarts(routes); + } + + void ruinEnds(Collection routes, Collection unassignedJobs){ + for(RuinListener l : ruinListeners) l.ruinEnds(routes, unassignedJobs); + } + + void removed(Job job, VehicleRoute fromRoute){ + for(RuinListener l : ruinListeners) l.removed(job, fromRoute); + } + + void addListener(RuinListener ruinListener){ + ruinListeners.add(ruinListener); + } + + void removeListener(RuinListener ruinListener){ + ruinListeners.remove(ruinListener); + } + + Collection getListeners(){ + return Collections.unmodifiableCollection(ruinListeners); + } +} diff --git a/jsprit-core/src/main/java/algorithms/RuinRadial.java b/jsprit-core/src/main/java/algorithms/RuinRadial.java index 82cb3ed6..2e293468 100644 --- a/jsprit-core/src/main/java/algorithms/RuinRadial.java +++ b/jsprit-core/src/main/java/algorithms/RuinRadial.java @@ -29,29 +29,11 @@ import util.RandomNumberGeneration; import util.StopWatch; import basics.Job; import basics.VehicleRoutingProblem; -import basics.VehicleRoutingProblemSolution; -import basics.algo.SearchStrategyModule; import basics.route.VehicleRoute; final class RuinRadial implements RuinStrategy { - - private final static String NAME = "radialRuin"; - - /** - * returns a new creation of instance of ruinRadial - * @param vrp - * @param fraction TODO - * @param jobDistance - * @param jobRemover TODO - * @param routeUpdater TODO - * @return - */ - static RuinRadial newInstance(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance, JobRemover jobRemover, VehicleRouteUpdater routeUpdater){ - return new RuinRadial(vrp, fraction, jobDistance, jobRemover, routeUpdater); - } - static class ReferencedJob { private Job job; @@ -84,21 +66,18 @@ final class RuinRadial implements RuinStrategy { private JobDistance jobDistance; - private JobRemover jobRemover; + private RuinListeners ruinListeners; - private VehicleRouteUpdater routeUpdater; - public void setRandom(Random random) { this.random = random; } - public RuinRadial(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance, JobRemover jobRemover, VehicleRouteUpdater routeUpdater) { + public RuinRadial(VehicleRoutingProblem vrp, double fraction, JobDistance jobDistance) { super(); this.vrp = vrp; this.jobDistance = jobDistance; - this.jobRemover = jobRemover; - this.routeUpdater = routeUpdater; this.fractionOfAllNodes2beRuined = fraction; + ruinListeners = new RuinListeners(); calculateDistancesFromJob2Job(); logger.info("intialise " + this); } @@ -158,6 +137,7 @@ final class RuinRadial implements RuinStrategy { } public Collection ruin(Collection vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved){ + ruinListeners.ruinStarts(vehicleRoutes); List unassignedJobs = new ArrayList(); TreeSet tree = distanceNodeTree.get(targetJob.getId()); Iterator descendingIterator = tree.descendingIterator(); @@ -169,15 +149,14 @@ final class RuinRadial implements RuinStrategy { counter++; boolean removed = false; for (VehicleRoute route : vehicleRoutes) { - removed = jobRemover.removeJobWithoutTourUpdate(job, route); + removed = route.getTourActivities().removeJob(job);; if (removed) { + ruinListeners.removed(job,route); break; } } } - for(VehicleRoute route : vehicleRoutes){ - routeUpdater.updateRoute(route); - } + ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs); return unassignedJobs; } @@ -193,15 +172,20 @@ final class RuinRadial implements RuinStrategy { * fractionOfAllNodes2beRuined); } -// @Override -// public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { -// ruin(vrpSolution.getRoutes()); -// return vrpSolution; -// } -// -// @Override -// public String getName() { -// return NAME; -// } + @Override + public void addListener(RuinListener ruinListener) { + ruinListeners.addListener(ruinListener); + } + + @Override + public void removeListener(RuinListener ruinListener) { + ruinListeners.removeListener(ruinListener); + } + + @Override + public Collection getListeners() { + return ruinListeners.getListeners(); + } + } diff --git a/jsprit-core/src/main/java/algorithms/RuinRandom.java b/jsprit-core/src/main/java/algorithms/RuinRandom.java index 9180f13a..3695a2dd 100644 --- a/jsprit-core/src/main/java/algorithms/RuinRandom.java +++ b/jsprit-core/src/main/java/algorithms/RuinRandom.java @@ -35,10 +35,6 @@ import basics.route.VehicleRoute; */ final class RuinRandom implements RuinStrategy { - - public static RuinRandom newInstance(VehicleRoutingProblem vrp, double fraction, JobRemover jobRemover, VehicleRouteUpdater routeUpdater){ - return new RuinRandom(vrp, fraction, jobRemover, routeUpdater); - } private Logger logger = Logger.getLogger(RuinRandom.class); @@ -47,10 +43,8 @@ final class RuinRandom implements RuinStrategy { private double fractionOfAllNodes2beRuined; private Random random = RandomNumberGeneration.getRandom(); - - private JobRemover jobRemover; - - private VehicleRouteUpdater vehicleRouteUpdater; + + private RuinListeners ruinListeners; public void setRandom(Random random) { this.random = random; @@ -61,15 +55,12 @@ final class RuinRandom implements RuinStrategy { * * @param vrp * @param fraction which is the fraction of total c - * @param jobRemover - * @param vehicleRouteUpdater */ - public RuinRandom(VehicleRoutingProblem vrp, double fraction, JobRemover jobRemover, VehicleRouteUpdater vehicleRouteUpdater) { + public RuinRandom(VehicleRoutingProblem vrp, double fraction) { super(); this.vrp = vrp; - this.jobRemover = jobRemover; - this.vehicleRouteUpdater = vehicleRouteUpdater; this.fractionOfAllNodes2beRuined = fraction; + ruinListeners = new RuinListeners(); logger.info("initialise " + this); logger.info("done"); } @@ -81,9 +72,11 @@ final class RuinRandom implements RuinStrategy { */ @Override public Collection ruin(Collection vehicleRoutes) { + ruinListeners.ruinStarts(vehicleRoutes); List unassignedJobs = new ArrayList(); int nOfJobs2BeRemoved = selectNuOfJobs2BeRemoved(); ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs); + ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs); return unassignedJobs; } @@ -92,19 +85,22 @@ final class RuinRandom implements RuinStrategy { */ @Override public Collection ruin(Collection vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved) { + ruinListeners.ruinStarts(vehicleRoutes); List unassignedJobs = new ArrayList(); if(targetJob != null){ boolean removed = false; for (VehicleRoute route : vehicleRoutes) { - removed = jobRemover.removeJobWithoutTourUpdate(targetJob, route); + removed = route.getTourActivities().removeJob(targetJob); if (removed) { nOfJobs2BeRemoved--; unassignedJobs.add(targetJob); + ruinListeners.removed(targetJob,route); break; } } } ruin(vehicleRoutes, nOfJobs2BeRemoved, unassignedJobs); + ruinListeners.ruinEnds(vehicleRoutes, unassignedJobs); return unassignedJobs; } @@ -113,27 +109,23 @@ final class RuinRandom implements RuinStrategy { logger.info("fraction set " + this); } - private void ruin(Collection vehicleRoutes,int nOfJobs2BeRemoved, List unassignedJobs) { + private void ruin(Collection vehicleRoutes, int nOfJobs2BeRemoved, List unassignedJobs) { LinkedList availableJobs = new LinkedList(vrp.getJobs().values()); for (int i = 0; i < nOfJobs2BeRemoved; i++) { Job job = pickRandomJob(availableJobs); unassignedJobs.add(job); availableJobs.remove(job); for (VehicleRoute route : vehicleRoutes) { - boolean removed = jobRemover.removeJobWithoutTourUpdate(job, route); - if (removed) break; + boolean removed = route.getTourActivities().removeJob(job); + if (removed) { + ruinListeners.removed(job,route); + break; + } } } - updateRoutes(vehicleRoutes); } - private void updateRoutes(Collection vehicleRoutes) { - for(VehicleRoute route : vehicleRoutes){ - vehicleRouteUpdater.updateRoute(route); - } - } - - + @Override public String toString() { return "[name=randomRuin][fraction="+fractionOfAllNodes2beRuined+"]"; @@ -148,4 +140,19 @@ final class RuinRandom implements RuinStrategy { return (int) Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined); } + @Override + public void addListener(RuinListener ruinListener) { + ruinListeners.addListener(ruinListener); + } + + @Override + public void removeListener(RuinListener ruinListener) { + ruinListeners.removeListener(ruinListener); + } + + @Override + public Collection getListeners() { + return ruinListeners.getListeners(); + } + } diff --git a/jsprit-core/src/main/java/algorithms/RuinStrategy.java b/jsprit-core/src/main/java/algorithms/RuinStrategy.java index 67cf868a..603050d7 100644 --- a/jsprit-core/src/main/java/algorithms/RuinStrategy.java +++ b/jsprit-core/src/main/java/algorithms/RuinStrategy.java @@ -13,7 +13,6 @@ package algorithms; import java.util.Collection; -import java.util.List; import basics.Job; import basics.route.VehicleRoute; @@ -29,19 +28,62 @@ import basics.route.VehicleRoute; interface RuinStrategy { + /** + * Listener that listens to the ruin-process. It informs whoever is interested about start, end and about a removal of a job. + * + * @author schroeder + * + */ public static interface RuinListener { + /** + * informs about ruin-start. + * + * @param routes + */ + public void ruinStarts(Collection routes); + + /** + * informs about ruin-end. + * + * @param routes + * @param unassignedJobs + */ + public void ruinEnds(Collection routes, Collection unassignedJobs); + + /** + * informs if a {@link Job} has been removed from a {@link VehicleRoute}. + * + * @param job + * @param fromRoute + */ + public void removed(Job job, VehicleRoute fromRoute); + } /** - * Ruins a current solution, i.e. removes jobs from service providers and - * returns a collection of these removed, and thus unassigned, jobs. + * Ruins a current solution, i.e. a collection of vehicle-routes and + * returns a collection of removed and thus unassigned jobs. * - * @param vehicleRoutes - * @return + * @param {@link VehicleRoute} + * @return Collection of {@link Job} */ public Collection ruin(Collection vehicleRoutes); + /** + * Removes targetJob as well as its neighbors with a size of (nOfJobs2BeRemoved-1). + */ public Collection ruin(Collection vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved); + + /** + * Adds a ruin-listener. + * + * @param {@link RuinListener} + */ + public void addListener(RuinListener ruinListener); + + public void removeListener(RuinListener ruinListener); + + public Collection getListeners(); } diff --git a/jsprit-core/src/main/java/algorithms/StateManager.java b/jsprit-core/src/main/java/algorithms/StateManager.java new file mode 100644 index 00000000..e0734ae4 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/StateManager.java @@ -0,0 +1,52 @@ +package algorithms; + +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +interface StateManager { + + interface State { + double toDouble(); + } + + class StateImpl implements State{ + double state; + + public StateImpl(double state) { + super(); + this.state = state; + } + + @Override + public double toDouble() { + return state; + } + +// public void setState(double val){ +// state=val; +// } + } + + interface States { + +// void putState(String key, State state); + + State getState(String key); + + } + + + +// Map getRouteStates(); + +// void put(VehicleRoute route, States states); + +// 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/StateManagerImpl.java b/jsprit-core/src/main/java/algorithms/StateManagerImpl.java new file mode 100644 index 00000000..b16f0d2c --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/StateManagerImpl.java @@ -0,0 +1,121 @@ +package algorithms; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class StateManagerImpl implements StateManager{ + + static class StatesImpl implements States{ + + private Map states = new HashMap(); + + public void putState(String key, State state) { + states.put(key, state); + } + + @Override + public State getState(String key) { + return states.get(key); + } + + } + + private Map vehicleRouteStates = new HashMap(); + + private Map activityStates = new HashMap(); + + public Map getRouteStates() { + return Collections.unmodifiableMap(vehicleRouteStates); + } + + public States getRouteStates(VehicleRoute route){ + return vehicleRouteStates.get(route); + } + + public void put(VehicleRoute route, States states) { + vehicleRouteStates.put(route, states); + } + + public Map getActivityStates() { + return Collections.unmodifiableMap(activityStates); + } + + 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/StateTypes.java b/jsprit-core/src/main/java/algorithms/StateTypes.java new file mode 100644 index 00000000..2306281d --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/StateTypes.java @@ -0,0 +1,13 @@ +package algorithms; + +class StateTypes { + final static String LOAD = "load"; + + 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/TourConstraintEngine.java b/jsprit-core/src/main/java/algorithms/TourConstraintEngine.java deleted file mode 100644 index 6cd3e758..00000000 --- a/jsprit-core/src/main/java/algorithms/TourConstraintEngine.java +++ /dev/null @@ -1,34 +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 basics.Job; -import basics.route.VehicleRoute; - -class TourConstraintEngine { - -// void ini(VehicleRoute route, Job job){ -// -// } -// - - -} 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 b46af2ec..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.setActivityStates(actStates); - backwardUpdate.setActivityStates(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..b058549f --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UdateCostsAtRouteLevel.java @@ -0,0 +1,62 @@ +package algorithms; + +import java.util.Collection; + +import algorithms.StateManager.StateImpl; +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 StateManagerImpl states; + + private VehicleRoutingTransportCosts tpCosts; + + private VehicleRoutingActivityCosts actCosts; + + public UdateCostsAtRouteLevel(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) { + 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){ + if(route.isEmpty()) continue; + route.getVehicleRouteCostCalculator().reset(); + route.getVehicleRouteCostCalculator().addOtherCost(states.getRouteState(route, StateTypes.COSTS).toDouble()); + route.getVehicleRouteCostCalculator().price(route.getVehicle()); +// 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..308739c6 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateActivityTimes.java @@ -0,0 +1,31 @@ +package algorithms; + +import org.apache.log4j.Logger; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class UpdateActivityTimes implements ForwardInTimeListener{ + + private Logger log = Logger.getLogger(UpdateActivityTimes.class); + + @Override + public void start(VehicleRoute route, Start start, double departureTime) { + start.setEndTime(departureTime); + } + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + act.setArrTime(arrTime); + act.setEndTime(endTime); + } + + @Override + public void end(End end, double arrivalTime) { + end.setArrTime(arrivalTime); + } + +} 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..2cc6bcf7 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateCostsAtAllLevels.java @@ -0,0 +1,84 @@ +package algorithms; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import algorithms.StateManager.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 StateManagerImpl 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, StateManagerImpl states) { + super(); + this.activityCost = activityCost; + this.transportCost = transportCost; + this.states = states; + } + + @Override + public void start(VehicleRoute route, Start start, double departureTime) { + vehicleRoute = route; + vehicleRoute.getVehicleRouteCostCalculator().reset(); + prevAct = start; + startTimeAtPrevAct = departureTime; + } + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + 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; + + states.putActivityState(act, StateTypes.COSTS, new StateImpl(totalOperationCost)); + + prevAct = act; + startTimeAtPrevAct = endTime; + } + + @Override + public void end(End end, double arrivalTime) { + double transportCost = this.transportCost.getTransportCost(prevAct.getLocationId(), end.getLocationId(), startTimeAtPrevAct, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); + double actCost = activityCost.getActivityCost(end, arrivalTime, vehicleRoute.getDriver(), vehicleRoute.getVehicle()); + + vehicleRoute.getVehicleRouteCostCalculator().addTransportCost(transportCost); + vehicleRoute.getVehicleRouteCostCalculator().addActivityCost(actCost); + + totalOperationCost += transportCost; + totalOperationCost += actCost; + + 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..1fab69ef --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateEarliestStartTimeWindowAtActLocations.java @@ -0,0 +1,30 @@ +package algorithms; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import algorithms.StateManager.StateImpl; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class UpdateEarliestStartTimeWindowAtActLocations implements ForwardInTimeListener{ + + private StateManagerImpl states; + + public UpdateEarliestStartTimeWindowAtActLocations(StateManagerImpl states) { + super(); + this.states = states; + } + + @Override + public void start(VehicleRoute route, Start start, double departureTime) {} + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + states.putActivityState(act, StateTypes.EARLIEST_OPERATION_START_TIME, new StateImpl(Math.max(arrTime, act.getTheoreticalEarliestOperationStartTime()))); + } + + @Override + public void end(End end, double arrivalTime) {} + +} 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..6c65282e --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateLatestOperationStartTimeAtActLocations.java @@ -0,0 +1,32 @@ +package algorithms; + +import algorithms.BackwardInTimeListeners.BackwardInTimeListener; +import algorithms.StateManager.StateImpl; +import basics.route.End; +import basics.route.Start; +import basics.route.TourActivity; +import basics.route.VehicleRoute; + +class UpdateLatestOperationStartTimeAtActLocations implements BackwardInTimeListener{ + + private StateManagerImpl states; + + public UpdateLatestOperationStartTimeAtActLocations(StateManagerImpl states) { + super(); + this.states = states; + } + + @Override + public void start(VehicleRoute route, End end, double latestArrivalTime) {} + + @Override + public void prevActivity(TourActivity act,double latestDepartureTime, double latestOperationStartTime) { + states.putActivityState(act, StateTypes.LATEST_OPERATION_START_TIME, new StateImpl(latestOperationStartTime)); + } + + @Override + public void end(Start start, double latestDepartureTime) {} + + + +} 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..5de4cdc2 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateLoadAtAllLevels.java @@ -0,0 +1,45 @@ +package algorithms; + +import algorithms.ForwardInTimeListeners.ForwardInTimeListener; +import algorithms.StateManager.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 StateManagerImpl states; + + private VehicleRoute vehicleRoute; + + public UpdateLoadAtAllLevels(StateManagerImpl states) { + super(); + this.states = states; + } + + @Override + public void start(VehicleRoute route, Start start, double departureTime) { vehicleRoute = route; } + + @Override + public void nextActivity(TourActivity act, double arrTime, double endTime) { + load += (double)act.getCapacityDemand(); + states.putActivityState(act, StateTypes.LOAD, new StateImpl(load)); + } + + @Override + public void end(End end, double arrivalTime) { + 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..5ed2adc1 --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/UpdateLoadAtRouteLevel.java @@ -0,0 +1,42 @@ +package algorithms; + +import java.util.Collection; + +import algorithms.StateManager.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 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)); + } + + } + +} 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..0d61558d --- /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; + +class UpdateStates implements JobInsertedListener, RuinListener{ + + private IterateRouteForwardInTime iterateForward; + + private IterateRouteBackwardInTime iterateBackward; + + public UpdateStates(StateManagerImpl 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 19a8d5e3..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 setActivityStates(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 96732e5c..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 setActivityStates(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 71631a38..0f52a27c 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java +++ b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java @@ -36,7 +36,8 @@ import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Logger; import util.RouteUtils; -import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractInsertionKey; +import algorithms.RuinStrategy.RuinListener; +import algorithms.VehicleRoutingAlgorithms.TypedMap.InsertionStrategyKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.AbstractKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.AcceptorKey; import algorithms.VehicleRoutingAlgorithms.TypedMap.RuinStrategyKey; @@ -56,19 +57,21 @@ 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.SearchStrategy.DiscoveredSolution; import basics.algo.VehicleRoutingAlgorithmListeners.PrioritizedVRAListener; import basics.algo.VehicleRoutingAlgorithmListeners.Priority; import basics.io.AlgorithmConfig; import basics.io.AlgorithmConfigXmlReader; +import basics.route.VehicleRoute; @@ -258,11 +261,11 @@ public class VehicleRoutingAlgorithms { } - static class AbstractInsertionKey implements AbstractKey{ + static class InsertionStrategyKey implements AbstractKey{ private ModKey modKey; - public AbstractInsertionKey(ModKey modKey) { + public InsertionStrategyKey(ModKey modKey) { super(); this.modKey = modKey; } @@ -284,7 +287,7 @@ public class VehicleRoutingAlgorithms { return false; if (getClass() != obj.getClass()) return false; - AbstractInsertionKey other = (AbstractInsertionKey) obj; + InsertionStrategyKey other = (InsertionStrategyKey) obj; if (modKey == null) { if (other.modKey != null) return false; @@ -296,8 +299,8 @@ public class VehicleRoutingAlgorithms { @Override - public Class getType() { - return AbstractInsertionStrategy.class; + public Class getType() { + return InsertionStrategy.class; } } @@ -445,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 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)); + +// 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(); @@ -533,16 +548,14 @@ public class VehicleRoutingAlgorithms { private static void registerInsertionListeners(TypedMap definedClasses, List insertionListeners) { for(AbstractKey key : definedClasses.keySet()){ - if(key instanceof AbstractInsertionKey){ - AbstractInsertionKey insertionKey = (AbstractInsertionKey) key; - AbstractInsertionStrategy insertionStrategy = definedClasses.get(insertionKey); + if(key instanceof InsertionStrategyKey){ + InsertionStrategyKey insertionKey = (InsertionStrategyKey) key; + InsertionStrategy insertionStrategy = definedClasses.get(insertionKey); for(InsertionListener l : insertionListeners){ - // log.info("add insertionListener " + l + " to " + insertionStrategy); insertionStrategy.addListener(l); } } } - // log.warn("cannot register insertion listeners yet"); } private static String getName(HierarchicalConfiguration strategyConfig) { @@ -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, StateManagerImpl 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; @@ -568,15 +581,15 @@ public class VehicleRoutingAlgorithms { String insertionId = modConfig.getString("[@id]"); if(insertionId == null) insertionId = "noId"; ModKey modKey = makeKey(insertionName,insertionId); - AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(modKey); - AbstractInsertionStrategy insertionStrategy = definedClasses.get(insertionStrategyKey); + InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(modKey); + 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); } - final AbstractInsertionStrategy finalInsertionStrategy = insertionStrategy; + final InsertionStrategy finalInsertionStrategy = insertionStrategy; return new AlgorithmStartsListener() { @@ -653,8 +666,8 @@ public class VehicleRoutingAlgorithms { } } - private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, - RouteStates activityStates, Set algorithmListeners, TypedMap definedClasses, ExecutorService executorService, int nuOfThreads) { + private static SearchStrategyModule buildModule(HierarchicalConfiguration moduleConfig, final VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, + final StateManagerImpl 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."); @@ -697,16 +710,16 @@ public class VehicleRoutingAlgorithms { String insertionId = moduleConfig.getString("insertion[@id]"); if(insertionId == null) insertionId = "noId"; ModKey insertionKey = makeKey(insertionName,insertionId); - AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(insertionKey); - AbstractInsertionStrategy insertion = definedClasses.get(insertionStrategyKey); + InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(insertionKey); + InsertionStrategy insertion = definedClasses.get(insertionStrategyKey); if(insertion == null){ 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 AbstractInsertionStrategy final_insertion = insertion; + final InsertionStrategy final_insertion = insertion; SearchStrategyModule module = new SearchStrategyModule() { private Logger logger = Logger.getLogger(SearchStrategyModule.class); @@ -714,7 +727,7 @@ public class VehicleRoutingAlgorithms { @Override public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { Collection ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); - final_insertion.run(vrpSolution.getRoutes(), ruinedJobs, Double.MAX_VALUE); + final_insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobs); double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); vrpSolution.setCost(totalCost); return vrpSolution; @@ -734,7 +747,7 @@ public class VehicleRoutingAlgorithms { public void addModuleListener(SearchStrategyModuleListener moduleListener) { if(moduleListener instanceof InsertionListener){ InsertionListener iListener = (InsertionListener) moduleListener; - if(!final_insertion.getListener().contains(iListener)){ + if(!final_insertion.getListeners().contains(iListener)){ logger.info("register moduleListener " + moduleListener); final_insertion.addListener(iListener); } @@ -746,41 +759,42 @@ public class VehicleRoutingAlgorithms { return module; } - if(moduleName.equals("gendreauPostOpt")){ + if(moduleName.equals("gendreau")){ int iterations = moduleConfig.getInt("iterations"); double share = moduleConfig.getDouble("share"); String ruinName = moduleConfig.getString("ruin[@name]"); - if(ruinName == null) throw new IllegalStateException("gendreauPostOpt.ruin[@name] is missing. set it to \"radialRuin\" or \"randomRuin\""); + if(ruinName == null) throw new IllegalStateException("gendreau.ruin[@name] is missing. set it to \"radialRuin\" or \"randomRuin\""); String ruinId = moduleConfig.getString("ruin[@id]"); if(ruinId == null) ruinId = "noId"; ModKey ruinKey = makeKey(ruinName,ruinId); RuinStrategyKey stratKey = new RuinStrategyKey(ruinKey); RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ - ruin = RuinRadial.newInstance(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts())); + ruin = new RuinRadial(vrp, 0.3, new JobDistanceAvgCosts(vrp.getTransportCosts())); + ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } String insertionName = moduleConfig.getString("insertion[@name]"); - if(insertionName == null) throw new IllegalStateException("gendreauPostOpt.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\""); + if(insertionName == null) throw new IllegalStateException("gendreau.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\""); String insertionId = moduleConfig.getString("insertion[@id]"); if(insertionId == null) insertionId = "noId"; ModKey insertionKey = makeKey(insertionName,insertionId); - AbstractInsertionKey insertionStrategyKey = new AbstractInsertionKey(insertionKey); - AbstractInsertionStrategy insertion = definedClasses.get(insertionStrategyKey); + InsertionStrategyKey insertionStrategyKey = new InsertionStrategyKey(insertionKey); + InsertionStrategy insertion = definedClasses.get(insertionStrategyKey); if(insertion == null){ 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); } - GendreauPostOpt postOpt = new GendreauPostOpt(vrp, ruin, insertion); - postOpt.setShareOfJobsToRuin(share); - postOpt.setNuOfIterations(iterations); - postOpt.setFleetManager(vehicleFleetManager); - definedClasses.put(strategyModuleKey, postOpt); - return postOpt; + Gendreau gendreau = new Gendreau(vrp, ruin, insertion); + gendreau.setShareOfJobsToRuin(share); + gendreau.setNuOfIterations(iterations); + gendreau.setFleetManager(vehicleFleetManager); + definedClasses.put(strategyModuleKey, gendreau); + return gendreau; } throw new NullPointerException("no module found with moduleName=" + moduleName + "\n\tcheck config whether the correct names are used" + @@ -791,30 +805,30 @@ public class VehicleRoutingAlgorithms { "\n\tgendreauPostOpt"); } - private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp, RouteStates activityStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) { + private static RuinStrategy getRadialRuin(final VehicleRoutingProblem vrp, final StateManagerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) { RuinStrategyKey stratKey = new RuinStrategyKey(modKey); RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ - ruin = RuinRadial.newInstance(vrp, shareToRuin, jobDistance, new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts())); + ruin = new RuinRadial(vrp, shareToRuin, jobDistance); + ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } return ruin; } - private static RuinStrategy getRandomRuin(VehicleRoutingProblem vrp, - RouteStates activityStates, TypedMap definedClasses, - ModKey modKey, double shareToRuin) { + private static RuinStrategy getRandomRuin(final VehicleRoutingProblem vrp, final StateManagerImpl routeStates, TypedMap definedClasses, ModKey modKey, double shareToRuin) { RuinStrategyKey stratKey = new RuinStrategyKey(modKey); RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ - ruin = RuinRandom.newInstance(vrp, shareToRuin, new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts())); + ruin = new RuinRandom(vrp, shareToRuin); + ruin.addListener(new UpdateStates(routeStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } return ruin; } - private static AbstractInsertionStrategy createInsertionStrategy(HierarchicalConfiguration moduleConfig, VehicleRoutingProblem vrp,VehicleFleetManager vehicleFleetManager, RouteStates activityStates, List algorithmListeners, ExecutorService executorService, int nuOfThreads) { - AbstractInsertionStrategy insertion = InsertionFactory.createInsertion(vrp, moduleConfig, vehicleFleetManager, activityStates, algorithmListeners, executorService, nuOfThreads); + 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); return insertion; } diff --git a/jsprit-core/src/main/java/algorithms/VehicleSwitched.java b/jsprit-core/src/main/java/algorithms/VehicleSwitched.java index cd0b6bb4..1ffabe42 100644 --- a/jsprit-core/src/main/java/algorithms/VehicleSwitched.java +++ b/jsprit-core/src/main/java/algorithms/VehicleSwitched.java @@ -21,7 +21,8 @@ package algorithms; import basics.route.Vehicle; -import algorithms.RouteAlgorithm.VehicleSwitchedListener; +import basics.route.VehicleRoute; + class VehicleSwitched implements VehicleSwitchedListener{ @@ -32,7 +33,7 @@ class VehicleSwitched implements VehicleSwitchedListener{ } @Override - public void vehicleSwitched(Vehicle oldVehicle, Vehicle newVehicle) { + public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle) { fleetManager.unlock(oldVehicle); fleetManager.lock(newVehicle); } diff --git a/jsprit-core/src/main/java/algorithms/VehicleSwitchedListener.java b/jsprit-core/src/main/java/algorithms/VehicleSwitchedListener.java new file mode 100644 index 00000000..a3589f5d --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/VehicleSwitchedListener.java @@ -0,0 +1,11 @@ +package algorithms; + +import basics.algo.InsertionListener; +import basics.route.Vehicle; +import basics.route.VehicleRoute; + +interface VehicleSwitchedListener extends InsertionListener{ + + public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle); + +} diff --git a/jsprit-core/src/main/java/basics/algo/InsertionStartsListener.java b/jsprit-core/src/main/java/basics/algo/InsertionStartsListener.java index a62459cd..8f8ea757 100644 --- a/jsprit-core/src/main/java/basics/algo/InsertionStartsListener.java +++ b/jsprit-core/src/main/java/basics/algo/InsertionStartsListener.java @@ -22,10 +22,11 @@ package basics.algo; import java.util.Collection; +import basics.Job; import basics.route.VehicleRoute; public interface InsertionStartsListener extends InsertionListener { - public void informInsertionStarts(Collection vehicleRoutes, int nOfJobs2Recreate); + public void informInsertionStarts(Collection vehicleRoutes, Collection unassignedJobs); } diff --git a/jsprit-core/src/main/java/basics/algo/JobInsertedListener.java b/jsprit-core/src/main/java/basics/algo/JobInsertedListener.java index 5cce5484..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(int nOfJobsStill2Recreate, Job job2insert, VehicleRoute insertedIn); + public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime); } diff --git a/jsprit-core/src/main/java/basics/io/VrpXMLReader.java b/jsprit-core/src/main/java/basics/io/VrpXMLReader.java index 308e633a..e7c93c63 100644 --- a/jsprit-core/src/main/java/basics/io/VrpXMLReader.java +++ b/jsprit-core/src/main/java/basics/io/VrpXMLReader.java @@ -274,7 +274,7 @@ public class VrpXMLReader{ if(distC != null) typeBuilder.setCostPerDistance(distC); // if(start != null && end != null) typeBuilder.setTimeSchedule(new TimeSchedule(start, end)); VehicleTypeImpl type = typeBuilder.build(); - types.put(type.typeId, type); + types.put(type.getTypeId(), type); vrpBuilder.addVehicleType(type); } diff --git a/jsprit-core/src/main/java/basics/route/End.java b/jsprit-core/src/main/java/basics/route/End.java index b39aead4..ba3f6f2a 100644 --- a/jsprit-core/src/main/java/basics/route/End.java +++ b/jsprit-core/src/main/java/basics/route/End.java @@ -61,12 +61,15 @@ public final class End implements TourActivity { this.locationId = locationId; theoretical_earliestOperationStartTime = theoreticalStart; theoretical_latestOperationStartTime = theoreticalEnd; + endTime = theoreticalEnd; } public End(End end) { this.locationId = end.getLocationId(); theoretical_earliestOperationStartTime = end.getTheoreticalEarliestOperationStartTime(); theoretical_latestOperationStartTime = end.getTheoreticalLatestOperationStartTime(); + arrTime = end.getArrTime(); + endTime = end.getEndTime(); } public double getTheoreticalEarliestOperationStartTime() { diff --git a/jsprit-core/src/main/java/basics/route/PenaltyVehicleType.java b/jsprit-core/src/main/java/basics/route/PenaltyVehicleType.java index 9963a00c..29582267 100644 --- a/jsprit-core/src/main/java/basics/route/PenaltyVehicleType.java +++ b/jsprit-core/src/main/java/basics/route/PenaltyVehicleType.java @@ -26,6 +26,11 @@ public class PenaltyVehicleType implements VehicleType{ return type.getVehicleCostParams(); } + @Override + public double getMaxVelocity() { + return type.getMaxVelocity(); + } + } diff --git a/jsprit-core/src/main/java/basics/route/TourActivities.java b/jsprit-core/src/main/java/basics/route/TourActivities.java index eed81154..2524b13b 100644 --- a/jsprit-core/src/main/java/basics/route/TourActivities.java +++ b/jsprit-core/src/main/java/basics/route/TourActivities.java @@ -76,15 +76,9 @@ public class TourActivities { } private final ArrayList tourActivities = new ArrayList(); -// private final LinkedList tourActivities = new LinkedList(); -// private final TreeList tourActivities = new TreeList(); private final Set jobs = new HashSet(); - private int load = 0; - - private double cost = 0.0; - private ReverseActivityIterator backward; private TourActivities(TourActivities tour2copy) { @@ -125,7 +119,7 @@ public class TourActivities { } /** - * Removes job AND belonging activity from tour. + * Removes job AND belonging activity from tour and returns true if job has been removed, otherwise false. * * @param job * @return diff --git a/jsprit-core/src/main/java/basics/route/VehicleRoute.java b/jsprit-core/src/main/java/basics/route/VehicleRoute.java index e7bf3814..95c8f3e0 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/basics/route/VehicleRoute.java @@ -158,6 +158,11 @@ public class VehicleRoute { start.setEndTime(vehicleDepTime); } + public double getDepartureTime(){ + if(start == null) throw new IllegalStateException("cannot get departureTime without having a vehicle on this route. use setVehicle(vehicle,departureTime) instead."); + return start.getEndTime(); + } + private void setStartAndEnd(Vehicle vehicle, double vehicleDepTime) { if(!(vehicle instanceof NoVehicle)){ if(start == null && end == null){ diff --git a/jsprit-core/src/main/java/basics/route/VehicleType.java b/jsprit-core/src/main/java/basics/route/VehicleType.java index e0870532..9558ba62 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleType.java +++ b/jsprit-core/src/main/java/basics/route/VehicleType.java @@ -8,6 +8,8 @@ public interface VehicleType { public String getTypeId(); public int getCapacity(); + + public double getMaxVelocity(); public VehicleCostParams getVehicleCostParams(); diff --git a/jsprit-core/src/main/java/basics/route/VehicleTypeImpl.java b/jsprit-core/src/main/java/basics/route/VehicleTypeImpl.java index aa3a7820..3e62c292 100644 --- a/jsprit-core/src/main/java/basics/route/VehicleTypeImpl.java +++ b/jsprit-core/src/main/java/basics/route/VehicleTypeImpl.java @@ -35,6 +35,7 @@ public class VehicleTypeImpl implements VehicleType { private String id; private int capacity; + private double maxVelo = Double.MAX_VALUE; /** * default cost values for default vehicle type */ @@ -48,6 +49,8 @@ public class VehicleTypeImpl implements VehicleType { this.capacity = capacity; } + public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds){ this.maxVelo = inMeterPerSeconds; return this; } + public VehicleTypeImpl.Builder setFixedCost(double fixedCost) { this.fixedCost = fixedCost; return this; } public VehicleTypeImpl.Builder setCostPerDistance(double perDistance){ this.perDistance = perDistance; return this; } @@ -86,9 +89,13 @@ public class VehicleTypeImpl implements VehicleType { return true; } - public final String typeId; - public final int capacity; - public final VehicleTypeImpl.VehicleCostParams vehicleCostParams; + private final String typeId; + + private final int capacity; + + private final VehicleTypeImpl.VehicleCostParams vehicleCostParams; + + private double maxVelocity; public static VehicleTypeImpl newInstance(String typeId, int capacity, VehicleTypeImpl.VehicleCostParams para){ return new VehicleTypeImpl(typeId, capacity, para); @@ -97,6 +104,7 @@ public class VehicleTypeImpl implements VehicleType { private VehicleTypeImpl(VehicleTypeImpl.Builder builder){ typeId = builder.id; capacity = builder.capacity; + maxVelocity = builder.maxVelo; vehicleCostParams = new VehicleCostParams(builder.fixedCost, builder.perTime, builder.perDistance); } @@ -135,4 +143,9 @@ public class VehicleTypeImpl implements VehicleType { public String toString() { return "[typeId="+typeId+"][capacity="+capacity+"]" + vehicleCostParams; } + + @Override + public double getMaxVelocity() { + return maxVelocity; + } } \ No newline at end of file diff --git a/jsprit-core/src/main/java/util/VehicleRoutingTransportCostsMatrix.java b/jsprit-core/src/main/java/util/VehicleRoutingTransportCostsMatrix.java index 2832d66c..4410e18f 100644 --- a/jsprit-core/src/main/java/util/VehicleRoutingTransportCostsMatrix.java +++ b/jsprit-core/src/main/java/util/VehicleRoutingTransportCostsMatrix.java @@ -10,7 +10,16 @@ import basics.route.Driver; import basics.route.Vehicle; import basics.route.VehicleTypeImpl.VehicleCostParams; - +/** + * CostMatrix that allows pre-compiled time and distance-matrices to be considered as {@link VehicleRoutingRoutingCosts} + * in the {@link VehicleRoutingProblem}. + *

Note that you can also use it with distance matrix only (or time matrix). But ones + * you set a particular distance, this expects distance-entries for all relations. This counts also + * for a particular time. If the method getTransportCosts(...) is then invoked for a relation, where no distance can be found, an + * IllegalStateException will be thrown. Thus if you want to only use distances only, do not use addTransportTime(...). + * @author schroeder + * + */ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTransportCosts { static class RelationKey { @@ -74,7 +83,12 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo } - + /** + * Builder that builds the matrix. + * + * @author schroeder + * + */ public static class Builder { private static Logger log = Logger.getLogger(Builder.class); @@ -84,6 +98,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo private Map times = new HashMap(); + private boolean distancesSet = false; + + private boolean timesSet = false; + + /** + * Creates a new builder returning the matrix-builder. + *

If you want to consider symmetric matrices, set isSymmetric to true. + * @param isSymmetric + * @return + */ public static Builder newInstance(boolean isSymmetric){ return new Builder(isSymmetric); } @@ -92,8 +116,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo this.isSymmetric = isSymmetric; } + /** + * Adds a transport-distance for a particular relation. + * @param from + * @param to + * @param distance + * @return + */ public Builder addTransportDistance(String from, String to, double distance){ RelationKey key = RelationKey.newKey(from, to); + if(!distancesSet) distancesSet = true; if(distances.containsKey(key)){ log.warn("distance from " + from + " to " + to + " already exists. This overrides distance."); } @@ -101,8 +133,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo return this; } + /** + * Adds transport-time for a particular relation. + * @param from + * @param to + * @param time + * @return + */ public Builder addTransportTime(String from, String to, double time){ RelationKey key = RelationKey.newKey(from, to); + if(!timesSet) timesSet = true; if(times.containsKey(key)){ log.warn("transport-time from " + from + " to " + to + " already exists. This overrides distance."); } @@ -110,6 +150,10 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo return this; } + /** + * Builds the matrix. + * @return + */ public VehicleRoutingTransportCostsMatrix build(){ return new VehicleRoutingTransportCostsMatrix(this); } @@ -121,10 +165,16 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo private boolean isSymmetric; + private boolean timesSet; + + private boolean distancesSet; + private VehicleRoutingTransportCostsMatrix(Builder builder){ this.isSymmetric = builder.isSymmetric; distances.putAll(builder.distances); times.putAll(builder.times); + timesSet = builder.timesSet; + distancesSet = builder.distancesSet; } @@ -136,6 +186,7 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo private double getTime(String fromId, String toId) { if(fromId.equals(toId)) return 0.0; + if(!timesSet) return 0.0; RelationKey key = RelationKey.newKey(fromId, toId); if(!isSymmetric){ if(times.containsKey(key)) return times.get(key); @@ -153,6 +204,7 @@ public class VehicleRoutingTransportCostsMatrix implements VehicleRoutingTranspo private double getDistance(String fromId, String toId) { if(fromId.equals(toId)) return 0.0; + if(!distancesSet) return 0.0; RelationKey key = RelationKey.newKey(fromId, toId); if(!isSymmetric){ if(distances.containsKey(key)) return distances.get(key); diff --git a/jsprit-core/src/main/resources/algorithm_schema.xsd b/jsprit-core/src/main/resources/algorithm_schema.xsd index f3992790..66b1582b 100644 --- a/jsprit-core/src/main/resources/algorithm_schema.xsd +++ b/jsprit-core/src/main/resources/algorithm_schema.xsd @@ -166,14 +166,16 @@ - + + + - + 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/BuildCVRPAlgoFromScratchTest.java b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java new file mode 100644 index 00000000..b255891e --- /dev/null +++ b/jsprit-core/src/test/java/algorithms/BuildCVRPAlgoFromScratchTest.java @@ -0,0 +1,99 @@ +package algorithms; + +import static org.junit.Assert.*; + +import java.util.Collection; + +import org.junit.Before; +import org.junit.Test; + +import util.Solutions; +import algorithms.HardConstraints.HardActivityLevelConstraint; +import algorithms.acceptors.AcceptNewIfBetterThanWorst; +import algorithms.selectors.SelectBest; +import basics.VehicleRoutingAlgorithm; +import basics.VehicleRoutingProblem; +import basics.VehicleRoutingProblemSolution; +import basics.algo.IterationStartsListener; +import basics.algo.SearchStrategy; +import basics.algo.SearchStrategyManager; +import basics.io.VrpXMLReader; +import basics.route.TourActivity; + +public class BuildCVRPAlgoFromScratchTest { + + VehicleRoutingProblem vrp; + + VehicleRoutingAlgorithm vra; + + @Before + public void setup(){ + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + new VrpXMLReader(builder).read("src/test/resources/vrpnc1-jsprit.xml"); + vrp = builder.build(); + + final StateManagerImpl stateManager = new StateManagerImpl(); + HardActivityLevelConstraint hardActLevelConstraint = new HardActivityLevelConstraint() { + + @Override + public boolean fulfilled(InsertionContext iFacts, TourActivity act, double arrTime) { + return true; + } + }; + MarginalsCalculus marginalCalculus = new MarginalsCalculusTriangleInequality(vrp.getTransportCosts(), vrp.getActivityCosts(), hardActLevelConstraint); + CalculatesServiceInsertion serviceInsertion = new CalculatesServiceInsertion(vrp.getTransportCosts(), marginalCalculus, new HardConstraints.HardLoadConstraint(stateManager)); + + VehicleFleetManager fleetManager = new InfiniteVehicles(vrp.getVehicles()); + JobInsertionCalculator finalServiceInsertion = new CalculatesVehTypeDepServiceInsertion(fleetManager, serviceInsertion); + + BestInsertion bestInsertion = new BestInsertion(finalServiceInsertion); + + RuinRadial radial = new RuinRadial(vrp, 0.15, new JobDistanceAvgCosts(vrp.getTransportCosts())); + RuinRandom random = new RuinRandom(vrp, 0.25); + + SearchStrategy randomStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + RuinAndRecreateModule randomModule = new RuinAndRecreateModule("randomRuin_bestInsertion", bestInsertion, random); + randomStrategy.addModule(randomModule); + + SearchStrategy radialStrategy = new SearchStrategy(new SelectBest(), new AcceptNewIfBetterThanWorst(1)); + RuinAndRecreateModule radialModule = new RuinAndRecreateModule("radialRuin_bestInsertion", bestInsertion, radial); + radialStrategy.addModule(radialModule); + + SearchStrategyManager strategyManager = new SearchStrategyManager(); + strategyManager.addStrategy(radialStrategy, 0.5); + strategyManager.addStrategy(randomStrategy, 0.5); + + vra = new VehicleRoutingAlgorithm(vrp, strategyManager); + + //listeners + IterationStartsListener clearStateManager = new IterationStartsListener() { + + @Override + public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { + stateManager.clear(); + } + }; + vra.getAlgorithmListeners().addListener(clearStateManager); + vra.getSearchStrategyManager().addSearchStrategyModuleListener(new RemoveEmptyVehicles(fleetManager)); + + vra.getSearchStrategyManager().addSearchStrategyModuleListener(new UdateCostsAtRouteLevel(stateManager, vrp.getTransportCosts(), vrp.getActivityCosts())); + vra.getSearchStrategyManager().addSearchStrategyModuleListener(new UpdateLoadAtRouteLevel(stateManager)); + + VehicleRoutingProblemSolution iniSolution = new CreateInitialSolution(bestInsertion).createInitialSolution(vrp); +// System.out.println("ini: costs="+iniSolution.getCost()+";#routes="+iniSolution.getRoutes().size()); + vra.addInitialSolution(iniSolution); + + vra.setNuOfIterations(2000); +// vra.setPrematureBreak(200); + + } + + @Test + public void testVRA(){ + Collection solutions = vra.searchSolutions(); + System.out.println("costs="+Solutions.getBest(solutions).getCost()+";#routes="+Solutions.getBest(solutions).getRoutes().size()); + assertEquals(530.0, Solutions.getBest(solutions).getCost(),15.0); + assertEquals(5, Solutions.getBest(solutions).getRoutes().size()); + } + +} diff --git a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java index 7ad448f5..27f75beb 100644 --- a/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java +++ b/jsprit-core/src/test/java/algorithms/GendreauPostOptTest.java @@ -37,15 +37,16 @@ import basics.Job; import basics.Service; import basics.VehicleRoutingProblem; import basics.VehicleRoutingProblemSolution; +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 { @@ -60,6 +61,8 @@ public class GendreauPostOptTest { VehicleRoutingTransportCosts cost; + VehicleRoutingActivityCosts activityCosts; + VehicleRoutingProblem vrp; Service job1; @@ -68,15 +71,13 @@ public class GendreauPostOptTest { Service job3; - private RouteStates states; + private StateManagerImpl states; private List vehicles; - private TourStateUpdater updater; - private VehicleFleetManagerImpl fleetManager; - - private RouteAlgorithmImpl routeAlgorithm; + + private JobInsertionCalculator insertionCalc; @Before public void setUp(){ @@ -146,32 +147,18 @@ public class GendreauPostOptTest { // Collection vehicles = Arrays.asList(lightVehicle1,lightVehicle2, heavyVehicle); fleetManager = new VehicleFleetManagerImpl(vehicles); - states = new RouteStates(); + states = new StateManagerImpl(); - ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction(); + activityCosts = new ExampleActivityCostFunction(); + + CalculatesServiceInsertion standardServiceInsertion = new CalculatesServiceInsertion(cost, new MarginalsCalculusTriangleInequality(cost, activityCosts, new HardConstraints.HardTimeWindowConstraint(states)), new HardConstraints.HardLoadConstraint(states)); - CalculatesServiceInsertion standardServiceInsertion = new CalculatesServiceInsertion(cost, activityCosts); - standardServiceInsertion.setActivityStates(states); CalculatesServiceInsertionConsideringFixCost withFixCost = new CalculatesServiceInsertionConsideringFixCost(standardServiceInsertion, states); withFixCost.setWeightOfFixCost(1.2); - final JobInsertionCalculator vehicleTypeDepInsertionCost = new CalculatesVehTypeDepServiceInsertion(fleetManager, withFixCost); - updater = new TourStateUpdater(states, cost, activityCosts); + insertionCalc = new CalculatesVehTypeDepServiceInsertion(fleetManager, withFixCost); - - routeAlgorithm = RouteAlgorithmImpl.newInstance(vehicleTypeDepInsertionCost, 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); } @@ -181,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())); @@ -202,10 +190,16 @@ public class GendreauPostOptTest { assertEquals(110.0, sol.getCost(), 0.5); - RuinRadial radialRuin = RuinRadial.newInstance(vrp, 0.2, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), updater); - AbstractInsertionStrategy insertionStrategy = new BestInsertion(routeAlgorithm); - GendreauPostOpt postOpt = new GendreauPostOpt(vrp, radialRuin, insertionStrategy); + + RuinRadial radialRuin = new RuinRadial(vrp, 0.2, new JobDistanceAvgCosts(vrp.getTransportCosts())); + radialRuin.addListener(stateUpdater); + + InsertionStrategy insertionStrategy = new BestInsertion(insertionCalc); + insertionStrategy.addListener(stateUpdater); + insertionStrategy.addListener(new VehicleSwitched(fleetManager)); + Gendreau postOpt = new Gendreau(vrp, radialRuin, insertionStrategy); postOpt.setFleetManager(fleetManager); + VehicleRoutingProblemSolution newSolution = postOpt.runAndGetSolution(sol); assertEquals(2,RouteUtils.getNuOfActiveRoutes(newSolution.getRoutes())); @@ -220,32 +214,32 @@ 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); Collection routes = new ArrayList(); routes.add(route); -// routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); -// routes.add(new VehicleRoute(getEmptyTour(),getDriver(),getNoVehicle())); VehicleRoutingProblemSolution sol = new VehicleRoutingProblemSolution(routes, route.getCost()); assertEquals(110.0, sol.getCost(), 0.5); - RuinRadial radialRuin = RuinRadial.newInstance(vrp, 0.2, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), updater); - AbstractInsertionStrategy insertionStrategy = new BestInsertion(routeAlgorithm); - GendreauPostOpt postOpt = new GendreauPostOpt(vrp, radialRuin, insertionStrategy); + RuinRadial radialRuin = new RuinRadial(vrp, 0.2, new JobDistanceAvgCosts(vrp.getTransportCosts())); + InsertionStrategy insertionStrategy = new BestInsertion(insertionCalc); + insertionStrategy.addListener(stateUpdater); + insertionStrategy.addListener(new VehicleSwitched(fleetManager)); + Gendreau postOpt = new Gendreau(vrp, radialRuin, insertionStrategy); postOpt.setShareOfJobsToRuin(1.0); postOpt.setNuOfIterations(1); postOpt.setFleetManager(fleetManager); @@ -256,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/RefuseCollectionTest.java b/jsprit-core/src/test/java/algorithms/RefuseCollectionTest.java new file mode 100644 index 00000000..21c9574a --- /dev/null +++ b/jsprit-core/src/test/java/algorithms/RefuseCollectionTest.java @@ -0,0 +1,218 @@ +package algorithms; + +import static org.junit.Assert.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; + +import org.junit.Test; + +import util.Solutions; +import util.VehicleRoutingTransportCostsMatrix; +import util.VehicleRoutingTransportCostsMatrix.Builder; +import basics.Service; +import basics.VehicleRoutingAlgorithm; +import basics.VehicleRoutingProblem; +import basics.VehicleRoutingProblem.FleetSize; +import basics.VehicleRoutingProblemSolution; +import basics.costs.VehicleRoutingTransportCosts; +import basics.route.Driver; +import basics.route.Vehicle; +import basics.route.VehicleImpl; +import basics.route.VehicleTypeImpl; + + +public class RefuseCollectionTest { + + static class RelationKey { + + static RelationKey newKey(String from, String to){ + int fromInt = Integer.parseInt(from); + int toInt = Integer.parseInt(to); + if(fromInt < toInt){ + return new RelationKey(from, to); + } + else { + return new RelationKey(to, from); + } + } + + final String from; + final String to; + + public RelationKey(String from, String to) { + super(); + this.from = from; + this.to = to; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((from == null) ? 0 : from.hashCode()); + result = prime * result + ((to == null) ? 0 : to.hashCode()); + return result; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RelationKey other = (RelationKey) obj; + if (from == null) { + if (other.from != null) + return false; + } else if (!from.equals(other.from)) + return false; + if (to == null) { + if (other.to != null) + return false; + } else if (!to.equals(other.to)) + return false; + return true; + } + } + + static class RoutingCosts implements VehicleRoutingTransportCosts { + + private Map distances; + + public RoutingCosts(Map distances) { + super(); + this.distances = distances; + } + + @Override + public double getTransportTime(String fromId, String toId, double departureTime, Driver driver, Vehicle vehicle) { + return getTransportCost(fromId, toId, departureTime, driver, vehicle); + } + + @Override + public double getBackwardTransportTime(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) { + if(fromId.equals(toId)) return 0.0; + RelationKey key = RelationKey.newKey(fromId, toId); + return distances.get(key); + } + + @Override + public double getBackwardTransportCost(String fromId, String toId,double arrivalTime, Driver driver, Vehicle vehicle) { + return getTransportCost(fromId, toId, arrivalTime, driver, vehicle); + } + + } + + + @Test + public void testAlgo(){ + + + /* + * create vehicle-type and vehicle + */ + VehicleTypeImpl.Builder typeBuilder = VehicleTypeImpl.Builder.newInstance("vehicle-type", 23); + typeBuilder.setCostPerDistance(1.0); + VehicleTypeImpl bigType = typeBuilder.build(); + + VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance("vehicle"); + vehicleBuilder.setLocationId("1"); + vehicleBuilder.setType(bigType); + Vehicle bigVehicle = vehicleBuilder.build(); + + /* + * start building the problem + */ + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + vrpBuilder.setFleetSize(FleetSize.INFINITE); + vrpBuilder.addVehicle(bigVehicle); + + /* + * create cost-matrix + */ + VehicleRoutingTransportCostsMatrix.Builder matrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true); + /* + * read demand quantities + */ + try { + readDemandQuantities(vrpBuilder); + readDistances(matrixBuilder); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + vrpBuilder.setRoutingCost(matrixBuilder.build()); + VehicleRoutingProblem vrp = vrpBuilder.build(); + VehicleRoutingAlgorithm vra = new GreedySchrimpfFactory().createAlgorithm(vrp); + vra.setPrematureBreak(100); + Collection solutions = vra.searchSolutions(); + + assertEquals(397.0,Solutions.getBest(solutions).getCost(),0.01); + assertEquals(2,Solutions.getBest(solutions).getRoutes().size()); + } + + + private static void readDemandQuantities(VehicleRoutingProblem.Builder vrpBuilder) throws FileNotFoundException, IOException { + BufferedReader reader = new BufferedReader(new FileReader(new File("src/test/resources/refuseCollectionExample_Quantities"))); + String line = null; + boolean firstLine = true; + while((line = reader.readLine()) != null){ + if(firstLine) { + firstLine = false; + continue; + } + String[] lineTokens = line.split(","); + /* + * build service + */ + Service service = Service.Builder.newInstance(lineTokens[0], Integer.parseInt(lineTokens[1])).setLocationId(lineTokens[0]).build(); + /* + * and add it to problem + */ + vrpBuilder.addService(service); + } + reader.close(); + } + + + private static void readDistances(Builder matrixBuilder) throws IOException { + BufferedReader reader = new BufferedReader(new FileReader(new File("src/test/resources/refuseCollectionExample_Distances"))); + String line = null; + boolean firstLine = true; + while((line = reader.readLine()) != null){ + if(firstLine) { + firstLine = false; + continue; + } + String[] lineTokens = line.split(","); + matrixBuilder.addTransportDistance(lineTokens[0],lineTokens[1], Integer.parseInt(lineTokens[2])); + } + reader.close(); + + } + + +} diff --git a/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java b/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java index db93a116..949cdfa3 100644 --- a/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java +++ b/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java @@ -169,6 +169,24 @@ public class TestAlgorithmReader { // TODO Auto-generated method stub return null; } + + @Override + public void addListener(RuinListener ruinListener) { + // TODO Auto-generated method stub + + } + + @Override + public void removeListener(RuinListener ruinListener) { + // TODO Auto-generated method stub + + } + + @Override + public Collection getListeners() { + // TODO Auto-generated method stub + return null; + } }; @@ -233,21 +251,21 @@ public class TestAlgorithmReader { assertEquals(3, nOfModules); } - @Test - public void whenCreatingAlgorithm_regretInsertionIsReadCorrectly(){ - VehicleRoutingAlgorithm algo = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "src/test/resources/configWithRegretInsertion.xml"); - int nOfModules = 0; - for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){ - for(SearchStrategyModule module : strat.getSearchStrategyModules()){ - if(module.getName().contains("ruin_and_recreate")){ - nOfModules++; - } - } - - } - assertEquals(3, nOfModules); - - } - +// @Test +// public void whenCreatingAlgorithm_regretInsertionIsReadCorrectly(){ +// VehicleRoutingAlgorithm algo = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "src/test/resources/configWithRegretInsertion.xml"); +// int nOfModules = 0; +// for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){ +// for(SearchStrategyModule module : strat.getSearchStrategyModules()){ +// if(module.getName().contains("ruin_and_recreate")){ +// nOfModules++; +// } +// } +// +// } +// assertEquals(3, nOfModules); +// +// } +// } 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..459ae877 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 StateManagerImpl states; private NoDriver driver; + private UpdateStates stateUpdater; + @Before public void setup(){ Logger.getRootLogger().setLevel(Level.DEBUG); @@ -151,17 +152,13 @@ public class TestCalculatesServiceInsertion { jobs.add(second); jobs.add(third); - states = new RouteStates(); - states.initialiseStateOfJobs(jobs); + states = new StateManagerImpl(); ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction(); - serviceInsertion = new CalculatesServiceInsertion(costs, activityCosts); - serviceInsertion.setActivityStates(states); - - tourStateUpdater = new TourStateUpdater(states, costs, activityCosts); - + serviceInsertion = new CalculatesServiceInsertion(costs, new MarginalsCalculusTriangleInequality(costs, activityCosts, new HardConstraints.HardTimeWindowConstraint(states)), new HardConstraints.HardLoadConstraint(states)); + stateUpdater = new UpdateStates(states, costs, activityCosts); } @@ -176,7 +173,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 +183,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 +196,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 +211,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 +226,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 +240,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..9844917b 100644 --- a/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertionOnRouteLevel.java +++ b/jsprit-core/src/test/java/algorithms/TestCalculatesServiceInsertionOnRouteLevel.java @@ -39,6 +39,7 @@ import basics.Service; 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.TourActivity; @@ -64,12 +65,12 @@ public class TestCalculatesServiceInsertionOnRouteLevel { private Service third; - private RouteStates states; - - private TourStateUpdater tourStateUpdater; + private StateManagerImpl states; private NoDriver driver; + private UpdateStates updateStates; + @Before public void setup(){ Logger.getRootLogger().setLevel(Level.DEBUG); @@ -142,15 +143,14 @@ public class TestCalculatesServiceInsertionOnRouteLevel { jobs.add(second); jobs.add(third); - states = new RouteStates(); - states.initialiseStateOfJobs(jobs); + states = new StateManagerImpl(); ExampleActivityCostFunction activityCosts = new ExampleActivityCostFunction(); serviceInsertion = new CalculatesServiceInsertionOnRouteLevel(costs,activityCosts); serviceInsertion.setNuOfActsForwardLooking(4); - serviceInsertion.setActivityStates(states); + serviceInsertion.setStates(states); - tourStateUpdater = new TourStateUpdater(states, costs, activityCosts); + updateStates = new UpdateStates(states, costs, activityCosts); @@ -167,48 +167,21 @@ public class TestCalculatesServiceInsertionOnRouteLevel { TourActivities tour = new TourActivities(); VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); - tourStateUpdater.updateRoute(route); + updateStates.update(route); InsertionData iData = serviceInsertion.calculate(route, first, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(20.0, iData.getInsertionCost(), 0.2); assertEquals(0, iData.getDeliveryInsertionIndex()); } -// @Test -// public void whenInsertingTheSecondJobInAnNonEmptyTourWithVehicle_itCalculatesMarginalCostChanges(){ -// TourActivities tour = new TourActivities(); -// tour.addActivity(states.getActivity(first, true)); -// -// VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); -// tourStateUpdater.updateRoute(route); -// -// InsertionData iData = serviceInsertion.calculate(route, second, vehicle, null, Double.MAX_VALUE); -// assertEquals(20.0, iData.getInsertionCost(), 0.2); -// assertEquals(1, iData.getDeliveryInsertionIndex()); -// } - -// @Test -// public void whenInsertingTheSecotndJobInAnNonEmptyTourWithNewVehicle_itCalculatesMarginalCostChanges(){ -// TourActivities tour = new TourActivities(); -// tour.addActivity(states.getActivity(first, true)); -// -// VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); -// tourStateUpdater.updateRoute(route); -// -// InsertionData iData = serviceInsertion.calculate(route, second, newVehicle, null, Double.MAX_VALUE); -// assertEquals(40.0, iData.getInsertionCost(), 0.2); -// assertEquals(1, iData.getDeliveryInsertionIndex()); -// } - @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); + updateStates.update(route); InsertionData iData = serviceInsertion.calculate(route, third, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(0.0, iData.getInsertionCost(), 0.2); @@ -218,12 +191,11 @@ public class TestCalculatesServiceInsertionOnRouteLevel { @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); + updateStates.update(route); InsertionData iData = serviceInsertion.calculate(route, third, newVehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(40.0, iData.getInsertionCost(), 0.2); @@ -233,11 +205,11 @@ public class TestCalculatesServiceInsertionOnRouteLevel { @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); + updateStates.update(route); InsertionData iData = serviceInsertion.calculate(route, second, vehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(0.0, iData.getInsertionCost(), 0.2); @@ -247,30 +219,15 @@ public class TestCalculatesServiceInsertionOnRouteLevel { @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); - tourStateUpdater.updateRoute(route); + updateStates.update(route); InsertionData iData = serviceInsertion.calculate(route, second, newVehicle, vehicle.getEarliestDeparture(), null, Double.MAX_VALUE); assertEquals(40.0, iData.getInsertionCost(), 0.2); assertEquals(2, iData.getDeliveryInsertionIndex()); } -// @Test -// public void whenInsertingFirstJobWithANewVehicle_itCalculatesLocalMarginalCostChanges(){ -// TourActivities tour = new TourActivities(); -// tour.addActivity(states.getActivity(third,true)); -// tour.addActivity(states.getActivity(second,true)); -// -// VehicleRoute route = VehicleRoute.newInstance(tour,driver,vehicle); -// tourStateUpdater.updateRoute(route); -// -// InsertionData iData = serviceInsertion.calculate(route, second, newVehicle, null, Double.MAX_VALUE); -// assertEquals(40.0, iData.getInsertionCost(), 0.2); -// assertEquals(2, iData.getDeliveryInsertionIndex()); -// } - - } 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..e3553e2a --- /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); + StateManagerImpl states = new StateManagerImpl(); + 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); + StateManagerImpl states = new StateManagerImpl(); + 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); + StateManagerImpl states = new StateManagerImpl(); + 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); + StateManagerImpl states = new StateManagerImpl(); + 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().getArrTime(),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..6ced378f 100644 --- a/jsprit-core/src/test/java/algorithms/TestTourStateUpdaterWithService.java +++ b/jsprit-core/src/test/java/algorithms/TestTourStateUpdaterWithService.java @@ -32,6 +32,7 @@ import basics.Service; 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; @@ -51,9 +52,9 @@ public class TestTourStateUpdaterWithService { TourActivities anotherTour; - TourStateUpdater tdTourStatusProcessor; + UpdateStates updateStates; - RouteStates states; + StateManagerImpl states; private VehicleRoute vehicleRoute; @@ -100,33 +101,32 @@ public class TestTourStateUpdaterWithService { services.add(firstService); services.add(secondService); - states = new RouteStates(); - states.initialiseStateOfJobs(services); + states = new StateManagerImpl(); 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(); - tour.addActivity(states.getActivity(firstService,true)); - tour.addActivity(states.getActivity(secondService,true)); + tour.addActivity(ServiceActivity.newInstance(firstService)); + tour.addActivity(ServiceActivity.newInstance(secondService)); - tdTourStatusProcessor = new TourStateUpdater(states, cost, new ExampleActivityCostFunction()); + updateStates = new UpdateStates(states, cost, new ExampleActivityCostFunction()); vehicleRoute = VehicleRoute.newInstance(tour,DriverImpl.noDriver(),vehicle); } @Test public void testCalculatedCost() { - tdTourStatusProcessor.updateRoute(vehicleRoute); - assertEquals(40.0, states.getRouteState(vehicleRoute).getCosts(), 0.05); - assertEquals(10, states.getRouteState(vehicleRoute).getLoad()); + updateStates.update(vehicleRoute); + assertEquals(40.0, states.getRouteState(vehicleRoute,StateTypes.COSTS).toDouble(), 0.05); + assertEquals(10, states.getRouteState(vehicleRoute, StateTypes.LOAD).toDouble(), 0.05); } @Test public void testStatesOfAct0(){ - tdTourStatusProcessor.updateRoute(vehicleRoute); + updateStates.update(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,112 +136,31 @@ public class TestTourStateUpdaterWithService { @Test public void testStatesOfAct1(){ - tdTourStatusProcessor.updateRoute(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); - assertEquals(20.0, states.getState(tour.getActivities().get(0)).getLatestOperationStart(),0.05); + updateStates.update(vehicleRoute); + assertEquals(10.0, states.getActivityState(tour.getActivities().get(0), StateTypes.COSTS).toDouble(),0.05); + assertEquals(5.0, states.getActivityState(tour.getActivities().get(0), StateTypes.LOAD).toDouble(),0.05); +// assertEquals(10.0, states.getActivityState(tour.getActivities().get(0), StateTypes.EARLIEST_OPERATION_START_TIME).toDouble(),0.05); + assertEquals(20.0, states.getActivityState(tour.getActivities().get(0), StateTypes.LATEST_OPERATION_START_TIME).toDouble(),0.05); } @Test public void testStatesOfAct2(){ - tdTourStatusProcessor.updateRoute(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); - assertEquals(40.0, states.getState(tour.getActivities().get(1)).getLatestOperationStart(),0.05); + updateStates.update(vehicleRoute); + + assertEquals(30.0, states.getActivityState(tour.getActivities().get(1), StateTypes.COSTS).toDouble(),0.05); + assertEquals(10.0, states.getActivityState(tour.getActivities().get(1), StateTypes.LOAD).toDouble(),0.05); +// assertEquals(10.0, states.getActivityState(tour.getActivities().get(0), StateTypes.EARLIEST_OPERATION_START_TIME).toDouble(),0.05); + assertEquals(40.0, states.getActivityState(tour.getActivities().get(1), StateTypes.LATEST_OPERATION_START_TIME).toDouble(),0.05); } @Test public void testStatesOfAct3(){ - tdTourStatusProcessor.updateRoute(vehicleRoute); - assertEquals(40.0, states.getRouteState(vehicleRoute).getCosts(), 0.05); - assertEquals(40.0, vehicleRoute.getEnd().getEndTime(),0.05); + updateStates.update(vehicleRoute); + + assertEquals(40.0, states.getRouteState(vehicleRoute, StateTypes.COSTS).toDouble(), 0.05); + assertEquals(40.0, vehicleRoute.getEnd().getArrTime(),0.05); assertEquals(50.0, vehicleRoute.getEnd().getTheoreticalLatestOperationStartTime(),0.05); } -// public void testEarliestArrStart() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(0.0, tour.getActivities().get(0) -// .getEarliestOperationStartTime()); -// } -// -// public void testLatestArrStart() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(0.0, tour.getActivities().get(0) -// .getLatestOperationStartTime()); -// } -// -// public void testEarliestArrAtFirstPickup() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(10.0, tour.getActivities().get(1) -// .getEarliestOperationStartTime()); -// } -// -// public void testEarliestArrAtFirstPickupWithTDCost() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(10.0, tour.getActivities().get(1) -// .getEarliestOperationStartTime()); -// } -// -// public void testLatestArrAtFirstPickup() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(10.0, tour.getActivities().get(1) -// .getLatestOperationStartTime()); -// } -// -// public void testLatestArrAtFirstPickupWithTDCost() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(12.0, tour.getActivities().get(1) -// .getLatestOperationStartTime()); -// } -// -// public void testEarliestArrAtSecondPickup() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(30.0, tour.getActivities().get(2) -// .getEarliestOperationStartTime()); -// } -// -// public void testEarliestArrAtSecondPickupWithTDCosts() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(30.0, tour.getActivities().get(2) -// .getEarliestOperationStartTime()); -// } -// -// public void testLatestArrAtSecondPickup() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(30.0, tour.getActivities().get(2) -// .getLatestOperationStartTime()); -// } -// -// public void testLatestArrAtSecondPickupWithTDCosts() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(30.0, tour.getActivities().get(2) -// .getLatestOperationStartTime()); -// } -// -// public void testEarliestArrAtEnd() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(40.0, tour.getActivities().get(5) -// .getEarliestOperationStartTime()); -// } -// -// public void testEarliestArrAtEndWithTDCosts() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(35.0, tour.getActivities().get(5) -// .getEarliestOperationStartTime()); -// } -// -// public void testLatestArrAtEnd() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(Double.MAX_VALUE, tour.getActivities().get(5) -// .getLatestOperationStartTime()); -// } -// -// public void testLatestArrAtEndWithTDCosts() { -// tdTourStatusProcessor.calculate(tour, vehicle, driver); -// assertEquals(Double.MAX_VALUE, tour.getActivities().get(5) -// .getLatestOperationStartTime()); -// } } diff --git a/jsprit-core/src/test/resources/refuseCollectionExample_Distances b/jsprit-core/src/test/resources/refuseCollectionExample_Distances new file mode 100644 index 00000000..ad147506 --- /dev/null +++ b/jsprit-core/src/test/resources/refuseCollectionExample_Distances @@ -0,0 +1,46 @@ +from,to,distance +1,2,25 +1,3,43 +1,4,57 +1,5,43 +1,6,61 +1,7,29 +1,8,41 +1,9,48 +1,10,71 +2,3,29 +2,4,34 +2,5,43 +2,6,68 +2,7,49 +2,8,66 +2,9,48 +2,10,91 +3,4,52 +3,5,72 +3,6,96 +3,7,72 +3,8,81 +3,9,89 +3,10,114 +4,5,45 +4,6,71 +4,7,71 +4,8,95 +4,9,99 +4,10,108 +5,6,27 +5,7,36 +5,8,65 +5,9,65 +5,10,65 +6,7,40 +6,8,66 +6,9,62 +6,10,46 +7,8,31 +7,9,31 +7,10,43 +8,9,11 +8,10,46 +9,10,36 \ No newline at end of file diff --git a/jsprit-core/src/test/resources/refuseCollectionExample_Quantities b/jsprit-core/src/test/resources/refuseCollectionExample_Quantities new file mode 100644 index 00000000..4645bac0 --- /dev/null +++ b/jsprit-core/src/test/resources/refuseCollectionExample_Quantities @@ -0,0 +1,10 @@ +node,quantity +2,4 +3,6 +4,5 +5,4 +6,7 +7,3 +8,5 +9,4 +10,4 \ No newline at end of file diff --git a/jsprit-core/src/test/resources/vrpnc1-jsprit.xml b/jsprit-core/src/test/resources/vrpnc1-jsprit.xml new file mode 100644 index 00000000..5d3ff044 --- /dev/null +++ b/jsprit-core/src/test/resources/vrpnc1-jsprit.xml @@ -0,0 +1,635 @@ + + + + INFINITE + HOMOGENEOUS + + + + christophidesVehicle + christophidesType + + [x=30.0][y=40.0] + + + + 0.0 + 999999.0 + + + + + + christophidesType + 160 + + 0.0 + 1.0 + + + + + + + [x=62.0][y=63.0] + + 17 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=63.0][y=69.0] + + 6 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=46.0][y=10.0] + + 23 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=61.0][y=33.0] + + 26 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=59.0][y=15.0] + + 14 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=32.0][y=22.0] + + 9 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=45.0][y=35.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=5.0][y=64.0] + + 11 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=21.0][y=10.0] + + 13 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=10.0][y=17.0] + + 27 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=5.0][y=6.0] + + 7 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=42.0][y=57.0] + + 8 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=16.0][y=57.0] + + 16 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=8.0][y=52.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=7.0][y=38.0] + + 28 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=27.0][y=68.0] + + 7 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=30.0][y=48.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=43.0][y=67.0] + + 14 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=58.0][y=48.0] + + 6 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=52.0][y=64.0] + + 16 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=49.0][y=49.0] + + 30 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=37.0][y=52.0] + + 7 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=17.0][y=63.0] + + 19 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=58.0][y=27.0] + + 19 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=21.0][y=47.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=40.0][y=30.0] + + 21 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=38.0][y=46.0] + + 12 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=20.0][y=26.0] + + 9 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=37.0][y=69.0] + + 11 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=52.0][y=33.0] + + 11 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=31.0][y=62.0] + + 23 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=13.0][y=13.0] + + 9 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=27.0][y=23.0] + + 3 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=17.0][y=33.0] + + 41 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=36.0][y=16.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=52.0][y=41.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=5.0][y=25.0] + + 23 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=12.0][y=42.0] + + 21 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=42.0][y=41.0] + + 19 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=31.0][y=32.0] + + 29 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=62.0][y=42.0] + + 8 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=57.0][y=58.0] + + 28 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=48.0][y=28.0] + + 18 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=25.0][y=55.0] + + 17 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=39.0][y=10.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=30.0][y=15.0] + + 16 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=25.0][y=32.0] + + 25 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=32.0][y=39.0] + + 5 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=51.0][y=21.0] + + 5 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=56.0][y=37.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + diff --git a/jsprit-examples/input/algorithmConfig.xml b/jsprit-examples/input/algorithmConfig.xml index dd27c419..410727cd 100755 --- a/jsprit-examples/input/algorithmConfig.xml +++ b/jsprit-examples/input/algorithmConfig.xml @@ -22,10 +22,12 @@ - 10000 + 2000 - + + route + @@ -33,10 +35,8 @@ - - 0.1 - 100 - + + @@ -51,7 +51,7 @@ - + @@ -67,7 +67,7 @@ - + diff --git a/jsprit-examples/input/algorithmConfig_solomon.xml b/jsprit-examples/input/algorithmConfig_solomon.xml index ca1ac2a1..12b98942 100755 --- a/jsprit-examples/input/algorithmConfig_solomon.xml +++ b/jsprit-examples/input/algorithmConfig_solomon.xml @@ -6,7 +6,9 @@ 2000 - + + + diff --git a/jsprit-examples/input/vrpnc1-jsprit.xml b/jsprit-examples/input/vrpnc1-jsprit.xml new file mode 100644 index 00000000..5d3ff044 --- /dev/null +++ b/jsprit-examples/input/vrpnc1-jsprit.xml @@ -0,0 +1,635 @@ + + + + INFINITE + HOMOGENEOUS + + + + christophidesVehicle + christophidesType + + [x=30.0][y=40.0] + + + + 0.0 + 999999.0 + + + + + + christophidesType + 160 + + 0.0 + 1.0 + + + + + + + [x=62.0][y=63.0] + + 17 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=63.0][y=69.0] + + 6 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=46.0][y=10.0] + + 23 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=61.0][y=33.0] + + 26 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=59.0][y=15.0] + + 14 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=32.0][y=22.0] + + 9 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=45.0][y=35.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=5.0][y=64.0] + + 11 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=21.0][y=10.0] + + 13 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=10.0][y=17.0] + + 27 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=5.0][y=6.0] + + 7 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=42.0][y=57.0] + + 8 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=16.0][y=57.0] + + 16 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=8.0][y=52.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=7.0][y=38.0] + + 28 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=27.0][y=68.0] + + 7 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=30.0][y=48.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=43.0][y=67.0] + + 14 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=58.0][y=48.0] + + 6 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=52.0][y=64.0] + + 16 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=49.0][y=49.0] + + 30 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=37.0][y=52.0] + + 7 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=17.0][y=63.0] + + 19 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=58.0][y=27.0] + + 19 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=21.0][y=47.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=40.0][y=30.0] + + 21 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=38.0][y=46.0] + + 12 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=20.0][y=26.0] + + 9 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=37.0][y=69.0] + + 11 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=52.0][y=33.0] + + 11 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=31.0][y=62.0] + + 23 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=13.0][y=13.0] + + 9 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=27.0][y=23.0] + + 3 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=17.0][y=33.0] + + 41 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=36.0][y=16.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=52.0][y=41.0] + + 15 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=5.0][y=25.0] + + 23 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=12.0][y=42.0] + + 21 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=42.0][y=41.0] + + 19 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=31.0][y=32.0] + + 29 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=62.0][y=42.0] + + 8 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=57.0][y=58.0] + + 28 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=48.0][y=28.0] + + 18 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=25.0][y=55.0] + + 17 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=39.0][y=10.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=30.0][y=15.0] + + 16 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=25.0][y=32.0] + + 25 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=32.0][y=39.0] + + 5 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=51.0][y=21.0] + + 5 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + [x=56.0][y=37.0] + + 10 + 0.0 + + + 0.0 + 1.7976931348623157E308 + + + + + diff --git a/jsprit-examples/input/vrpnc1.txt b/jsprit-examples/input/vrpnc1.txt new file mode 100644 index 00000000..7296a49f --- /dev/null +++ b/jsprit-examples/input/vrpnc1.txt @@ -0,0 +1,52 @@ + 50 160 999999 0 + 30 40 + 37 52 7 + 49 49 30 + 52 64 16 + 20 26 9 + 40 30 21 + 21 47 15 + 17 63 19 + 31 62 23 + 52 33 11 + 51 21 5 + 42 41 19 + 31 32 29 + 5 25 23 + 12 42 21 + 36 16 10 + 52 41 15 + 27 23 3 + 17 33 41 + 13 13 9 + 57 58 28 + 62 42 8 + 42 57 8 + 16 57 16 + 8 52 10 + 7 38 28 + 27 68 7 + 30 48 15 + 43 67 14 + 58 48 6 + 58 27 19 + 37 69 11 + 38 46 12 + 46 10 23 + 61 33 26 + 62 63 17 + 63 69 6 + 32 22 9 + 45 35 15 + 59 15 14 + 5 6 7 + 10 17 27 + 21 10 13 + 5 64 11 + 30 15 16 + 39 10 10 + 32 39 5 + 25 32 25 + 25 55 17 + 48 28 18 + 56 37 10 diff --git a/jsprit-examples/src/main/java/examples/CVRPExample.java b/jsprit-examples/src/main/java/examples/CVRPExample.java new file mode 100644 index 00000000..3196a732 --- /dev/null +++ b/jsprit-examples/src/main/java/examples/CVRPExample.java @@ -0,0 +1,16 @@ +package examples; + +import readers.ChristofidesReader; +import basics.VehicleRoutingProblem; +import basics.io.VrpXMLWriter; + +public class CVRPExample { + + public static void main(String[] args) { + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + new ChristofidesReader(builder).read("input/vrpnc1.txt"); + VehicleRoutingProblem vrp = builder.build(); + new VrpXMLWriter(vrp).write("input/vrpnc1-jsprit.xml"); + } + +} diff --git a/jsprit-examples/src/main/java/examples/CompareAlgorithmExample.java b/jsprit-examples/src/main/java/examples/CompareAlgorithmExample.java index 65ce758b..cfa4273d 100644 --- a/jsprit-examples/src/main/java/examples/CompareAlgorithmExample.java +++ b/jsprit-examples/src/main/java/examples/CompareAlgorithmExample.java @@ -20,6 +20,8 @@ ******************************************************************************/ package examples; +import java.io.File; + import readers.SolomonReader; import algorithms.GreedySchrimpfFactory; import algorithms.SchrimpfFactory; @@ -35,7 +37,16 @@ public class CompareAlgorithmExample { * @param args */ public static void main(String[] args) { - + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } /* * Build the problem. * diff --git a/jsprit-examples/src/main/java/examples/CostMatrixExample.java b/jsprit-examples/src/main/java/examples/CostMatrixExample.java index 85959b98..0ab81b4e 100644 --- a/jsprit-examples/src/main/java/examples/CostMatrixExample.java +++ b/jsprit-examples/src/main/java/examples/CostMatrixExample.java @@ -1,5 +1,6 @@ package examples; +import java.io.File; import java.util.Collection; import util.Solutions; @@ -32,7 +33,16 @@ public class CostMatrixExample { * @param args */ public static void main(String[] args) { - + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } VehicleType type = VehicleTypeImpl.Builder.newInstance("type", 2).setCostPerDistance(1).setCostPerTime(2).build(); Vehicle vehicle = VehicleImpl.Builder.newInstance("vehicle").setLocationId("0").setType(type).build(); diff --git a/jsprit-examples/src/main/java/examples/MultipleDepotExample.java b/jsprit-examples/src/main/java/examples/MultipleDepotExample.java index c05183bb..fc963747 100644 --- a/jsprit-examples/src/main/java/examples/MultipleDepotExample.java +++ b/jsprit-examples/src/main/java/examples/MultipleDepotExample.java @@ -1,5 +1,6 @@ package examples; +import java.io.File; import java.util.Arrays; import java.util.Collection; @@ -18,7 +19,6 @@ import basics.algo.VehicleRoutingAlgorithmListeners.Priority; import basics.io.VrpXMLReader; import basics.route.Vehicle; import basics.route.VehicleImpl; -import basics.route.VehicleType; import basics.route.VehicleTypeImpl; public class MultipleDepotExample { @@ -27,7 +27,16 @@ public class MultipleDepotExample { * @param args */ public static void main(String[] args) { - + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); /* * Read cordeau-instance p01, BUT only its services without any vehicles diff --git a/jsprit-examples/src/main/java/examples/MultipleDepotExampleWithPenaltyVehicles.java b/jsprit-examples/src/main/java/examples/MultipleDepotExampleWithPenaltyVehicles.java index dc43639e..51992690 100644 --- a/jsprit-examples/src/main/java/examples/MultipleDepotExampleWithPenaltyVehicles.java +++ b/jsprit-examples/src/main/java/examples/MultipleDepotExampleWithPenaltyVehicles.java @@ -1,5 +1,6 @@ package examples; +import java.io.File; import java.util.Arrays; import java.util.Collection; @@ -29,6 +30,16 @@ public class MultipleDepotExampleWithPenaltyVehicles { * @param args */ public static void main(String[] args) { + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); /* diff --git a/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java b/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java index 1e9df400..58a3133d 100644 --- a/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java +++ b/jsprit-examples/src/main/java/examples/RefuseCollectionExample.java @@ -155,6 +155,16 @@ public class RefuseCollectionExample { * @throws IOException */ public static void main(String[] args) throws IOException { + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } /* * create vehicle-type and vehicle diff --git a/jsprit-examples/src/main/java/examples/SimpleExample.java b/jsprit-examples/src/main/java/examples/SimpleExample.java index e7225411..0bb27c52 100644 --- a/jsprit-examples/src/main/java/examples/SimpleExample.java +++ b/jsprit-examples/src/main/java/examples/SimpleExample.java @@ -20,6 +20,7 @@ ******************************************************************************/ package examples; +import java.io.File; import java.util.Collection; import util.Coordinate; @@ -42,6 +43,16 @@ import basics.route.VehicleTypeImpl; public class SimpleExample { public static void main(String[] args) { + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } /* * get a vehicle type-builder and build a type with the typeId "vehicleType" and a capacity of 2 diff --git a/jsprit-examples/src/main/java/examples/SolomonExample.java b/jsprit-examples/src/main/java/examples/SolomonExample.java index 6ba7099b..d4cbe843 100644 --- a/jsprit-examples/src/main/java/examples/SolomonExample.java +++ b/jsprit-examples/src/main/java/examples/SolomonExample.java @@ -20,12 +20,12 @@ ******************************************************************************/ package examples; +import java.io.File; import java.util.Collection; import readers.SolomonReader; -import algorithms.SchrimpfFactory; +import algorithms.VehicleRoutingAlgorithms; import algorithms.selectors.SelectBest; -import analysis.AlgorithmSearchProgressChartListener; import analysis.SolutionPlotter; import analysis.SolutionPrinter; import analysis.SolutionPrinter.Print; @@ -36,7 +36,16 @@ import basics.VehicleRoutingProblemSolution; public class SolomonExample { public static void main(String[] args) { - + /* + * some preparation - create output folder + */ + File dir = new File("output"); + // if the directory does not exist, create it + if (!dir.exists()){ + System.out.println("creating directory ./output"); + boolean result = dir.mkdir(); + if(result) System.out.println("./output created"); + } /* * Build the problem. @@ -62,8 +71,10 @@ public class SolomonExample { * * The algorithm can be defined and configured in an xml-file. */ - VehicleRoutingAlgorithm vra = new SchrimpfFactory().createAlgorithm(vrp); - vra.getAlgorithmListeners().addListener(new AlgorithmSearchProgressChartListener("output/sol_progress.png")); +// VehicleRoutingAlgorithm vra = new SchrimpfFactory().createAlgorithm(vrp); + VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, "input/algorithmConfig_solomon.xml"); + vra.setPrematureBreak(100); +// vra.getAlgorithmListeners().addListener(new AlgorithmSearchProgressChartListener("output/sol_progress.png")); /* * Solve the problem. * diff --git a/pom.xml b/pom.xml index 4be68ef5..7aae13de 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ Stefan Schroeder - 4sschroeder@gmail.com + jsprit.vehicle.routing@gmail.com