1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

merged master into multiple tw branch

This commit is contained in:
oblonski 2015-12-11 17:40:41 +01:00
parent 0b3b07a7de
commit 02c3c96e9c
523 changed files with 77426 additions and 74576 deletions

13
.editorconfig Normal file
View file

@ -0,0 +1,13 @@
root = true
[*]
indent_style = space
indent_size = 4
insert_final_newline = true
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
max_line_length = 120
[.travis.yml]
indent_size = 2

View file

@ -1,6 +1,18 @@
Change-log Change-log
========== ==========
**v1.6.1** @ 2015-08-10
- feature [#165](https://github.com/jsprit/jsprit/issues/156)
- feature [#169](https://github.com/jsprit/jsprit/issues/159)
- bugfix [#154](https://github.com/jsprit/jsprit/issues/154)
- bugfix [#155](https://github.com/jsprit/jsprit/issues/155)
- bugfix [#158](https://github.com/jsprit/jsprit/issues/158)
- bugfix [#164](https://github.com/jsprit/jsprit/issues/164)
- bugfix [#165](https://github.com/jsprit/jsprit/issues/165)
- [detailed changelog ](https://rawgit.com/jsprit/misc-rep/master/changelog_1.6_to_1.6.1.html)
**v1.6** @ 2015-03-12 **v1.6** @ 2015-03-12
<b>! Break change !</b> <b>! Break change !</b>

View file

@ -40,7 +40,7 @@ This software is released under [LGPL](http://opensource.org/licenses/LGPL-3.0).
##Contact ##Contact
####Mailing List: ####Mailing List:
In the [mailing list](https://groups.google.com/group/jsprit-mailing-list) you can discuss jsprit related issues and you will probably get answers to your questions. In the [mailing list](https://discuss.graphhopper.com/) ([old mailing list](https://groups.google.com/group/jsprit-mailing-list)) you can discuss jsprit related issues and you will probably get answers to your questions.
####Stackoverflow: ####Stackoverflow:
You can also use [stackoverflow](http://stackoverflow.com/questions/tagged/jsprit) to discuss your issues. Tag it with <em>jsprit</em> then it is easier to keep track of your topic. You can also use [stackoverflow](http://stackoverflow.com/questions/tagged/jsprit) to discuss your issues. Tag it with <em>jsprit</em> then it is easier to keep track of your topic.

View file

@ -1,6 +1,11 @@
WHATS NEW WHATS NEW
========== ==========
------------------------------ ------------------------------
<b>2015-08-10</b> new release **v1.6.1**
Jsprit results are now reproducible since every time the algorithm runs, a unique random number generator (always starting with a
predefined seed) is invoked. If one does not want this behaviour, one can always specify custom random number generators.
<b>2015-03-12</b> new release **v1.6** <b>2015-03-12</b> new release **v1.6**
When reviewing the feedback from our users, we realized that jsprit cannot solve certain kinds of problems adequately. When reviewing the feedback from our users, we realized that jsprit cannot solve certain kinds of problems adequately.

View file

@ -1,8 +1,9 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>jsprit</groupId> <groupId>jsprit</groupId>
<artifactId>jsprit</artifactId> <artifactId>jsprit</artifactId>
<version>1.6.1-SNAPSHOT</version> <version>1.6.2-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jsprit-analysis</artifactId> <artifactId>jsprit-analysis</artifactId>
@ -43,7 +44,7 @@
<dependency> <dependency>
<groupId>org.jfree</groupId> <groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId> <artifactId>jfreechart</artifactId>
<version>1.0.14</version> <version>1.0.19</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>

View file

@ -92,8 +92,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
if (dgsFile.getName().endsWith("gz")) { if (dgsFile.getName().endsWith("gz")) {
gzipOs = new GZIPOutputStream(fos); gzipOs = new GZIPOutputStream(fos);
fileSink.begin(gzipOs); fileSink.begin(gzipOs);
} } else {
else{
fileSink.begin(fos); fileSink.begin(fos);
} }
graph.addSink(fileSink); graph.addSink(fileSink);
@ -151,8 +150,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
Job job = ((TourActivity.JobActivity) act).getJob(); Job job = ((TourActivity.JobActivity) act).getJob();
if (job instanceof Service) { if (job instanceof Service) {
nodeId = job.getId(); nodeId = job.getId();
} } else if (job instanceof Shipment) {
else if(job instanceof Shipment){
if (act.getName().equals("pickupShipment")) nodeId = getFromNodeId((Shipment) job); if (act.getName().equals("pickupShipment")) nodeId = getFromNodeId((Shipment) job);
else nodeId = getToNodeId((Shipment) job); else nodeId = getToNodeId((Shipment) job);
} }
@ -192,7 +190,8 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
removeEdge(enteringFromNode.getId()); removeEdge(enteringFromNode.getId());
removeEdge(enteringToNode.getId()); removeEdge(enteringToNode.getId());
if (graph.getNode(toNodeId).getLeavingEdgeSet().isEmpty()) { if (graph.getNode(toNodeId).getLeavingEdgeSet().isEmpty()) {
if(fromRoute.getVehicle().isReturnToDepot()) throw new IllegalStateException("leaving edge is missing"); if (fromRoute.getVehicle().isReturnToDepot())
throw new IllegalStateException("leaving edge is missing");
return; return;
} }
@ -203,8 +202,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
if (!fromRoute.getActivities().isEmpty()) { if (!fromRoute.getActivities().isEmpty()) {
addEdge(makeEdgeId(from, to), from.getId(), to.getId()); addEdge(makeEdgeId(from, to), from.getId(), to.getId());
} }
} } else {
else{
removeNodeAndBelongingEdges(fromNodeId, fromRoute); removeNodeAndBelongingEdges(fromNodeId, fromRoute);
removeNodeAndBelongingEdges(toNodeId, fromRoute); removeNodeAndBelongingEdges(toNodeId, fromRoute);
} }
@ -215,7 +213,9 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
if (edges.size() == 1) return edges.iterator().next(); if (edges.size() == 1) return edges.iterator().next();
else { else {
for (Edge e : edges) { for (Edge e : edges) {
if(e.getId().startsWith("shipment")){ continue; } if (e.getId().startsWith("shipment")) {
continue;
}
return e; return e;
} }
} }
@ -227,7 +227,9 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
if (enteringEdges.size() == 1) return enteringEdges.iterator().next(); if (enteringEdges.size() == 1) return enteringEdges.iterator().next();
else { else {
for (Edge e : enteringEdges) { for (Edge e : enteringEdges) {
if(e.getId().startsWith("shipment")){ continue; } if (e.getId().startsWith("shipment")) {
continue;
}
return e; return e;
} }
} }
@ -312,8 +314,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
Service service = (Service) job; Service service = (Service) job;
addNode(service.getId(), service.getLocation().getCoordinate()); addNode(service.getId(), service.getLocation().getCoordinate());
markService(service); markService(service);
} } else if (job instanceof Shipment) {
else if(job instanceof Shipment){
Shipment shipment = (Shipment) job; Shipment shipment = (Shipment) job;
String fromNodeId = getFromNodeId(shipment); String fromNodeId = getFromNodeId(shipment);
addNode(fromNodeId, shipment.getPickupLocation().getCoordinate()); addNode(fromNodeId, shipment.getPickupLocation().getCoordinate());
@ -335,8 +336,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
private void markService(Service service) { private void markService(Service service) {
if (service instanceof Delivery) { if (service instanceof Delivery) {
markDelivery(service.getId()); markDelivery(service.getId());
} } else {
else {
markPickup(service.getId()); markPickup(service.getId());
} }
} }
@ -438,8 +438,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
if (isFirst(insertionIndex)) { if (isFirst(insertionIndex)) {
node_i = makeStartId(data.getSelectedVehicle()); node_i = makeStartId(data.getSelectedVehicle());
} } else {
else {
TourActivity.JobActivity jobActivity = (TourActivity.JobActivity) route.getActivities().get(insertionIndex - 1); TourActivity.JobActivity jobActivity = (TourActivity.JobActivity) route.getActivities().get(insertionIndex - 1);
node_i = getNodeId(jobActivity); node_i = getNodeId(jobActivity);
} }
@ -447,8 +446,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
String node_j; String node_j;
if (isLast(insertionIndex, route)) { if (isLast(insertionIndex, route)) {
node_j = makeEndId(data.getSelectedVehicle()); node_j = makeEndId(data.getSelectedVehicle());
} } else {
else {
TourActivity.JobActivity jobActivity = (TourActivity.JobActivity) route.getActivities().get(insertionIndex); TourActivity.JobActivity jobActivity = (TourActivity.JobActivity) route.getActivities().get(insertionIndex);
node_j = getNodeId(jobActivity); node_j = getNodeId(jobActivity);
} }
@ -495,8 +493,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
private void markInserted(Job job) { private void markInserted(Job job) {
if (job instanceof Service) { if (job instanceof Service) {
markService((Service) job); markService((Service) job);
} } else {
else{
markShipment((Shipment) job); markShipment((Shipment) job);
} }
} }

View file

@ -136,11 +136,9 @@ public class AlgorithmEventsViewer {
} }
if (step == AlgorithmEventsRecorder.RUIN) { if (step == AlgorithmEventsRecorder.RUIN) {
delayContainer.delay = ruinDelay; delayContainer.delay = ruinDelay;
} } else if (step == AlgorithmEventsRecorder.CLEAR_SOLUTION) {
else if(step == AlgorithmEventsRecorder.CLEAR_SOLUTION){
delayContainer.delay = delay; delayContainer.delay = delay;
} } else if (step == AlgorithmEventsRecorder.BEFORE_RUIN_RENDER_SOLUTION) {
else if(step == AlgorithmEventsRecorder.BEFORE_RUIN_RENDER_SOLUTION){
delayContainer.delay = delay; delayContainer.delay = delay;
} }
} }

View file

@ -30,11 +30,10 @@ import java.util.Collection;
/** /**
* VehicleRoutingAlgorithm-Listener to record the solution-search-progress. * VehicleRoutingAlgorithm-Listener to record the solution-search-progress.
* * <p/>
* <p>Register this listener in VehicleRoutingAlgorithm. * <p>Register this listener in VehicleRoutingAlgorithm.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class AlgorithmSearchProgressChartListener implements IterationEndsListener, AlgorithmEndsListener, AlgorithmStartsListener { public class AlgorithmSearchProgressChartListener implements IterationEndsListener, AlgorithmEndsListener, AlgorithmStartsListener {
@ -60,7 +59,7 @@ public class AlgorithmSearchProgressChartListener implements IterationEndsListen
@Override @Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
log.info("create chart " + filename); log.info("create chart {}", filename);
XYLineChartBuilder.saveChartAsPNG(chartBuilder.build(), filename); XYLineChartBuilder.saveChartAsPNG(chartBuilder.build(), filename);
} }

View file

@ -39,12 +39,11 @@ public class ComputationalLaboratory {
/** /**
* Listener-interface to listen to calculation. * Listener-interface to listen to calculation.
* * <p/>
* <p>Note that calculations are run concurrently, i.e. a unique task that is distributed to an available thread is * <p>Note that calculations are run concurrently, i.e. a unique task that is distributed to an available thread is
* {algorithm, instance, run}. * {algorithm, instance, run}.
* *
* @author schroeder * @author schroeder
*
*/ */
public static interface CalculationListener extends LabListener { public static interface CalculationListener extends LabListener {
@ -65,7 +64,6 @@ public class ComputationalLaboratory {
* Collects whatever indicators you require by algorithmName, instanceName, run and indicator. * Collects whatever indicators you require by algorithmName, instanceName, run and indicator.
* *
* @author schroeder * @author schroeder
*
*/ */
public static class DataCollector { public static class DataCollector {
@ -82,6 +80,7 @@ public class ComputationalLaboratory {
this.run = run; this.run = run;
this.indicatorName = indicatorName; this.indicatorName = indicatorName;
} }
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
@ -100,6 +99,7 @@ public class ComputationalLaboratory {
result = prime * result + run; result = prime * result + run;
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
@ -128,15 +128,19 @@ public class ComputationalLaboratory {
return false; return false;
return true; return true;
} }
public String getInstanceName() { public String getInstanceName() {
return instanceName; return instanceName;
} }
public String getAlgorithmName() { public String getAlgorithmName() {
return algorithmName; return algorithmName;
} }
public int getRun() { public int getRun() {
return run; return run;
} }
public String getIndicatorName() { public String getIndicatorName() {
return indicatorName; return indicatorName;
} }
@ -153,6 +157,7 @@ public class ComputationalLaboratory {
private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>(); private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>();
private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>(); private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>();
/** /**
* Adds a single date by instanceName, algorithmName, run and indicatorName. * Adds a single date by instanceName, algorithmName, run and indicatorName.
* <p>If there is already an entry for this instance, algorithm, run and indicatorName, it is overwritten. * <p>If there is already an entry for this instance, algorithm, run and indicatorName, it is overwritten.
@ -164,7 +169,8 @@ public class ComputationalLaboratory {
* @param value * @param value
*/ */
public void addDate(String instanceName, String algorithmName, int run, String indicatorName, double value) { public void addDate(String instanceName, String algorithmName, int run, String indicatorName, double value) {
if(indicatorName.equals(SOLUTION_INDICATOR_NAME)) throw new IllegalArgumentException(indicatorName + " is already used internally. please choose another indicator-name."); if (indicatorName.equals(SOLUTION_INDICATOR_NAME))
throw new IllegalArgumentException(indicatorName + " is already used internally. please choose another indicator-name.");
Key key = new Key(instanceName, algorithmName, run, indicatorName); Key key = new Key(instanceName, algorithmName, run, indicatorName);
data.put(key, value); data.put(key, value);
} }
@ -285,7 +291,8 @@ public class ComputationalLaboratory {
* @throws IllegalStateException if there is already an algorithmFactory with the same name * @throws IllegalStateException if there is already an algorithmFactory with the same name
*/ */
public void addAlgorithmFactory(String name, VehicleRoutingAlgorithmFactory factory) { public void addAlgorithmFactory(String name, VehicleRoutingAlgorithmFactory factory) {
if(algorithmNames.contains(name)) throw new IllegalStateException("there is already a algorithmFactory with the same name (algorithmName="+name+"). unique names are required."); if (algorithmNames.contains(name))
throw new IllegalStateException("there is already a algorithmFactory with the same name (algorithmName=" + name + "). unique names are required.");
algorithms.add(new Algorithm(name, factory)); algorithms.add(new Algorithm(name, factory));
algorithmNames.add(name); algorithmNames.add(name);
} }
@ -306,7 +313,8 @@ public class ComputationalLaboratory {
* @throws IllegalStateException if there is already an instance with the same name. * @throws IllegalStateException if there is already an instance with the same name.
*/ */
public void addInstance(String name, VehicleRoutingProblem problem) { public void addInstance(String name, VehicleRoutingProblem problem) {
if(benchmarkInstances.contains(name)) throw new IllegalStateException("there is already an instance with the same name (instanceName="+name+"). unique names are required."); if (benchmarkInstances.contains(name))
throw new IllegalStateException("there is already an instance with the same name (instanceName=" + name + "). unique names are required.");
benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null)); benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null));
instanceNames.add(name); instanceNames.add(name);
} }
@ -318,7 +326,8 @@ public class ComputationalLaboratory {
* @throws IllegalStateException if there is already an instance with the same name. * @throws IllegalStateException if there is already an instance with the same name.
*/ */
public void addInstance(BenchmarkInstance instance) { public void addInstance(BenchmarkInstance instance) {
if(benchmarkInstances.contains(instance.name)) throw new IllegalStateException("there is already an instance with the same name (instanceName="+instance.name+"). unique names are required."); if (benchmarkInstances.contains(instance.name))
throw new IllegalStateException("there is already an instance with the same name (instanceName=" + instance.name + "). unique names are required.");
benchmarkInstances.add(instance); benchmarkInstances.add(instance);
instanceNames.add(instance.name); instanceNames.add(instance.name);
} }
@ -372,7 +381,7 @@ public class ComputationalLaboratory {
/** /**
* Runs experiments. * Runs experiments.
* * <p/>
* <p>If nuThreads > 1 it runs them concurrently, i.e. individual runs are distributed to available threads. Therefore * <p>If nuThreads > 1 it runs them concurrently, i.e. individual runs are distributed to available threads. Therefore
* a unique task is defined by its algorithmName, instanceName and its runNumber. * a unique task is defined by its algorithmName, instanceName and its runNumber.
* <p>If you have one algorithm called "myAlgorithm" and one instance called "myInstance", and you need to run "myAlgorithm" on "myInstance" three times * <p>If you have one algorithm called "myAlgorithm" and one instance called "myInstance", and you need to run "myAlgorithm" on "myInstance" three times
@ -380,8 +389,8 @@ public class ComputationalLaboratory {
* <p>You can register whatever analysisTool you require by implementing and registering CalculationListener. Then your tool is informed just * <p>You can register whatever analysisTool you require by implementing and registering CalculationListener. Then your tool is informed just
* before a calculation starts as well as just after a calculation has been finished. * before a calculation starts as well as just after a calculation has been finished.
* *
* @see CalculationListener
* @throws IllegalStateException if either no algorithm or no instance has been specified * @throws IllegalStateException if either no algorithm or no instance has been specified
* @see CalculationListener
*/ */
public void run() { public void run() {
if (algorithms.isEmpty()) { if (algorithms.isEmpty()) {
@ -398,8 +407,7 @@ public class ComputationalLaboratory {
for (final BenchmarkInstance p : benchmarkInstances) { for (final BenchmarkInstance p : benchmarkInstances) {
for (int run = 0; run < runs; run++) { for (int run = 0; run < runs; run++) {
final int r = run; final int r = run;
// runAlgorithm(p, algorithm, r+1); try {
executor.submit(new Runnable() { executor.submit(new Runnable() {
@Override @Override
@ -408,6 +416,9 @@ public class ComputationalLaboratory {
} }
}); });
} catch (Exception e) {
throw new RuntimeException(e);
}
} }
} }
} }
@ -416,7 +427,7 @@ public class ComputationalLaboratory {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); throw new RuntimeException(e);
} }
System.out.println("benchmarking done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]"); System.out.println("benchmarking done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]");
informEnd(); informEnd();

View file

@ -41,7 +41,6 @@ public class ConcurrentBenchmarker {
} }
private String algorithmConfig = null; private String algorithmConfig = null;
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>(); private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
@ -63,7 +62,9 @@ public class ConcurrentBenchmarker {
private VehicleRoutingAlgorithmFactory algorithmFactory; private VehicleRoutingAlgorithmFactory algorithmFactory;
public void setCost(Cost cost){ this.cost = cost; } public void setCost(Cost cost) {
this.cost = cost;
}
public ConcurrentBenchmarker(String algorithmConfig) { public ConcurrentBenchmarker(String algorithmConfig) {
super(); super();
@ -165,8 +166,7 @@ public class ConcurrentBenchmarker {
private VehicleRoutingAlgorithm createAlgorithm(BenchmarkInstance p) { private VehicleRoutingAlgorithm createAlgorithm(BenchmarkInstance p) {
if (algorithmConfig != null) { if (algorithmConfig != null) {
return VehicleRoutingAlgorithms.readAndCreateAlgorithm(p.vrp, algorithmConfig); return VehicleRoutingAlgorithms.readAndCreateAlgorithm(p.vrp, algorithmConfig);
} } else {
else{
return algorithmFactory.createAlgorithm(p.vrp); return algorithmFactory.createAlgorithm(p.vrp);
} }

View file

@ -113,7 +113,6 @@ public class GraphStreamViewer {
"}"; "}";
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
public static String SIMPLE_WHITE = public static String SIMPLE_WHITE =
"node {" + "node {" +
@ -308,7 +307,7 @@ public class GraphStreamViewer {
/** /**
* Sets the camera-view. Center describes the center-focus of the camera and zoomFactor its * Sets the camera-view. Center describes the center-focus of the camera and zoomFactor its
* zoomFactor. * zoomFactor.
* * <p/>
* <p>a zoomFactor < 1 zooms in and > 1 out. * <p>a zoomFactor < 1 zooms in and > 1 out.
* *
* @param centerX x coordinate of center * @param centerX x coordinate of center
@ -392,8 +391,7 @@ public class GraphStreamViewer {
for (Job j : vrp.getJobs().values()) { for (Job j : vrp.getJobs().values()) {
if (j instanceof Service) { if (j instanceof Service) {
renderService(g, (Service) j, label); renderService(g, (Service) j, label);
} } else if (j instanceof Shipment) {
else if(j instanceof Shipment){
renderShipment(g, (Shipment) j, label, renderShipments); renderShipment(g, (Shipment) j, label, renderShipments);
} }
sleep(renderDelay_in_ms); sleep(renderDelay_in_ms);
@ -583,22 +581,20 @@ public class GraphStreamViewer {
if (label.equals(Label.ACTIVITY)) { if (label.equals(Label.ACTIVITY)) {
Node actNode = g.getNode(currIdentifier); Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", act.getName()); actNode.addAttribute("ui.label", act.getName());
} } else if (label.equals(Label.JOB_NAME)) {
else if(label.equals(Label.JOB_NAME)){
Node actNode = g.getNode(currIdentifier); Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", job.getName()); actNode.addAttribute("ui.label", job.getName());
} } else if (label.equals(Label.ARRIVAL_TIME)) {
else if(label.equals(Label.ARRIVAL_TIME)){
Node actNode = g.getNode(currIdentifier); Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime())); actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getArrTime()));
} } else if (label.equals(Label.DEPARTURE_TIME)) {
else if(label.equals(Label.DEPARTURE_TIME)){
Node actNode = g.getNode(currIdentifier); Node actNode = g.getNode(currIdentifier);
actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime())); actNode.addAttribute("ui.label", Time.parseSecondsToTime(act.getEndTime()));
} }
g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true); g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, currIdentifier, true);
if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute"); if (act instanceof PickupActivity) g.getNode(currIdentifier).addAttribute("ui.class", "pickupInRoute");
else if (act instanceof DeliveryActivity) g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute"); else if (act instanceof DeliveryActivity)
g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute");
prevIdentifier = currIdentifier; prevIdentifier = currIdentifier;
vehicle_edgeId++; vehicle_edgeId++;
sleep(renderDelay_in_ms); sleep(renderDelay_in_ms);

View file

@ -53,7 +53,6 @@ import java.util.*;
* <p>Note that every item to be rendered need to have coordinates. * <p>Note that every item to be rendered need to have coordinates.
* *
* @author schroeder * @author schroeder
*
*/ */
public class Plotter { public class Plotter {
@ -124,6 +123,7 @@ public class Plotter {
double minY; double minY;
double maxX; double maxX;
double maxY; double maxY;
public BoundingBox(double minX, double minY, double maxX, double maxY) { public BoundingBox(double minX, double minY, double maxX, double maxY) {
super(); super();
this.minX = minX; this.minX = minX;
@ -143,8 +143,8 @@ public class Plotter {
/** /**
* Label to label ID (=jobId), SIZE (=jobSize=jobCapacityDimensions) * Label to label ID (=jobId), SIZE (=jobSize=jobCapacityDimensions)
* @author schroeder
* *
* @author schroeder
*/ */
public static enum Label { public static enum Label {
ID, SIZE, @SuppressWarnings("UnusedDeclaration")NO_LABEL ID, SIZE, @SuppressWarnings("UnusedDeclaration")NO_LABEL
@ -224,6 +224,7 @@ public class Plotter {
/** /**
* Sets a label. * Sets a label.
*
* @param label of jobs * @param label of jobs
* @return plotter * @return plotter
*/ */
@ -274,17 +275,15 @@ public class Plotter {
if (!pngFileName.endsWith(".png")) filename += ".png"; if (!pngFileName.endsWith(".png")) filename += ".png";
if (plotSolutionAsWell) { if (plotSolutionAsWell) {
plot(vrp, routes, filename, plotTitle); plot(vrp, routes, filename, plotTitle);
} } else if (!(vrp.getInitialVehicleRoutes().isEmpty())) {
else if(!(vrp.getInitialVehicleRoutes().isEmpty())){
plot(vrp, vrp.getInitialVehicleRoutes(), filename, plotTitle); plot(vrp, vrp.getInitialVehicleRoutes(), filename, plotTitle);
} } else {
else{
plot(vrp, null, filename, plotTitle); plot(vrp, null, filename, plotTitle);
} }
} }
private void plot(VehicleRoutingProblem vrp, final Collection<VehicleRoute> routes, String pngFile, String title) { private void plot(VehicleRoutingProblem vrp, final Collection<VehicleRoute> routes, String pngFile, String title) {
log.info("plot to " + pngFile); log.info("plot to {}", pngFile);
XYSeriesCollection problem; XYSeriesCollection problem;
XYSeriesCollection solution = null; XYSeriesCollection solution = null;
final XYSeriesCollection shipments; final XYSeriesCollection shipments;
@ -428,8 +427,7 @@ public class Plotter {
if (boundingBox == null) { if (boundingBox == null) {
xAxis.setRangeWithMargins(getDomainRange(problem)); xAxis.setRangeWithMargins(getDomainRange(problem));
yAxis.setRangeWithMargins(getRange(problem)); yAxis.setRangeWithMargins(getRange(problem));
} } else {
else{
xAxis.setRangeWithMargins(new Range(boundingBox.minX, boundingBox.maxX)); xAxis.setRangeWithMargins(new Range(boundingBox.minX, boundingBox.maxX));
yAxis.setRangeWithMargins(new Range(boundingBox.minY, boundingBox.maxY)); yAxis.setRangeWithMargins(new Range(boundingBox.minY, boundingBox.maxY));
} }
@ -500,8 +498,7 @@ public class Plotter {
if (first) { if (first) {
first = false; first = false;
shipmentSeries = new XYSeries(ship, false, true); shipmentSeries = new XYSeries(ship, false, true);
} } else {
else{
shipmentSeries = new XYSeries(sCounter, false, true); shipmentSeries = new XYSeries(sCounter, false, true);
sCounter++; sCounter++;
} }
@ -530,8 +527,7 @@ public class Plotter {
addLabel(s, dataItem2); addLabel(s, dataItem2);
markItem(dataItem2, Activity.DELIVERY); markItem(dataItem2, Activity.DELIVERY);
containsDeliveryAct = true; containsDeliveryAct = true;
} } else if (job instanceof Pickup) {
else if(job instanceof Pickup){
Pickup service = (Pickup) job; Pickup service = (Pickup) job;
Coordinate coord = getCoordinate(service.getLocation().getCoordinate()); Coordinate coord = getCoordinate(service.getLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor); XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor);
@ -539,8 +535,7 @@ public class Plotter {
addLabel(service, dataItem); addLabel(service, dataItem);
markItem(dataItem, Activity.PICKUP); markItem(dataItem, Activity.PICKUP);
containsPickupAct = true; containsPickupAct = true;
} } else if (job instanceof Delivery) {
else if(job instanceof Delivery){
Delivery service = (Delivery) job; Delivery service = (Delivery) job;
Coordinate coord = getCoordinate(service.getLocation().getCoordinate()); Coordinate coord = getCoordinate(service.getLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor); XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor);
@ -548,8 +543,7 @@ public class Plotter {
addLabel(service, dataItem); addLabel(service, dataItem);
markItem(dataItem, Activity.DELIVERY); markItem(dataItem, Activity.DELIVERY);
containsDeliveryAct = true; containsDeliveryAct = true;
} } else if (job instanceof Service) {
else if(job instanceof Service){
Service service = (Service) job; Service service = (Service) job;
Coordinate coord = getCoordinate(service.getLocation().getCoordinate()); Coordinate coord = getCoordinate(service.getLocation().getCoordinate());
XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor); XYDataItem dataItem = new XYDataItem(coord.getX() * scalingFactor, coord.getY() * scalingFactor);
@ -557,8 +551,7 @@ public class Plotter {
addLabel(service, dataItem); addLabel(service, dataItem);
markItem(dataItem, Activity.SERVICE); markItem(dataItem, Activity.SERVICE);
containsServiceAct = true; containsServiceAct = true;
} } else {
else{
throw new IllegalStateException("job instanceof " + job.getClass().toString() + ". this is not supported."); throw new IllegalStateException("job instanceof " + job.getClass().toString() + ". this is not supported.");
} }
} }
@ -566,8 +559,7 @@ public class Plotter {
private void addLabel(Job job, XYDataItem dataItem) { private void addLabel(Job job, XYDataItem dataItem) {
if (this.label.equals(Label.SIZE)) { if (this.label.equals(Label.SIZE)) {
labelsByDataItem.put(dataItem, getSizeString(job)); labelsByDataItem.put(dataItem, getSizeString(job));
} } else if (this.label.equals(Label.ID)) {
else if(this.label.equals(Label.ID)){
labelsByDataItem.put(dataItem, String.valueOf(job.getId())); labelsByDataItem.put(dataItem, String.valueOf(job.getId()));
} }
} }
@ -580,8 +572,7 @@ public class Plotter {
if (firstDim) { if (firstDim) {
builder.append(String.valueOf(job.getSize().get(i))); builder.append(String.valueOf(job.getSize().get(i)));
firstDim = false; firstDim = false;
} } else {
else {
builder.append(","); builder.append(",");
builder.append(String.valueOf(job.getSize().get(i))); builder.append(String.valueOf(job.getSize().get(i)));
} }

View file

@ -49,7 +49,7 @@ public class StopWatch implements AlgorithmStartsListener, AlgorithmEndsListener
@Override @Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
stop(); stop();
log.info("computation time [in sec]: " + getCompTimeInSeconds()); log.info("computation time [in sec]: {}", getCompTimeInSeconds());
} }
public void stop() { public void stop() {

View file

@ -32,9 +32,7 @@ import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /**
*
* @author schroeder * @author schroeder
*
*/ */
public class XYLineChartBuilder { public class XYLineChartBuilder {
@ -58,7 +56,6 @@ public class XYLineChartBuilder {
* @param chartTitle appears on top of the XYLineChart * @param chartTitle appears on top of the XYLineChart
* @param xDomainName appears below the xAxis * @param xDomainName appears below the xAxis
* @param yDomainName appears beside the yAxis * @param yDomainName appears beside the yAxis
*
* @return the builder * @return the builder
*/ */
public static XYLineChartBuilder newInstance(String chartTitle, String xDomainName, String yDomainName) { public static XYLineChartBuilder newInstance(String chartTitle, String xDomainName, String yDomainName) {
@ -95,6 +92,7 @@ public class XYLineChartBuilder {
/** /**
* Builds and returns JFreeChart. * Builds and returns JFreeChart.
*
* @return * @return
*/ */
public JFreeChart build() { public JFreeChart build() {

View file

@ -16,10 +16,10 @@
******************************************************************************/ ******************************************************************************/
package jsprit.analysis.util; package jsprit.analysis.util;
import java.util.Collection;
import jsprit.core.util.BenchmarkResult; import jsprit.core.util.BenchmarkResult;
import java.util.Collection;
public interface BenchmarkWriter { public interface BenchmarkWriter {
public void write(Collection<BenchmarkResult> results); public void write(Collection<BenchmarkResult> results);
} }

View file

@ -16,14 +16,14 @@
******************************************************************************/ ******************************************************************************/
package jsprit.analysis.util; package jsprit.analysis.util;
import jsprit.core.util.BenchmarkResult;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import jsprit.core.util.BenchmarkResult;
public class HtmlBenchmarkTableWriter implements BenchmarkWriter { public class HtmlBenchmarkTableWriter implements BenchmarkWriter {
private String filename; private String filename;
@ -169,15 +169,13 @@ public class HtmlBenchmarkTableWriter implements BenchmarkWriter{
if (sum_res_star != null) { if (sum_res_star != null) {
writer.write(date(Double.valueOf(round(sum_res_star.doubleValue() / (double) results.size(), 2)).toString()) + newline()); writer.write(date(Double.valueOf(round(sum_res_star.doubleValue() / (double) results.size(), 2)).toString()) + newline());
delta_res = (sum_avg_result / sum_res_star - 1) * 100; delta_res = (sum_avg_result / sum_res_star - 1) * 100;
} } else writer.write(date("null") + newline());
else writer.write(date("null") + newline());
//bestKnownVeh //bestKnownVeh
Double delta_veh = null; Double delta_veh = null;
if (sum_veh_star != null) { if (sum_veh_star != null) {
writer.write(date(Double.valueOf(round(sum_veh_star.doubleValue() / (double) results.size(), 2)).toString()) + newline()); writer.write(date(Double.valueOf(round(sum_veh_star.doubleValue() / (double) results.size(), 2)).toString()) + newline());
delta_veh = (sum_avg_veh - sum_veh_star) / (double) results.size(); delta_veh = (sum_avg_veh - sum_veh_star) / (double) results.size();
} } else writer.write(date("null") + newline());
else writer.write(date("null") + newline());
writer.write(closeRow() + newline()); writer.write(closeRow() + newline());
writer.write(closeTable() + newline()); writer.write(closeTable() + newline());
@ -255,5 +253,4 @@ public class HtmlBenchmarkTableWriter implements BenchmarkWriter{
} }
} }

View file

@ -1,4 +1,3 @@
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Copyright (C) 2014 Stefan Schroeder ~ Copyright (C) 2014 Stefan Schroeder
~ ~
@ -16,11 +15,12 @@
~ License along with this library. If not, see <http://www.gnu.org/licenses />. ~ License along with this library. If not, see <http://www.gnu.org/licenses />.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>jsprit</groupId> <groupId>jsprit</groupId>
<artifactId>jsprit</artifactId> <artifactId>jsprit</artifactId>
<version>1.6.1-SNAPSHOT</version> <version>1.6.2-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>jsprit-core</artifactId> <artifactId>jsprit-core</artifactId>
@ -55,8 +55,37 @@
</plugin> </plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<excludedGroups>jsprit.core.IntegrationTest</excludedGroups>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<includes>
<include>**/*.java</include>
</includes>
<groups>jsprit.core.IntegrationTest</groups>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build> </build>
<dependencies> <dependencies>
<dependency> <dependency>
@ -77,8 +106,8 @@
<dependency> <dependency>
<groupId>xerces</groupId> <groupId>xerces</groupId>
<artifactId>xerces</artifactId> <artifactId>xercesImpl</artifactId>
<version>2.4.0</version> <version>2.11.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>

View file

@ -25,6 +25,7 @@ import jsprit.core.problem.solution.InitialSolutionFactory;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.Vehicle;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -60,7 +61,11 @@ public final class InsertionInitialSolutionFactory implements InitialSolutionFac
} }
private List<Job> getUnassignedJobs(VehicleRoutingProblem vrp) { private List<Job> getUnassignedJobs(VehicleRoutingProblem vrp) {
return new ArrayList<Job>(vrp.getJobs().values()); ArrayList<Job> jobs = new ArrayList<Job>(vrp.getJobs().values());
for (Vehicle v : vrp.getVehicles()) {
if (v.getBreak() != null) jobs.add(v.getBreak());
}
return jobs;
} }
} }

View file

@ -25,6 +25,7 @@ import jsprit.core.algorithm.recreate.VehicleSwitched;
import jsprit.core.algorithm.state.*; import jsprit.core.algorithm.state.*;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.constraint.ConstraintManager; import jsprit.core.problem.constraint.ConstraintManager;
import jsprit.core.problem.constraint.SwitchNotFeasible;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
@ -89,10 +90,11 @@ public class PrettyAlgorithmBuilder {
constraintManager.addTimeWindowConstraint(); constraintManager.addTimeWindowConstraint();
constraintManager.addLoadConstraint(); constraintManager.addLoadConstraint();
constraintManager.addSkillsConstraint(); constraintManager.addSkillsConstraint();
constraintManager.addConstraint(new SwitchNotFeasible(stateManager));
stateManager.updateLoadStates(); stateManager.updateLoadStates();
stateManager.updateTimeWindowStates(); stateManager.updateTimeWindowStates();
UpdateVehicleDependentPracticalTimeWindows tw_updater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts()); UpdateVehicleDependentPracticalTimeWindows twUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts());
tw_updater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() { twUpdater.setVehiclesToUpdate(new UpdateVehicleDependentPracticalTimeWindows.VehiclesToUpdate() {
Map<VehicleTypeKey, Vehicle> uniqueTypes = new HashMap<VehicleTypeKey, Vehicle>(); Map<VehicleTypeKey, Vehicle> uniqueTypes = new HashMap<VehicleTypeKey, Vehicle>();
@ -109,12 +111,14 @@ public class PrettyAlgorithmBuilder {
vehicles.addAll(uniqueTypes.values()); vehicles.addAll(uniqueTypes.values());
return vehicles; return vehicles;
} }
}); });
stateManager.addStateUpdater(tw_updater); stateManager.addStateUpdater(twUpdater);
stateManager.updateSkillStates(); stateManager.updateSkillStates();
stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen()); stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen());
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS)); stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS));
stateManager.addStateUpdater(new UpdateVariableCosts(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager)); stateManager.addStateUpdater(new UpdateVariableCosts(vrp.getActivityCosts(), vrp.getTransportCosts(), stateManager));
stateManager.addStateUpdater(new UpdateFutureWaitingTimes(stateManager, vrp.getTransportCosts()));
} }
VehicleRoutingAlgorithm vra = new VehicleRoutingAlgorithm(vrp, searchStrategyManager); VehicleRoutingAlgorithm vra = new VehicleRoutingAlgorithm(vrp, searchStrategyManager);
vra.addListener(stateManager); vra.addListener(stateManager);
@ -136,8 +140,10 @@ public class PrettyAlgorithmBuilder {
vra.addListener(new AlgorithmStartsListener() { vra.addListener(new AlgorithmStartsListener() {
@Override @Override
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) { public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
if (solutions.isEmpty()) {
solutions.add(new InsertionInitialSolutionFactory(iniInsertionStrategy, iniObjFunction).createSolution(vrp)); solutions.add(new InsertionInitialSolutionFactory(iniInsertionStrategy, iniObjFunction).createSolution(vrp));
} }
}
}); });
} }
addArbitraryListener(vra); addArbitraryListener(vra);

View file

@ -60,7 +60,9 @@ public class SearchStrategy {
return strategyId; return strategyId;
} }
public String getStrategyId() { return strategyId; } public String getStrategyId() {
return strategyId;
}
@Override @Override
public String toString() { public String toString() {
@ -88,7 +90,7 @@ public class SearchStrategy {
this.solutionAcceptor = solutionAcceptor; this.solutionAcceptor = solutionAcceptor;
this.solutionCostCalculator = solutionCostCalculator; this.solutionCostCalculator = solutionCostCalculator;
this.id = id; this.id = id;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public String getId() { public String getId() {
@ -124,7 +126,7 @@ public class SearchStrategy {
/** /**
* Runs the search-strategy and its according modules, and returns DiscoveredSolution. * Runs the search-strategy and its according modules, and returns DiscoveredSolution.
* * <p/>
* <p>This involves three basic steps: 1) Selecting a solution from solutions (input parameter) according to {@link jsprit.core.algorithm.selector.SolutionSelector}, 2) running the modules * <p>This involves three basic steps: 1) Selecting a solution from solutions (input parameter) according to {@link jsprit.core.algorithm.selector.SolutionSelector}, 2) running the modules
* ({@link jsprit.core.algorithm.SearchStrategyModule}) on the selectedSolution and 3) accepting the new solution according to {@link jsprit.core.algorithm.acceptor.SolutionAcceptor}. * ({@link jsprit.core.algorithm.SearchStrategyModule}) on the selectedSolution and 3) accepting the new solution according to {@link jsprit.core.algorithm.acceptor.SolutionAcceptor}.
* <p> Note that after 1) the selected solution is copied, thus the original solution is not modified. * <p> Note that after 1) the selected solution is copied, thus the original solution is not modified.
@ -159,7 +161,7 @@ public class SearchStrategy {
public void addModule(SearchStrategyModule module) { public void addModule(SearchStrategyModule module) {
if (module == null) throw new IllegalStateException("module to be added is null."); if (module == null) throw new IllegalStateException("module to be added is null.");
searchStrategyModules.add(module); searchStrategyModules.add(module);
logger.debug("module added [module=" + module + "][#modules=" + searchStrategyModules.size() + "]"); logger.debug("module added [module={}][#modules={}]", module, searchStrategyModules.size());
} }
public void addModuleListener(SearchStrategyModuleListener moduleListener) { public void addModuleListener(SearchStrategyModuleListener moduleListener) {

View file

@ -55,6 +55,7 @@ public class SearchStrategyManager {
* Returns the probabilities. * Returns the probabilities.
* [schroeder (2014.11.21): Now they are actually no propabilities anymore but weights. The resulting probabilities * [schroeder (2014.11.21): Now they are actually no propabilities anymore but weights. The resulting probabilities
* are calculated here with the sum of weights] * are calculated here with the sum of weights]
*
* @return list of probabilities * @return list of probabilities
*/ */
@Deprecated @Deprecated
@ -62,7 +63,9 @@ public class SearchStrategyManager {
return Collections.unmodifiableList(weights); return Collections.unmodifiableList(weights);
} }
public List<Double> getWeights(){ return Collections.unmodifiableList(weights); } public List<Double> getWeights() {
return Collections.unmodifiableList(weights);
}
public double getWeight(String strategyId) { public double getWeight(String strategyId) {
return weights.get(id2index.get(strategyId)); return weights.get(id2index.get(strategyId));
@ -70,6 +73,7 @@ public class SearchStrategyManager {
/** /**
* adds a new search strategy with a certain weight. * adds a new search strategy with a certain weight.
*
* @param strategy strategy to be added * @param strategy strategy to be added
* @param weight of corresponding strategy to be added * @param weight of corresponding strategy to be added
* @throws java.lang.IllegalStateException if strategy is null OR weight < 0 * @throws java.lang.IllegalStateException if strategy is null OR weight < 0
@ -112,7 +116,8 @@ public class SearchStrategyManager {
* @throws java.lang.IllegalStateException if randomNumberGenerator is null OR no search strategy can be found * @throws java.lang.IllegalStateException if randomNumberGenerator is null OR no search strategy can be found
*/ */
public SearchStrategy getRandomStrategy() { public SearchStrategy getRandomStrategy() {
if(random == null) throw new IllegalStateException("randomizer is null. make sure you set random object correctly"); if (random == null)
throw new IllegalStateException("randomizer is null. make sure you set random object correctly");
double randomFig = random.nextDouble(); double randomFig = random.nextDouble();
double sumProbabilities = 0.0; double sumProbabilities = 0.0;
for (int i = 0; i < weights.size(); i++) { for (int i = 0; i < weights.size(); i++) {

View file

@ -31,7 +31,6 @@ import jsprit.core.problem.vehicle.Vehicle;
* this objective function. * this objective function.
* *
* @author schroeder * @author schroeder
*
*/ */
public class VariablePlusFixedSolutionCostCalculatorFactory { public class VariablePlusFixedSolutionCostCalculatorFactory {

View file

@ -20,6 +20,7 @@ import jsprit.core.algorithm.SearchStrategy.DiscoveredSolution;
import jsprit.core.algorithm.listener.*; import jsprit.core.algorithm.listener.*;
import jsprit.core.algorithm.termination.PrematureAlgorithmTermination; import jsprit.core.algorithm.termination.PrematureAlgorithmTermination;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
@ -35,7 +36,6 @@ import java.util.Collection;
* Algorithm that solves a {@link VehicleRoutingProblem}. * Algorithm that solves a {@link VehicleRoutingProblem}.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class VehicleRoutingAlgorithm { public class VehicleRoutingAlgorithm {
@ -142,8 +142,8 @@ public class VehicleRoutingAlgorithm {
} }
} }
if (nuJobs != problem.getJobs().values().size()) { if (nuJobs != problem.getJobs().values().size()) {
logger.warn("number of jobs in initial solution (" + nuJobs + ") is not equal nuJobs in vehicle routing problem (" + problem.getJobs().values().size() + ")" + logger.warn("number of jobs in initial solution ({}) is not equal nuJobs in vehicle routing problem ({})" +
"\n this might yield unintended effects, e.g. initial solution cannot be improved anymore."); "\n this might yield unintended effects, e.g. initial solution cannot be improved anymore.", nuJobs, problem.getJobs().values().size());
} }
} }
@ -179,7 +179,7 @@ public class VehicleRoutingAlgorithm {
/** /**
* Runs the vehicle routing algorithm and returns a number of generated solutions. * Runs the vehicle routing algorithm and returns a number of generated solutions.
* * <p/>
* <p>The algorithm runs as long as it is specified in nuOfIterations and prematureBreak. In each iteration it selects a searchStrategy according * <p>The algorithm runs as long as it is specified in nuOfIterations and prematureBreak. In each iteration it selects a searchStrategy according
* to searchStrategyManager and runs the strategy to improve solutions. * to searchStrategyManager and runs the strategy to improve solutions.
* <p>Note that clients are allowed to observe/listen the algorithm. See {@link VehicleRoutingAlgorithmListener} and its according listeners. * <p>Note that clients are allowed to observe/listen the algorithm. See {@link VehicleRoutingAlgorithmListener} and its according listeners.
@ -188,34 +188,35 @@ public class VehicleRoutingAlgorithm {
* @see {@link SearchStrategyManager}, {@link VehicleRoutingAlgorithmListener}, {@link AlgorithmStartsListener}, {@link AlgorithmEndsListener}, {@link IterationStartsListener}, {@link IterationEndsListener} * @see {@link SearchStrategyManager}, {@link VehicleRoutingAlgorithmListener}, {@link AlgorithmStartsListener}, {@link AlgorithmEndsListener}, {@link IterationStartsListener}, {@link IterationEndsListener}
*/ */
public Collection<VehicleRoutingProblemSolution> searchSolutions() { public Collection<VehicleRoutingProblemSolution> searchSolutions() {
logger.info("algorithm starts: " + "[maxIterations=" + maxIterations + "]"); logger.info("algorithm starts: [maxIterations={}]", maxIterations);
double now = System.currentTimeMillis(); double now = System.currentTimeMillis();
int noIterationsThisAlgoIsRunning = maxIterations; int noIterationsThisAlgoIsRunning = maxIterations;
counter.reset(); counter.reset();
Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions); Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions);
algorithmStarts(problem, solutions); algorithmStarts(problem, solutions);
bestEver = Solutions.bestOf(solutions); bestEver = Solutions.bestOf(solutions);
if (logger.isTraceEnabled()) log(solutions);
logger.info("iterations start"); logger.info("iterations start");
for (int i = 0; i < maxIterations; i++) { for (int i = 0; i < maxIterations; i++) {
iterationStarts(i + 1, problem, solutions); iterationStarts(i + 1, problem, solutions);
logger.debug("start iteration: " + i); logger.debug("start iteration: {}", i);
counter.incCounter(); counter.incCounter();
SearchStrategy strategy = searchStrategyManager.getRandomStrategy(); SearchStrategy strategy = searchStrategyManager.getRandomStrategy();
DiscoveredSolution discoveredSolution = strategy.run(problem, solutions); DiscoveredSolution discoveredSolution = strategy.run(problem, solutions);
logger.trace("discovered solution: " + discoveredSolution); if (logger.isTraceEnabled()) log(discoveredSolution);
memorizeIfBestEver(discoveredSolution); memorizeIfBestEver(discoveredSolution);
selectedStrategy(discoveredSolution, problem, solutions); selectedStrategy(discoveredSolution, problem, solutions);
if (terminationManager.isPrematureBreak(discoveredSolution)) { if (terminationManager.isPrematureBreak(discoveredSolution)) {
logger.info("premature algorithm termination at iteration "+ (i+1)); logger.info("premature algorithm termination at iteration {}", (i + 1));
noIterationsThisAlgoIsRunning = (i + 1); noIterationsThisAlgoIsRunning = (i + 1);
break; break;
} }
iterationEnds(i + 1, problem, solutions); iterationEnds(i + 1, problem, solutions);
} }
logger.info("iterations end at " + noIterationsThisAlgoIsRunning + " iterations"); logger.info("iterations end at {} iterations", noIterationsThisAlgoIsRunning);
addBestEver(solutions); addBestEver(solutions);
algorithmEnds(problem, solutions); algorithmEnds(problem, solutions);
logger.info("took " + ((System.currentTimeMillis()-now)/1000.0) + " seconds"); logger.info("took {} seconds", ((System.currentTimeMillis() - now) / 1000.0));
return solutions; return solutions;
} }
@ -223,10 +224,43 @@ public class VehicleRoutingAlgorithm {
if (bestEver != null) solutions.add(bestEver); if (bestEver != null) solutions.add(bestEver);
} }
private void log(Collection<VehicleRoutingProblemSolution> solutions) {
for (VehicleRoutingProblemSolution sol : solutions) log(sol);
}
private void log(VehicleRoutingProblemSolution solution) {
logger.trace("solution costs: {}", solution.getCost());
for (VehicleRoute r : solution.getRoutes()) {
StringBuilder b = new StringBuilder();
b.append(r.getVehicle().getId()).append(" : ").append("[ ");
for (TourActivity act : r.getActivities()) {
if (act instanceof TourActivity.JobActivity) {
b.append(((TourActivity.JobActivity) act).getJob().getId()).append(" ");
}
}
b.append("]");
logger.trace(b.toString());
}
StringBuilder b = new StringBuilder();
b.append("unassigned : [ ");
for (Job j : solution.getUnassignedJobs()) {
b.append(j.getId()).append(" ");
}
b.append("]");
logger.trace(b.toString());
}
private void log(DiscoveredSolution discoveredSolution) {
logger.trace("discovered solution: {}", discoveredSolution);
log(discoveredSolution.getSolution());
}
private void memorizeIfBestEver(DiscoveredSolution discoveredSolution) { private void memorizeIfBestEver(DiscoveredSolution discoveredSolution) {
if (discoveredSolution == null) return; if (discoveredSolution == null) return;
if (bestEver == null) bestEver = discoveredSolution.getSolution(); if (bestEver == null) bestEver = discoveredSolution.getSolution();
else if(discoveredSolution.getSolution().getCost() < bestEver.getCost()) bestEver = discoveredSolution.getSolution(); else if (discoveredSolution.getSolution().getCost() < bestEver.getCost())
bestEver = discoveredSolution.getSolution();
} }
@ -244,8 +278,10 @@ public class VehicleRoutingAlgorithm {
public void addListener(VehicleRoutingAlgorithmListener l) { public void addListener(VehicleRoutingAlgorithmListener l) {
algoListeners.addListener(l); algoListeners.addListener(l);
if(l instanceof SearchStrategyListener) searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l); if (l instanceof SearchStrategyListener)
if(l instanceof SearchStrategyModuleListener) searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l); searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l);
if (l instanceof SearchStrategyModuleListener)
searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l);
} }
private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
@ -267,7 +303,7 @@ public class VehicleRoutingAlgorithm {
*/ */
public void setMaxIterations(int maxIterations) { public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations; this.maxIterations = maxIterations;
logger.debug("set maxIterations to " + this.maxIterations); logger.debug("set maxIterations to {}", this.maxIterations);
} }
/** /**

View file

@ -29,7 +29,6 @@ import jsprit.core.problem.solution.SolutionCostCalculator;
* Builder that builds a {@link VehicleRoutingAlgorithm}. * Builder that builds a {@link VehicleRoutingAlgorithm}.
* *
* @author schroeder * @author schroeder
*
*/ */
public class VehicleRoutingAlgorithmBuilder { public class VehicleRoutingAlgorithmBuilder {
@ -77,7 +76,7 @@ public class VehicleRoutingAlgorithmBuilder {
/** /**
* Sets custom objective function. * Sets custom objective function.
* * <p/>
* <p>If objective function is not set, a default function is applied (which basically minimizes * <p>If objective function is not set, a default function is applied (which basically minimizes
* fixed and variable transportation costs ({@link VariablePlusFixedSolutionCostCalculatorFactory}). * fixed and variable transportation costs ({@link VariablePlusFixedSolutionCostCalculatorFactory}).
* *
@ -100,10 +99,9 @@ public class VehicleRoutingAlgorithmBuilder {
/** /**
* Adds core constraints. * Adds core constraints.
* * <p/>
* <p>Thus, it adds vehicle-capacity, time-window and skills constraints and their * <p>Thus, it adds vehicle-capacity, time-window and skills constraints and their
* required stateUpdater. * required stateUpdater.
*
*/ */
public void addCoreConstraints() { public void addCoreConstraints() {
addCoreConstraints = true; addCoreConstraints = true;
@ -115,7 +113,7 @@ public class VehicleRoutingAlgorithmBuilder {
* By default, marginal transportation costs are calculated. Thus when inserting * By default, marginal transportation costs are calculated. Thus when inserting
* act_k between act_i and act_j, marginal (additional) transportation costs * act_k between act_i and act_j, marginal (additional) transportation costs
* are basically c(act_i,act_k)+c(act_k,act_j)-c(act_i,act_j). * are basically c(act_i,act_k)+c(act_k,act_j)-c(act_i,act_j).
* * <p/>
* <p>Do not use this method, if you plan to control the insertion heuristic * <p>Do not use this method, if you plan to control the insertion heuristic
* entirely via hard- and soft-constraints. * entirely via hard- and soft-constraints.
*/ */
@ -147,7 +145,7 @@ public class VehicleRoutingAlgorithmBuilder {
/** /**
* Builds and returns the algorithm. * Builds and returns the algorithm.
* * <p/>
* <p>If algorithmConfigFile is set, it reads the configuration. * <p>If algorithmConfigFile is set, it reads the configuration.
* *
* @return the algorithm * @return the algorithm

View file

@ -35,7 +35,7 @@ public class AcceptNewRemoveFirst implements SolutionAcceptor{
/** /**
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory. * Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
* Consequently, the worst solution is removed from solutions, and the new solution added. * Consequently, the worst solution is removed from solutions, and the new solution added.
* * <p/>
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions. * <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
*/ */
@Override @Override
@ -53,6 +53,4 @@ public class AcceptNewRemoveFirst implements SolutionAcceptor{
} }
} }

View file

@ -57,11 +57,10 @@ public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, Iterati
this.alpha = alpha; this.alpha = alpha;
this.nOfRandomWalks = nOfWarmupIterations; this.nOfRandomWalks = nOfWarmupIterations;
this.solutionMemory = solutionMemory; this.solutionMemory = solutionMemory;
logger.info("initialise " + this); logger.info("initialise {}", this);
} }
@Override @Override
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) { public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
boolean solutionAccepted = false; boolean solutionAccepted = false;
@ -79,8 +78,7 @@ public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, Iterati
solutions.remove(worst); solutions.remove(worst);
solutions.add(newSolution); solutions.add(newSolution);
solutionAccepted = true; solutionAccepted = true;
} } else if (newSolution.getRoutes().size() == worst.getRoutes().size() && newSolution.getCost() < worst.getCost() + threshold) {
else if(newSolution.getRoutes().size() == worst.getRoutes().size() && newSolution.getCost() < worst.getCost() + threshold){
solutions.remove(worst); solutions.remove(worst);
solutions.add(newSolution); solutions.add(newSolution);
solutionAccepted = true; solutionAccepted = true;
@ -96,7 +94,7 @@ public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, Iterati
private double getThreshold(int iteration) { private double getThreshold(int iteration) {
double scheduleVariable = (double) iteration / (double) nOfTotalIterations; double scheduleVariable = (double) iteration / (double) nOfTotalIterations;
// logger.debug("iter="+iteration+" totalIter="+nOfTotalIterations+" scheduling="+scheduleVariable); // logger.debug("iter={} totalIter={} scheduling={}", iteration, nOfTotalIterations, scheduleVariable);
double currentThreshold = initialThreshold * Math.exp(-Math.log(2) * scheduleVariable / alpha); double currentThreshold = initialThreshold * Math.exp(-Math.log(2) * scheduleVariable / alpha);
return currentThreshold; return currentThreshold;
} }
@ -126,7 +124,7 @@ public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, Iterati
@Override @Override
public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
double result = Solutions.bestOf(solutions).getCost(); double result = Solutions.bestOf(solutions).getCost();
// logger.info("result="+result); // logger.info("result={}", result);
results[iteration - 1] = result; results[iteration - 1] = result;
} }
@ -138,8 +136,8 @@ public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, Iterati
initialThreshold = standardDeviation / 2; initialThreshold = standardDeviation / 2;
logger.info("warmup done"); logger.info("warmup done");
logger.info("total time: " + ((System.currentTimeMillis()-now)/1000.0) + "s"); logger.info("total time: {}s", ((System.currentTimeMillis() - now) / 1000.0));
logger.info("initial threshold: " + initialThreshold); logger.info("initial threshold: {}", initialThreshold);
logger.info("---------------------------------------------------------------------"); logger.info("---------------------------------------------------------------------");
} }

View file

@ -23,7 +23,7 @@ import java.util.Collection;
/** /**
* Acceptor that accepts solutions to be memorized only better solutions. * Acceptor that accepts solutions to be memorized only better solutions.
* * <p/>
* <p>If there is enough memory, every solution will be accepted. If there is no memory anymore and the solution * <p>If there is enough memory, every solution will be accepted. If there is no memory anymore and the solution
* to be evaluated is better than the worst, the worst will be replaced by the new solution.</p> * to be evaluated is better than the worst, the worst will be replaced by the new solution.</p>
*/ */
@ -38,7 +38,7 @@ public class GreedyAcceptance implements SolutionAcceptor{
/** /**
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory. * Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
* Consequently, the worst solution is removed from solutions, and the new solution added. * Consequently, the worst solution is removed from solutions, and the new solution added.
* * <p/>
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions. * <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
*/ */
@Override @Override
@ -68,6 +68,4 @@ public class GreedyAcceptance implements SolutionAcceptor{
} }
} }

View file

@ -33,7 +33,7 @@ public class GreedyAcceptance_minVehFirst implements SolutionAcceptor{
/** /**
* Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory. * Accepts every solution if solution memory allows. If memory occupied, than accepts new solution only if better than the worst in memory.
* Consequently, the worst solution is removed from solutions, and the new solution added. * Consequently, the worst solution is removed from solutions, and the new solution added.
* * <p/>
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions. * <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
*/ */
@Override @Override
@ -52,8 +52,7 @@ public class GreedyAcceptance_minVehFirst implements SolutionAcceptor{
solutions.remove(worstSolution); solutions.remove(worstSolution);
solutions.add(newSolution); solutions.add(newSolution);
solutionAccepted = true; solutionAccepted = true;
} } else if (newSolution.getRoutes().size() == worstSolution.getRoutes().size() && newSolution.getCost() < worstSolution.getCost()) {
else if(newSolution.getRoutes().size() == worstSolution.getRoutes().size() && newSolution.getCost() < worstSolution.getCost()){
solutions.remove(worstSolution); solutions.remove(worstSolution);
solutions.add(newSolution); solutions.add(newSolution);
solutionAccepted = true; solutionAccepted = true;
@ -68,6 +67,4 @@ public class GreedyAcceptance_minVehFirst implements SolutionAcceptor{
} }
} }

View file

@ -29,21 +29,21 @@ import java.util.Collection;
/** /**
* ThresholdAcceptance-Function defined by Schrimpf et al. (2000). * ThresholdAcceptance-Function defined by Schrimpf et al. (2000).
* * <p/>
* <p>The <b>idea</b> can be described as follows: Most problems do not only have one unique minimum (maximum) but * <p>The <b>idea</b> can be described as follows: Most problems do not only have one unique minimum (maximum) but
* a number of local minima (maxima). To avoid to get stuck in a local minimum at the beginning of a search * a number of local minima (maxima). To avoid to get stuck in a local minimum at the beginning of a search
* this threshold-acceptance function accepts also worse solution at the beginning (in contrary to a greedy * this threshold-acceptance function accepts also worse solution at the beginning (in contrary to a greedy
* approach which only accepts better solutions), and converges to a greedy approach at the end. <br> * approach which only accepts better solutions), and converges to a greedy approach at the end. <br>
* The difficulty is to define (i) an appropriate initial threshold and (ii) a corresponding function describing * The difficulty is to define (i) an appropriate initial threshold and (ii) a corresponding function describing
* how the threshold converges to zero, i.e. the greedy threshold. * how the threshold converges to zero, i.e. the greedy threshold.
* * <p/>
* <p>ad i) The initial threshold is determined by a random walk through the search space. * <p>ad i) The initial threshold is determined by a random walk through the search space.
* The random walk currently runs with the following algorithm: src/main/resources/randomWalk.xml. It runs * The random walk currently runs with the following algorithm: src/main/resources/randomWalk.xml. It runs
* as long as it is specified in nuOfWarmupIterations. In the first iteration or walk respectively the algorithm generates a solution. * as long as it is specified in nuOfWarmupIterations. In the first iteration or walk respectively the algorithm generates a solution.
* This solution in turn is the basis of the next walk yielding to another solution value ... and so on. * This solution in turn is the basis of the next walk yielding to another solution value ... and so on.
* Each solution value is memorized since the initial threshold is essentially a function of the standard deviation of these solution values. * Each solution value is memorized since the initial threshold is essentially a function of the standard deviation of these solution values.
* To be more precise: initial threshold = stddev(solution values) / 2. * To be more precise: initial threshold = stddev(solution values) / 2.
* * <p/>
* <p>ad ii) The threshold of iteration i is determined as follows: * <p>ad ii) The threshold of iteration i is determined as follows:
* threshold(i) = initialThreshold * Math.exp(-Math.log(2) * (i / nuOfTotalIterations) / alpha) * threshold(i) = initialThreshold * Math.exp(-Math.log(2) * (i / nuOfTotalIterations) / alpha)
* To get a better understanding of the threshold-function go to Wolfram Alpha and plot the following line * To get a better understanding of the threshold-function go to Wolfram Alpha and plot the following line
@ -55,15 +55,13 @@ import java.util.Collection;
* alpha = 0.1<br> * alpha = 0.1<br>
* x corresponds to i iterations and<br> * x corresponds to i iterations and<br>
* y to the threshold(i) * y to the threshold(i)
* * <p/>
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck (2000). * <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck (2000).
* Record breaking optimization results using the ruin and recreate principle. * Record breaking optimization results using the ruin and recreate principle.
* Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413. * Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.
* URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136 * URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136
* *
*
* @author schroeder * @author schroeder
*
*/ */
public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsListener, AlgorithmStartsListener { public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsListener, AlgorithmStartsListener {
@ -83,7 +81,7 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
public SchrimpfAcceptance(int solutionMemory, double alpha) { public SchrimpfAcceptance(int solutionMemory, double alpha) {
this.alpha = alpha; this.alpha = alpha;
this.solutionMemory = solutionMemory; this.solutionMemory = solutionMemory;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@Override @Override
@ -102,8 +100,7 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList
if (worst == null) { if (worst == null) {
solutions.add(newSolution); solutions.add(newSolution);
solutionAccepted = true; solutionAccepted = true;
} } else if (newSolution.getCost() < worst.getCost() + threshold) {
else if(newSolution.getCost() < worst.getCost() + threshold){
solutions.remove(worst); solutions.remove(worst);
solutions.add(newSolution); solutions.add(newSolution);
solutionAccepted = true; solutionAccepted = true;

View file

@ -67,7 +67,7 @@ public class SchrimpfInitialThresholdGenerator implements AlgorithmStartsListene
@Override @Override
public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
double result = Solutions.bestOf(solutions).getCost(); double result = Solutions.bestOf(solutions).getCost();
// logger.info("result="+result); // logger.info("result={}", result);
results[iteration - 1] = result; results[iteration - 1] = result;
} }
@ -80,8 +80,8 @@ public class SchrimpfInitialThresholdGenerator implements AlgorithmStartsListene
schrimpfAcceptance.setInitialThreshold(initialThreshold); schrimpfAcceptance.setInitialThreshold(initialThreshold);
logger.info("took " + ((System.currentTimeMillis()-now)/1000.0) + " seconds"); logger.info("took {} seconds", ((System.currentTimeMillis() - now) / 1000.0));
logger.debug("initial threshold: " + initialThreshold); logger.debug("initial threshold: {}", initialThreshold);
logger.info("---------------------------------------------------------------------"); logger.info("---------------------------------------------------------------------");
} }

View file

@ -1,4 +1,3 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder * Copyright (C) 2014 Stefan Schroeder
* *
@ -26,15 +25,13 @@ import java.util.Collection;
/** /**
* Acceptor that decides whether the newSolution is accepted or not. * Acceptor that decides whether the newSolution is accepted or not.
* *
*
* @author stefan * @author stefan
*
*/ */
public interface SolutionAcceptor { public interface SolutionAcceptor {
/** /**
* Accepts solution or not, and returns true if a new solution has been accepted. * Accepts solution or not, and returns true if a new solution has been accepted.
* * <p/>
* <p>If the solution is accepted, it is added to solutions, i.e. the solutions-collections is modified. * <p>If the solution is accepted, it is added to solutions, i.e. the solutions-collections is modified.
* *
* @param solutions collection of existing solutions * @param solutions collection of existing solutions

View file

@ -0,0 +1,61 @@
package jsprit.core.algorithm.box;
import jsprit.core.algorithm.listener.IterationStartsListener;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.constraint.SoftActivityConstraint;
import jsprit.core.problem.misc.JobInsertionContext;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.util.RandomNumberGeneration;
import java.util.Collection;
import java.util.Random;
/**
* Created by schroeder on 16/01/15.
*/
class ConcurrentInsertionNoiseMaker implements SoftActivityConstraint, IterationStartsListener {
private final double noiseProbability;
private boolean makeNoise = false;
private double noiseLevel = 0.1;
private Random random = RandomNumberGeneration.newInstance();
private Random[] randomArray;
private double maxCosts;
ConcurrentInsertionNoiseMaker(VehicleRoutingProblem vrp, double maxCosts, double noiseLevel, double noiseProbability) {
this.noiseLevel = noiseLevel;
this.noiseProbability = noiseProbability;
this.maxCosts = maxCosts;
randomArray = new Random[vrp.getNuActivities() + 2];
for (int i = 0; i < randomArray.length; i++) {
Random r = new Random();
r.setSeed(random.nextLong());
randomArray[i] = r;
}
}
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (random.nextDouble() < noiseProbability) {
makeNoise = true;
} else makeNoise = false;
}
@Override
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
if (makeNoise) {
return noiseLevel * maxCosts * randomArray[newAct.getIndex()].nextDouble();
}
return 0;
}
public void setRandom(Random random) {
this.random = random;
}
}

View file

@ -26,25 +26,23 @@ import jsprit.core.util.Resource;
import java.net.URL; import java.net.URL;
/** /**
* Factory that creates the {@link VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters: * Factory that creates the {@link VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters:
* * <p/>
* <p> * <p/>
* R&R_random (prob=0.5, F=0.5); * R&R_random (prob=0.5, F=0.5);
* R&R_radial (prob=0.5, F=0.3); * R&R_radial (prob=0.5, F=0.3);
* threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100); * threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100);
* nuOfIterations=2000 * nuOfIterations=2000
* * <p/>
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck. * <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck.
* Record breaking optimization results using the ruin and recreate principle. * Record breaking optimization results using the ruin and recreate principle.
* Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413. * Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.
* URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136 * URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136
* * <p/>
* <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml. * <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class GreedySchrimpfFactory { public class GreedySchrimpfFactory {
@ -62,5 +60,4 @@ public class GreedySchrimpfFactory {
} }
} }

View file

@ -1,20 +1,14 @@
package jsprit.core.algorithm.box; package jsprit.core.algorithm.box;
import jsprit.core.algorithm.listener.IterationStartsListener; import jsprit.core.algorithm.listener.IterationStartsListener;
import jsprit.core.problem.Location;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.constraint.SoftActivityConstraint; import jsprit.core.problem.constraint.SoftActivityConstraint;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.job.Shipment;
import jsprit.core.problem.misc.JobInsertionContext; import jsprit.core.problem.misc.JobInsertionContext;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.util.RandomNumberGeneration; import jsprit.core.util.RandomNumberGeneration;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Random; import java.util.Random;
/** /**
@ -26,56 +20,31 @@ class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsList
private boolean makeNoise = false; private boolean makeNoise = false;
private VehicleRoutingProblem vrp;
double maxCosts = 0.;
private double noiseLevel = 0.1; private double noiseLevel = 0.1;
private Random random = RandomNumberGeneration.getRandom(); private Random random = RandomNumberGeneration.newInstance();
public InsertionNoiseMaker(VehicleRoutingProblem vrp, double noiseLevel, double noiseProbability) { // private Random[] randomArray;
this.vrp = vrp;
private double maxCosts;
InsertionNoiseMaker(VehicleRoutingProblem vrp, double maxCosts, double noiseLevel, double noiseProbability) {
this.noiseLevel = noiseLevel; this.noiseLevel = noiseLevel;
this.noiseProbability = noiseProbability; this.noiseProbability = noiseProbability;
determineMaxCosts(vrp); this.maxCosts = maxCosts;
} // randomArray = new Random[vrp.getNuActivities() + 2];
// for (int i = 0; i < randomArray.length; i++) {
//@ToDo refactor determining max costs to allow skipping this // Random r = new Random();
private void determineMaxCosts(VehicleRoutingProblem vrp) { // r.setSeed(random.nextLong());
double max = 0.; // randomArray[i] = r;
for(Job i : vrp.getJobs().values()){ // }
List<Location> fromLocations = getLocations(i);
for(Job j : vrp.getJobs().values()){
List<Location> toLocations = getLocations(j);
for(Location iLoc : fromLocations){
for(Location jLoc : toLocations) {
max = Math.max(max, vrp.getTransportCosts().getTransportCost(iLoc, jLoc, 0, null, vrp.getVehicles().iterator().next()));
}
}
}
}
maxCosts = max;
}
private List<Location> getLocations(Job j) {
List<Location> locs = new ArrayList<Location>();
if(j instanceof Service) {
locs.add(((Service) j).getLocation());
}
else if(j instanceof Shipment){
locs.add(((Shipment) j).getPickupLocation());
locs.add(((Shipment) j).getDeliveryLocation());
}
return locs;
} }
@Override @Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
if (random.nextDouble() < noiseProbability) { if (random.nextDouble() < noiseProbability) {
makeNoise = true; makeNoise = true;
} } else makeNoise = false;
else makeNoise = false;
} }
@Override @Override
@ -86,7 +55,6 @@ class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsList
return 0; return 0;
} }
public void setRandom(Random random) { public void setRandom(Random random) {
this.random = random; this.random = random;
} }

View file

@ -17,6 +17,7 @@ import jsprit.core.problem.constraint.ConstraintManager;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.BreakActivity;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.vehicle.FiniteFleetManagerFactory; import jsprit.core.problem.vehicle.FiniteFleetManagerFactory;
import jsprit.core.problem.vehicle.InfiniteFleetManagerFactory; import jsprit.core.problem.vehicle.InfiniteFleetManagerFactory;
@ -34,6 +35,8 @@ import java.util.concurrent.Executors;
public class Jsprit { public class Jsprit {
private final ActivityInsertionCostsCalculator activityInsertion;
public enum Construction { public enum Construction {
BEST_INSERTION("best_insertion"), REGRET_INSERTION("regret_insertion"); BEST_INSERTION("best_insertion"), REGRET_INSERTION("regret_insertion");
@ -93,6 +96,8 @@ public class Jsprit {
INSERTION_NOISE_PROB("insertion.noise_prob"), INSERTION_NOISE_PROB("insertion.noise_prob"),
RUIN_WORST_NOISE_LEVEL("worst.noise_level"), RUIN_WORST_NOISE_LEVEL("worst.noise_level"),
RUIN_WORST_NOISE_PROB("worst.noise_prob"), RUIN_WORST_NOISE_PROB("worst.noise_prob"),
FAST_REGRET("regret.fast"),
MAX_TRANSPORT_COSTS("max_transport_costs"),
CONSTRUCTION("construction"); CONSTRUCTION("construction");
String paraName; String paraName;
@ -131,6 +136,8 @@ public class Jsprit {
private Random random = RandomNumberGeneration.newInstance(); private Random random = RandomNumberGeneration.newInstance();
private ActivityInsertionCostsCalculator activityInsertionCalculator;
public static Builder newInstance(VehicleRoutingProblem vrp) { public static Builder newInstance(VehicleRoutingProblem vrp) {
return new Builder(vrp); return new Builder(vrp);
} }
@ -177,6 +184,7 @@ public class Jsprit {
defaults.put(Parameter.RUIN_WORST_NOISE_LEVEL.toString(), String.valueOf(0.15)); defaults.put(Parameter.RUIN_WORST_NOISE_LEVEL.toString(), String.valueOf(0.15));
defaults.put(Parameter.RUIN_WORST_NOISE_PROB.toString(), String.valueOf(0.2)); defaults.put(Parameter.RUIN_WORST_NOISE_PROB.toString(), String.valueOf(0.2));
defaults.put(Parameter.VEHICLE_SWITCH.toString(), String.valueOf(true)); defaults.put(Parameter.VEHICLE_SWITCH.toString(), String.valueOf(true));
defaults.put(Parameter.FAST_REGRET, String.valueOf(false));
defaults.put(Parameter.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString()); defaults.put(Parameter.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString());
return defaults; return defaults;
} }
@ -224,6 +232,11 @@ public class Jsprit {
return this; return this;
} }
public Builder setActivityInsertionCalculator(ActivityInsertionCostsCalculator activityInsertionCalculator) {
this.activityInsertionCalculator = activityInsertionCalculator;
return this;
}
public VehicleRoutingAlgorithm buildAlgorithm() { public VehicleRoutingAlgorithm buildAlgorithm() {
return new Jsprit(this).create(vrp); return new Jsprit(this).create(vrp);
} }
@ -245,13 +258,15 @@ public class Jsprit {
} }
public RuinShareFactoryImpl(int minShare, int maxShare) { public RuinShareFactoryImpl(int minShare, int maxShare) {
if(maxShare < minShare) throw new IllegalArgumentException("maxShare must be equal or greater than minShare"); if (maxShare < minShare)
throw new IllegalArgumentException("maxShare must be equal or greater than minShare");
this.minShare = minShare; this.minShare = minShare;
this.maxShare = maxShare; this.maxShare = maxShare;
} }
public RuinShareFactoryImpl(int minShare, int maxShare, Random random) { public RuinShareFactoryImpl(int minShare, int maxShare, Random random) {
if(maxShare < minShare) throw new IllegalArgumentException("maxShare must be equal or greater than minShare"); if (maxShare < minShare)
throw new IllegalArgumentException("maxShare must be equal or greater than minShare");
this.minShare = minShare; this.minShare = minShare;
this.maxShare = maxShare; this.maxShare = maxShare;
this.random = random; this.random = random;
@ -291,14 +306,18 @@ public class Jsprit {
this.properties = builder.properties; this.properties = builder.properties;
this.objectiveFunction = builder.objectiveFunction; this.objectiveFunction = builder.objectiveFunction;
this.random = builder.random; this.random = builder.random;
this.activityInsertion = builder.activityInsertionCalculator;
} }
private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) { private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) {
VehicleFleetManager fm; VehicleFleetManager fm;
if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) { if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) {
fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} else {
FiniteFleetManagerFactory finiteFleetManagerFactory = new FiniteFleetManagerFactory(vrp.getVehicles());
finiteFleetManagerFactory.setRandom(random);
fm = finiteFleetManagerFactory.createFleetManager();
} }
else fm = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
if (stateManager == null) { if (stateManager == null) {
stateManager = new StateManager(vrp); stateManager = new StateManager(vrp);
@ -307,15 +326,43 @@ public class Jsprit {
constraintManager = new ConstraintManager(vrp, stateManager); constraintManager = new ConstraintManager(vrp, stateManager);
} }
if (noThreads == null) {
noThreads = toInteger(getProperty(Parameter.THREADS.toString()));
}
if (noThreads > 1) {
if (es == null) {
setupExecutorInternally = true;
es = Executors.newFixedThreadPool(noThreads);
}
}
double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString())); double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString()));
double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString())); double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString()));
final InsertionNoiseMaker noiseMaker = new InsertionNoiseMaker(vrp, noiseLevel, noiseProbability);
noiseMaker.setRandom(random);
constraintManager.addConstraint(noiseMaker);
JobNeighborhoods jobNeighborhoods = new JobNeighborhoodsFactory().createNeighborhoods(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts()), (int) (vrp.getJobs().values().size() * 0.5)); JobNeighborhoods jobNeighborhoods = new JobNeighborhoodsFactory().createNeighborhoods(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts()), (int) (vrp.getJobs().values().size() * 0.5));
jobNeighborhoods.initialise(); jobNeighborhoods.initialise();
final double maxCosts;
if(properties.containsKey(Parameter.MAX_TRANSPORT_COSTS.toString())){
maxCosts = Double.parseDouble(getProperty(Parameter.MAX_TRANSPORT_COSTS.toString()));
}
else{
maxCosts = jobNeighborhoods.getMaxDistance();
}
IterationStartsListener noiseConfigurator;
if (noThreads > 1) {
ConcurrentInsertionNoiseMaker noiseMaker = new ConcurrentInsertionNoiseMaker(vrp, maxCosts, noiseLevel, noiseProbability);
noiseMaker.setRandom(random);
constraintManager.addConstraint(noiseMaker);
noiseConfigurator = noiseMaker;
} else {
InsertionNoiseMaker noiseMaker = new InsertionNoiseMaker(vrp, maxCosts, noiseLevel, noiseProbability);
noiseMaker.setRandom(random);
constraintManager.addConstraint(noiseMaker);
noiseConfigurator = noiseMaker;
}
RuinRadial radial = new RuinRadial(vrp, vrp.getJobs().size(), jobNeighborhoods); RuinRadial radial = new RuinRadial(vrp, vrp.getJobs().size(), jobNeighborhoods);
radial.setRandom(random); radial.setRandom(random);
radial.setRuinShareFactory(new RuinShareFactoryImpl( radial.setRuinShareFactory(new RuinShareFactoryImpl(
@ -355,9 +402,8 @@ public class Jsprit {
public double makeNoise() { public double makeNoise() {
if (random.nextDouble() < toDouble(getProperty(Parameter.RUIN_WORST_NOISE_PROB.toString()))) { if (random.nextDouble() < toDouble(getProperty(Parameter.RUIN_WORST_NOISE_PROB.toString()))) {
return toDouble(getProperty(Parameter.RUIN_WORST_NOISE_LEVEL.toString())) return toDouble(getProperty(Parameter.RUIN_WORST_NOISE_LEVEL.toString()))
* noiseMaker.maxCosts * random.nextDouble(); * maxCosts * random.nextDouble();
} } else return 0.;
else return 0.;
} }
}); });
} }
@ -372,22 +418,43 @@ public class Jsprit {
); );
AbstractInsertionStrategy regret; AbstractInsertionStrategy regret;
final RegretInsertion.DefaultScorer scorer; final DefaultScorer scorer;
if(noThreads == null){
noThreads = toInteger(getProperty(Parameter.THREADS.toString())); boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString()));
}
if(noThreads > 1){
if(es == null){
setupExecutorInternally = true;
es = Executors.newFixedThreadPool(noThreads);
}
}
if (es != null) { if (es != null) {
if(fastRegret){
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads)
.setFastRegret(true)
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer);
regret = regretInsertion;
}
else {
RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager) RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setConcurrentMode(es, noThreads) .setConcurrentMode(es, noThreads)
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build();
scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer);
regret = regretInsertion;
}
} else {
if(fastRegret) {
RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setFastRegret(true)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build(); .build();
scorer = getRegretScorer(vrp); scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer); regretInsertion.setScoringFunction(scorer);
@ -398,11 +465,13 @@ public class Jsprit {
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build(); .build();
scorer = getRegretScorer(vrp); scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer); regretInsertion.setScoringFunction(scorer);
regret = regretInsertion; regret = regretInsertion;
} }
}
regret.setRandom(random); regret.setRandom(random);
AbstractInsertionStrategy best; AbstractInsertionStrategy best;
@ -411,15 +480,16 @@ public class Jsprit {
.setInsertionStrategy(InsertionBuilder.Strategy.BEST) .setInsertionStrategy(InsertionBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setActivityInsertionCostCalculator(activityInsertion)
.build(); .build();
best = bestInsertion; best = bestInsertion;
} } else {
else{
BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager) BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
.setInsertionStrategy(InsertionBuilder.Strategy.BEST) .setInsertionStrategy(InsertionBuilder.Strategy.BEST)
.considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString())))
.setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString())))
.setConcurrentMode(es, noThreads) .setConcurrentMode(es, noThreads)
.setActivityInsertionCostCalculator(activityInsertion)
.build(); .build();
best = bestInsertion; best = bestInsertion;
} }
@ -436,7 +506,7 @@ public class Jsprit {
} }
}; };
SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, noiseMaker.maxCosts); SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, maxCosts);
SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction); SearchStrategy radial_regret = new SearchStrategy(Strategy.RADIAL_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
radial_regret.addModule(new RuinAndRecreateModule(Strategy.RADIAL_REGRET.toString(), regret, radial)); radial_regret.addModule(new RuinAndRecreateModule(Strategy.RADIAL_REGRET.toString(), regret, radial));
@ -477,28 +547,29 @@ public class Jsprit {
.withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString()))); .withStrategy(clusters_best, toDouble(getProperty(Strategy.CLUSTER_BEST.toString())));
if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) { if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) {
prettyBuilder.constructInitialSolutionWith(best, objectiveFunction); prettyBuilder.constructInitialSolutionWith(best, objectiveFunction);
} } else {
else{
prettyBuilder.constructInitialSolutionWith(regret, objectiveFunction); prettyBuilder.constructInitialSolutionWith(regret, objectiveFunction);
} }
VehicleRoutingAlgorithm vra = prettyBuilder.build(); VehicleRoutingAlgorithm vra = prettyBuilder.build();
vra.addListener(schrimpfThreshold); vra.addListener(schrimpfThreshold);
vra.addListener(noiseMaker); vra.addListener(noiseConfigurator);
vra.addListener(noise); vra.addListener(noise);
vra.addListener(clusters); vra.addListener(clusters);
vra.addListener(new RuinBreaks());
handleExecutorShutdown(vra); handleExecutorShutdown(vra);
vra.setMaxIterations(Integer.valueOf(properties.getProperty(Parameter.ITERATIONS.toString()))); vra.setMaxIterations(Integer.valueOf(properties.getProperty(Parameter.ITERATIONS.toString())));
return vra; return vra;
} }
private RegretInsertion.DefaultScorer getRegretScorer(VehicleRoutingProblem vrp) { private DefaultScorer getRegretScorer(VehicleRoutingProblem vrp) {
RegretInsertion.DefaultScorer scorer; DefaultScorer scorer;
scorer = new RegretInsertion.DefaultScorer(vrp); scorer = new DefaultScorer(vrp);
scorer.setTimeWindowParam(Double.valueOf(properties.getProperty(Parameter.REGRET_TIME_WINDOW_SCORER.toString()))); scorer.setTimeWindowParam(Double.valueOf(properties.getProperty(Parameter.REGRET_TIME_WINDOW_SCORER.toString())));
scorer.setDepotDistanceParam(Double.valueOf(properties.getProperty(Parameter.REGRET_TIME_WINDOW_SCORER.toString()))); scorer.setDepotDistanceParam(Double.valueOf(properties.getProperty(Parameter.REGRET_DISTANCE_SCORER.toString())));
return scorer; return scorer;
} }
@ -549,14 +620,28 @@ public class Jsprit {
@Override @Override
public double getCosts(VehicleRoutingProblemSolution solution) { public double getCosts(VehicleRoutingProblemSolution solution) {
double costs = 0.; double costs = 0.;
for (VehicleRoute route : solution.getRoutes()) { for (VehicleRoute route : solution.getRoutes()) {
costs += route.getVehicle().getType().getVehicleCostParams().fix; costs += route.getVehicle().getType().getVehicleCostParams().fix;
boolean hasBreak = false;
TourActivity prevAct = route.getStart(); TourActivity prevAct = route.getStart();
for (TourActivity act : route.getActivities()) { for (TourActivity act : route.getActivities()) {
if (act instanceof BreakActivity) hasBreak = true;
costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), act.getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle()); costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), act.getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle());
costs += vrp.getActivityCosts().getActivityCost(act, act.getArrTime(), route.getDriver(), route.getVehicle());
prevAct = act; prevAct = act;
} }
costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), route.getEnd().getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle()); costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(), route.getEnd().getLocation(), prevAct.getEndTime(), route.getDriver(), route.getVehicle());
if (route.getVehicle().getBreak() != null) {
if (!hasBreak) {
//break defined and required but not assigned penalty
if (route.getEnd().getArrTime() > route.getVehicle().getBreak().getTimeWindow().getEnd()) {
costs += maxCosts * 2 + route.getVehicle().getBreak().getServiceDuration() * route.getVehicle().getType().getVehicleCostParams().perServiceTimeUnit;
} else {
costs -= maxCosts * 2;
}
}
}
} }
costs += solution.getUnassignedJobs().size() * maxCosts * 2; costs += solution.getUnassignedJobs().size() * maxCosts * 2;
return costs; return costs;
@ -565,4 +650,5 @@ public class Jsprit {
return solutionCostCalculator; return solutionCostCalculator;
} }
} }

View file

@ -26,25 +26,23 @@ import jsprit.core.util.Resource;
import java.net.URL; import java.net.URL;
/** /**
* Factory that creates the {@link VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters: * Factory that creates the {@link VehicleRoutingAlgorithm} as proposed by Schrimpf et al., 2000 with the following parameters:
* * <p/>
* <p> * <p/>
* R&R_random (prob=0.5, F=0.5); * R&R_random (prob=0.5, F=0.5);
* R&R_radial (prob=0.5, F=0.3); * R&R_radial (prob=0.5, F=0.3);
* threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100); * threshold-accepting with exponentialDecayFunction (alpha=0.1, warmup-iterations=100);
* nuOfIterations=2000 * nuOfIterations=2000
* * <p/>
* <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck. * <p>Gerhard Schrimpf, Johannes Schneider, Hermann Stamm- Wilbrandt, and Gunter Dueck.
* Record breaking optimization results using the ruin and recreate principle. * Record breaking optimization results using the ruin and recreate principle.
* Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413. * Journal of Computational Physics, 159(2):139 171, 2000. ISSN 0021-9991. doi: 10.1006/jcph.1999. 6413.
* URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136 * URL http://www.sciencedirect.com/science/article/ pii/S0021999199964136
* * <p/>
* <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml. * <p>algorithm-xml-config is available at src/main/resources/schrimpf.xml.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class SchrimpfFactory { public class SchrimpfFactory {
@ -62,5 +60,4 @@ public class SchrimpfFactory {
} }
} }

View file

@ -70,17 +70,14 @@ public class AlgorithmConfigXmlReader {
}; };
algorithmConfig.getXMLConfiguration().setEntityResolver(resolver); algorithmConfig.getXMLConfiguration().setEntityResolver(resolver);
algorithmConfig.getXMLConfiguration().setSchemaValidation(true); algorithmConfig.getXMLConfiguration().setSchemaValidation(true);
} } else {
else{
log.warn("cannot find schema-xsd file (algorithm_xml_schema.xsd). try to read xml without xml-file-validation."); log.warn("cannot find schema-xsd file (algorithm_xml_schema.xsd). try to read xml without xml-file-validation.");
} }
} }
try { try {
algorithmConfig.getXMLConfiguration().load(); algorithmConfig.getXMLConfiguration().load();
} catch (ConfigurationException e) { } catch (ConfigurationException e) {
log.error(e); throw new RuntimeException(e);
e.printStackTrace();
System.exit(1);
} }
} }

View file

@ -56,21 +56,20 @@ class InsertionFactory {
String level = config.getString("level"); String level = config.getString("level");
if (level.equals("local")) { if (level.equals("local")) {
iBuilder.setLocalLevel(addDefaultCostCalculators); iBuilder.setLocalLevel(addDefaultCostCalculators);
} } else if (level.equals("route")) {
else if(level.equals("route")){
int forwardLooking = 0; int forwardLooking = 0;
int memory = 1; int memory = 1;
String forward = config.getString("level[@forwardLooking]"); String forward = config.getString("level[@forwardLooking]");
String mem = config.getString("level[@memory]"); String mem = config.getString("level[@memory]");
if (forward != null) forwardLooking = Integer.parseInt(forward); if (forward != null) forwardLooking = Integer.parseInt(forward);
else log.warn("parameter route[@forwardLooking] is missing. by default it is 0 which equals to local level"); else
log.warn("parameter route[@forwardLooking] is missing. by default it is 0 which equals to local level");
if (mem != null) memory = Integer.parseInt(mem); if (mem != null) memory = Integer.parseInt(mem);
else log.warn("parameter route[@memory] is missing. by default it is 1"); else log.warn("parameter route[@memory] is missing. by default it is 1");
iBuilder.setRouteLevel(forwardLooking, memory, addDefaultCostCalculators); iBuilder.setRouteLevel(forwardLooking, memory, addDefaultCostCalculators);
} } else
else throw new IllegalStateException("level " + level + " is not known. currently it only knows \"local\" or \"route\""); throw new IllegalStateException("level " + level + " is not known. currently it only knows \"local\" or \"route\"");
} } else iBuilder.setLocalLevel(addDefaultCostCalculators);
else iBuilder.setLocalLevel(addDefaultCostCalculators);
if (config.containsKey("considerFixedCosts") || config.containsKey("considerFixedCost")) { if (config.containsKey("considerFixedCosts") || config.containsKey("considerFixedCost")) {
if (addDefaultCostCalculators) { if (addDefaultCostCalculators) {
@ -81,14 +80,14 @@ class InsertionFactory {
String weight = config.getString("considerFixedCosts[@weight]"); String weight = config.getString("considerFixedCosts[@weight]");
if (weight == null) weight = config.getString("considerFixedCost[@weight]"); if (weight == null) weight = config.getString("considerFixedCost[@weight]");
if (weight != null) fixedCostWeight = Double.parseDouble(weight); if (weight != null) fixedCostWeight = Double.parseDouble(weight);
else throw new IllegalStateException("fixedCostsParameter 'weight' must be set, e.g. <considerFixedCosts weight=1.0>true</considerFixedCosts>.\n" + else
throw new IllegalStateException("fixedCostsParameter 'weight' must be set, e.g. <considerFixedCosts weight=1.0>true</considerFixedCosts>.\n" +
"this has to be changed in algorithm-config-xml-file."); "this has to be changed in algorithm-config-xml-file.");
iBuilder.considerFixedCosts(fixedCostWeight); iBuilder.considerFixedCosts(fixedCostWeight);
} } else if (val.equals("false")) {
else if(val.equals("false")){
} } else
else throw new IllegalStateException("considerFixedCosts must either be true or false, i.e. <considerFixedCosts weight=1.0>true</considerFixedCosts> or \n<considerFixedCosts weight=1.0>false</considerFixedCosts>. " + throw new IllegalStateException("considerFixedCosts must either be true or false, i.e. <considerFixedCosts weight=1.0>true</considerFixedCosts> or \n<considerFixedCosts weight=1.0>false</considerFixedCosts>. " +
"if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file"); "if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file");
} }
} }
@ -104,10 +103,14 @@ class InsertionFactory {
if (insertionName.equals("regretInsertion")) { if (insertionName.equals("regretInsertion")) {
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET); iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
String fastRegret = config.getString("fastRegret");
if (fastRegret != null) {
iBuilder.setFastRegret(Boolean.parseBoolean(fastRegret));
}
} }
return iBuilder.build(); return iBuilder.build();
} } else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
} }

View file

@ -42,6 +42,7 @@ import jsprit.core.algorithm.termination.VariationCoefficientTermination;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.VehicleRoutingProblem.FleetSize; import jsprit.core.problem.VehicleRoutingProblem.FleetSize;
import jsprit.core.problem.constraint.ConstraintManager; import jsprit.core.problem.constraint.ConstraintManager;
import jsprit.core.problem.constraint.SwitchNotFeasible;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
@ -151,7 +152,6 @@ public class VehicleRoutingAlgorithms {
} }
@Override @Override
public Class<SolutionSelector> getType() { public Class<SolutionSelector> getType() {
return SolutionSelector.class; return SolutionSelector.class;
@ -195,7 +195,6 @@ public class VehicleRoutingAlgorithms {
} }
@Override @Override
public Class<SearchStrategyModule> getType() { public Class<SearchStrategyModule> getType() {
return SearchStrategyModule.class; return SearchStrategyModule.class;
@ -239,7 +238,6 @@ public class VehicleRoutingAlgorithms {
} }
@Override @Override
public Class<RuinStrategy> getType() { public Class<RuinStrategy> getType() {
return RuinStrategy.class; return RuinStrategy.class;
@ -283,7 +281,6 @@ public class VehicleRoutingAlgorithms {
} }
@Override @Override
public Class<InsertionStrategy> getType() { public Class<InsertionStrategy> getType() {
return InsertionStrategy.class; return InsertionStrategy.class;
@ -325,6 +322,7 @@ public class VehicleRoutingAlgorithms {
result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode());
return result; return result;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
@ -351,7 +349,8 @@ public class VehicleRoutingAlgorithms {
private static Logger log = LogManager.getLogger(VehicleRoutingAlgorithms.class.getName()); private static Logger log = LogManager.getLogger(VehicleRoutingAlgorithms.class.getName());
private VehicleRoutingAlgorithms(){} private VehicleRoutingAlgorithms() {
}
/** /**
* Creates a {@link jsprit.core.algorithm.VehicleRoutingAlgorithm} from a AlgorithConfig based on the input vrp. * Creates a {@link jsprit.core.algorithm.VehicleRoutingAlgorithm} from a AlgorithConfig based on the input vrp.
@ -363,6 +362,7 @@ public class VehicleRoutingAlgorithms {
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, final AlgorithmConfig algorithmConfig) { public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, final AlgorithmConfig algorithmConfig) {
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null); return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null);
} }
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final AlgorithmConfig algorithmConfig) { public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final AlgorithmConfig algorithmConfig) {
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), nThreads, null); return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), nThreads, null);
} }
@ -380,6 +380,7 @@ public class VehicleRoutingAlgorithms {
xmlReader.read(configURL); xmlReader.read(configURL);
return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null); return createAlgo(vrp, algorithmConfig.getXMLConfiguration(), 0, null);
} }
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final URL configURL) { public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, int nThreads, final URL configURL) {
AlgorithmConfig algorithmConfig = new AlgorithmConfig(); AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig); AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
@ -459,8 +460,7 @@ public class VehicleRoutingAlgorithms {
final StateManager stateManager; final StateManager stateManager;
if (stateMan != null) { if (stateMan != null) {
stateManager = stateMan; stateManager = stateMan;
} } else {
else{
stateManager = new StateManager(vrp); stateManager = new StateManager(vrp);
} }
stateManager.updateLoadStates(); stateManager.updateLoadStates();
@ -479,6 +479,7 @@ public class VehicleRoutingAlgorithms {
constraintManager.addTimeWindowConstraint(); constraintManager.addTimeWindowConstraint();
constraintManager.addLoadConstraint(); constraintManager.addLoadConstraint();
constraintManager.addSkillsConstraint(); constraintManager.addSkillsConstraint();
constraintManager.addConstraint(new SwitchNotFeasible(stateManager));
return readAndCreateAlgorithm(vrp, config, nuOfThreads, null, stateManager, constraintManager, true); return readAndCreateAlgorithm(vrp, config, nuOfThreads, null, stateManager, constraintManager, true);
} }
@ -518,7 +519,6 @@ public class VehicleRoutingAlgorithms {
@Override @Override
public void uncaughtException(Thread arg0, Throwable arg1) { public void uncaughtException(Thread arg0, Throwable arg1) {
System.err.println(arg1.toString()); System.err.println(arg1.toString());
System.exit(0);
} }
}); });
Runtime.getRuntime().addShutdownHook(new Thread() { Runtime.getRuntime().addShutdownHook(new Thread() {
@ -529,8 +529,7 @@ public class VehicleRoutingAlgorithms {
} }
} }
}); });
} } else executorService = null;
else executorService = null;
//create fleetmanager //create fleetmanager
@ -540,8 +539,7 @@ public class VehicleRoutingAlgorithms {
final boolean switchAllowed; final boolean switchAllowed;
if (switchString != null) { if (switchString != null) {
switchAllowed = Boolean.parseBoolean(switchString); switchAllowed = Boolean.parseBoolean(switchString);
} } else switchAllowed = true;
else switchAllowed = true;
ActivityTimeTracker.ActivityPolicy activityPolicy; ActivityTimeTracker.ActivityPolicy activityPolicy;
if (stateManager.timeWindowUpdateIsActivated()) { if (stateManager.timeWindowUpdateIsActivated()) {
UpdateVehicleDependentPracticalTimeWindows timeWindowUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts()); UpdateVehicleDependentPracticalTimeWindows timeWindowUpdater = new UpdateVehicleDependentPracticalTimeWindows(stateManager, vrp.getTransportCosts());
@ -564,8 +562,7 @@ public class VehicleRoutingAlgorithms {
}); });
stateManager.addStateUpdater(timeWindowUpdater); stateManager.addStateUpdater(timeWindowUpdater);
activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS; activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_TIME_WINDOW_OPENS;
} } else {
else{
activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_ARRIVED; activityPolicy = ActivityTimeTracker.ActivityPolicy.AS_SOON_AS_ARRIVED;
} }
stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), activityPolicy)); stateManager.addStateUpdater(new UpdateActivityTimes(vrp.getTransportCosts(), activityPolicy));
@ -578,7 +575,8 @@ public class VehicleRoutingAlgorithms {
PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager); PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager);
//construct initial solution creator //construct initial solution creator
final InsertionStrategy initialInsertionStrategy = createInitialSolution(config, vrp, vehicleFleetManager, stateManager, algorithmListeners, definedClasses, executorService, nuOfThreads, costCalculator, constraintManager, addDefaultCostCalculators); final InsertionStrategy initialInsertionStrategy = createInitialSolution(config, vrp, vehicleFleetManager, stateManager, algorithmListeners, definedClasses, executorService, nuOfThreads, costCalculator, constraintManager, addDefaultCostCalculators);
if(initialInsertionStrategy != null) prettyAlgorithmBuilder.constructInitialSolutionWith(initialInsertionStrategy,costCalculator); if (initialInsertionStrategy != null)
prettyAlgorithmBuilder.constructInitialSolutionWith(initialInsertionStrategy, costCalculator);
//construct algorithm, i.e. search-strategies and its modules //construct algorithm, i.e. search-strategies and its modules
int solutionMemory = config.getInt("strategy.memory"); int solutionMemory = config.getInt("strategy.memory");
@ -605,7 +603,8 @@ public class VehicleRoutingAlgorithms {
//define prematureBreak //define prematureBreak
PrematureAlgorithmTermination prematureAlgorithmTermination = getPrematureTermination(config, algorithmListeners); PrematureAlgorithmTermination prematureAlgorithmTermination = getPrematureTermination(config, algorithmListeners);
if(prematureAlgorithmTermination != null) metaAlgorithm.setPrematureAlgorithmTermination(prematureAlgorithmTermination); if (prematureAlgorithmTermination != null)
metaAlgorithm.setPrematureAlgorithmTermination(prematureAlgorithmTermination);
else { else {
List<HierarchicalConfiguration> terminationCriteria = config.configurationsAt("terminationCriteria.termination"); List<HierarchicalConfiguration> terminationCriteria = config.configurationsAt("terminationCriteria.termination");
for (HierarchicalConfiguration terminationConfig : terminationCriteria) { for (HierarchicalConfiguration terminationConfig : terminationCriteria) {
@ -634,8 +633,7 @@ public class VehicleRoutingAlgorithms {
if (vrp.getFleetSize().equals(FleetSize.INFINITE)) { if (vrp.getFleetSize().equals(FleetSize.INFINITE)) {
return new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); return new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} } else if (vrp.getFleetSize().equals(FleetSize.FINITE)) {
else if(vrp.getFleetSize().equals(FleetSize.FINITE)){
return new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); return new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager();
} }
throw new IllegalStateException("fleet size can only be infinite or finite. " + throw new IllegalStateException("fleet size can only be infinite or finite. " +
@ -716,7 +714,8 @@ public class VehicleRoutingAlgorithms {
throw new IllegalStateException("prematureBreak basedOn " + basedOn + " is not defined"); throw new IllegalStateException("prematureBreak basedOn " + basedOn + " is not defined");
} }
private static String getName(HierarchicalConfiguration strategyConfig) { if(strategyConfig.containsKey("[@name]")){ private static String getName(HierarchicalConfiguration strategyConfig) {
if (strategyConfig.containsKey("[@name]")) {
return strategyConfig.getString("[@name]"); return strategyConfig.getString("[@name]");
} }
return ""; return "";
@ -746,7 +745,8 @@ public class VehicleRoutingAlgorithms {
private static SolutionSelector getSelector(HierarchicalConfiguration strategyConfig, VehicleRoutingProblem vrp, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedSelectors) { private static SolutionSelector getSelector(HierarchicalConfiguration strategyConfig, VehicleRoutingProblem vrp, Set<PrioritizedVRAListener> algorithmListeners, TypedMap definedSelectors) {
String selectorName = strategyConfig.getString("selector[@name]"); String selectorName = strategyConfig.getString("selector[@name]");
if(selectorName == null) throw new IllegalStateException("no solutionSelector defined. define either \"selectRandomly\" or \"selectBest\""); if (selectorName == null)
throw new IllegalStateException("no solutionSelector defined. define either \"selectRandomly\" or \"selectBest\"");
String selectorId = strategyConfig.getString("selector[@id]"); String selectorId = strategyConfig.getString("selector[@id]");
if (selectorId == null) selectorId = "noId"; if (selectorId == null) selectorId = "noId";
ModKey modKey = makeKey(selectorName, selectorId); ModKey modKey = makeKey(selectorName, selectorId);
@ -807,8 +807,7 @@ public class VehicleRoutingAlgorithms {
if (nuWarmupIterations != null) { if (nuWarmupIterations != null) {
SchrimpfInitialThresholdGenerator iniThresholdGenerator = new SchrimpfInitialThresholdGenerator(schrimpf, Integer.parseInt(nuWarmupIterations)); SchrimpfInitialThresholdGenerator iniThresholdGenerator = new SchrimpfInitialThresholdGenerator(schrimpf, Integer.parseInt(nuWarmupIterations));
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, iniThresholdGenerator)); algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, iniThresholdGenerator));
} } else {
else{
double threshold = strategyConfig.getDouble("acceptor.initialThreshold"); double threshold = strategyConfig.getDouble("acceptor.initialThreshold");
schrimpf.setInitialThreshold(threshold); schrimpf.setInitialThreshold(threshold);
} }
@ -823,8 +822,7 @@ public class VehicleRoutingAlgorithms {
algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, schrimpf)); algorithmListeners.add(new PrioritizedVRAListener(Priority.LOW, schrimpf));
typedMap.put(acceptorKey, schrimpf); typedMap.put(acceptorKey, schrimpf);
return schrimpf; return schrimpf;
} } else {
else{
throw new IllegalStateException("solution acceptor " + acceptorName + " is not known"); throw new IllegalStateException("solution acceptor " + acceptorName + " is not known");
} }
} }
@ -852,15 +850,15 @@ public class VehicleRoutingAlgorithms {
ModKey ruinKey = makeKey(ruin_name, ruin_id); ModKey ruinKey = makeKey(ruin_name, ruin_id);
if (ruin_name.equals("randomRuin")) { if (ruin_name.equals("randomRuin")) {
ruin = getRandomRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin); ruin = getRandomRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin);
} } else if (ruin_name.equals("radialRuin")) {
else if(ruin_name.equals("radialRuin")){
JobDistance jobDistance = new AvgServiceAndShipmentDistance(vrp.getTransportCosts()); JobDistance jobDistance = new AvgServiceAndShipmentDistance(vrp.getTransportCosts());
ruin = getRadialRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin, jobDistance); ruin = getRadialRuin(vrp, routeStates, definedClasses, ruinKey, shareToRuin, jobDistance);
} } else
else throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin."); throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin.");
String insertionName = moduleConfig.getString("insertion[@name]"); String insertionName = moduleConfig.getString("insertion[@name]");
if(insertionName == null) throw new IllegalStateException("module.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\""); if (insertionName == null)
throw new IllegalStateException("module.insertion[@name] is missing. set it to \"regretInsertion\" or \"bestInsertion\"");
String insertionId = moduleConfig.getString("insertion[@id]"); String insertionId = moduleConfig.getString("insertion[@id]");
if (insertionId == null) insertionId = "noId"; if (insertionId == null) insertionId = "noId";
ModKey insertionKey = makeKey(insertionName, insertionId); ModKey insertionKey = makeKey(insertionName, insertionId);
@ -911,6 +909,4 @@ public class VehicleRoutingAlgorithms {
} }
} }

View file

@ -22,8 +22,6 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.Collection; import java.util.Collection;
public interface AlgorithmEndsListener extends VehicleRoutingAlgorithmListener { public interface AlgorithmEndsListener extends VehicleRoutingAlgorithmListener {
void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions); void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);

View file

@ -23,8 +23,6 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.Collection; import java.util.Collection;
public interface AlgorithmStartsListener extends VehicleRoutingAlgorithmListener { public interface AlgorithmStartsListener extends VehicleRoutingAlgorithmListener {
void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions); void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions);

View file

@ -22,9 +22,6 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.Collection; import java.util.Collection;
public interface IterationEndsListener extends VehicleRoutingAlgorithmListener { public interface IterationEndsListener extends VehicleRoutingAlgorithmListener {
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions); public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);

View file

@ -22,8 +22,6 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.Collection; import java.util.Collection;
public interface IterationStartsListener extends VehicleRoutingAlgorithmListener { public interface IterationStartsListener extends VehicleRoutingAlgorithmListener {
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions); public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);

View file

@ -23,8 +23,6 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.Collection; import java.util.Collection;
public interface StrategySelectedListener extends VehicleRoutingAlgorithmListener { public interface StrategySelectedListener extends VehicleRoutingAlgorithmListener {
void informSelectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem vehicleRoutingProblem, Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions); void informSelectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem vehicleRoutingProblem, Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions);

View file

@ -24,57 +24,27 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.*; import java.util.*;
public class VehicleRoutingAlgorithmListeners { public class VehicleRoutingAlgorithmListeners {
public static class PrioritizedVRAListener { public static class PrioritizedVRAListener {
Priority priority; Priority priority;
VehicleRoutingAlgorithmListener l; VehicleRoutingAlgorithmListener l;
public PrioritizedVRAListener(Priority priority, VehicleRoutingAlgorithmListener l) { public PrioritizedVRAListener(Priority priority, VehicleRoutingAlgorithmListener l) {
super(); super();
this.priority = priority; this.priority = priority;
this.l = l; this.l = l;
} }
public Priority getPriority() { public Priority getPriority() {
return priority; return priority;
} }
public VehicleRoutingAlgorithmListener getListener() { public VehicleRoutingAlgorithmListener getListener() {
return l; return l;
} }
// @Override
// public int hashCode() {
// final int prime = 31;
// int result = 1;
// result = prime * result + ((l == null) ? 0 : l.hashCode());
// result = prime * result
// + ((priority == null) ? 0 : priority.hashCode());
// return result;
// }
// @Override
// public boolean equals(Object obj) {
// if (this == obj)
// return true;
// if (obj == null)
// return false;
// if (getClass() != obj.getClass())
// return false;
// PrioritizedVRAListener other = (PrioritizedVRAListener) obj;
// if (l == null) {
// if (other.l != null)
// return false;
// } else if (!l.equals(other.l))
// return false;
// if (priority == null) {
// if (other.priority != null)
// return false;
// } else if (!priority.equals(other.priority))
// return false;
// return true;
// }
} }
public enum Priority { public enum Priority {
@ -89,14 +59,11 @@ public class VehicleRoutingAlgorithmListeners {
if (o1 == o2) return 0; if (o1 == o2) return 0;
if (o1.getPriority() == Priority.HIGH && o2.getPriority() != Priority.HIGH) { if (o1.getPriority() == Priority.HIGH && o2.getPriority() != Priority.HIGH) {
return -1; return -1;
} } else if (o2.getPriority() == Priority.HIGH && o1.getPriority() != Priority.HIGH) {
else if(o2.getPriority() == Priority.HIGH && o1.getPriority() != Priority.HIGH){
return 1; return 1;
} } else if (o1.getPriority() == Priority.MEDIUM && o2.getPriority() != Priority.MEDIUM) {
else if(o1.getPriority() == Priority.MEDIUM && o2.getPriority() != Priority.MEDIUM){
return -1; return -1;
} } else if (o2.getPriority() == Priority.MEDIUM && o1.getPriority() != Priority.MEDIUM) {
else if(o2.getPriority() == Priority.MEDIUM && o1.getPriority() != Priority.MEDIUM){
return 1; return 1;
} }
return 1; return 1;
@ -114,7 +81,9 @@ public class VehicleRoutingAlgorithmListeners {
public void remove(PrioritizedVRAListener listener) { public void remove(PrioritizedVRAListener listener) {
boolean removed = algorithmListeners.remove(listener); boolean removed = algorithmListeners.remove(listener);
if(!removed){ throw new IllegalStateException("cannot remove listener"); } if (!removed) {
throw new IllegalStateException("cannot remove listener");
}
} }
public void addListener(VehicleRoutingAlgorithmListener listener, Priority priority) { public void addListener(VehicleRoutingAlgorithmListener listener, Priority priority) {
@ -143,7 +112,6 @@ public class VehicleRoutingAlgorithmListeners {
} }
public void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
for (PrioritizedVRAListener l : algorithmListeners) { for (PrioritizedVRAListener l : algorithmListeners) {
if (l.getListener() instanceof IterationStartsListener) { if (l.getListener() instanceof IterationStartsListener) {
@ -153,7 +121,6 @@ public class VehicleRoutingAlgorithmListeners {
} }
public void algorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) { public void algorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
for (PrioritizedVRAListener l : algorithmListeners) { for (PrioritizedVRAListener l : algorithmListeners) {
if (l.getListener() instanceof AlgorithmStartsListener) { if (l.getListener() instanceof AlgorithmStartsListener) {

View file

@ -110,7 +110,7 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy{
} }
protected void insertJob(Job unassignedJob, InsertionData iData, VehicleRoute inRoute) { protected void insertJob(Job unassignedJob, InsertionData iData, VehicleRoute inRoute) {
logger.trace("insert: [jobId=" + unassignedJob.getId() + "]" + iData ); logger.trace("insert: [jobId={}]{}", unassignedJob.getId(), iData);
insertionsListeners.informBeforeJobInsertion(unassignedJob, iData, inRoute); insertionsListeners.informBeforeJobInsertion(unassignedJob, iData, inRoute);
if (!(inRoute.getVehicle().getId().equals(iData.getSelectedVehicle().getId()))) { if (!(inRoute.getVehicle().getId().equals(iData.getSelectedVehicle().getId()))) {
insertionsListeners.informVehicleSwitched(inRoute, inRoute.getVehicle(), iData.getSelectedVehicle()); insertionsListeners.informVehicleSwitched(inRoute, inRoute.getVehicle(), iData.getSelectedVehicle());

View file

@ -1,4 +1,3 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder * Copyright (C) 2014 Stefan Schroeder
* *
@ -27,17 +26,20 @@ public interface ActivityInsertionCostsCalculator {
private double additionalCosts; private double additionalCosts;
private double additionalTime; private double additionalTime;
public ActivityInsertionCosts(double additionalCosts, double additionalTime) { public ActivityInsertionCosts(double additionalCosts, double additionalTime) {
super(); super();
this.additionalCosts = additionalCosts; this.additionalCosts = additionalCosts;
this.additionalTime = additionalTime; this.additionalTime = additionalTime;
} }
/** /**
* @return the additionalCosts * @return the additionalCosts
*/ */
public double getAdditionalCosts() { public double getAdditionalCosts() {
return additionalCosts; return additionalCosts;
} }
/** /**
* @return the additionalTime * @return the additionalTime
*/ */
@ -46,7 +48,6 @@ public interface ActivityInsertionCostsCalculator {
} }
} }
public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct); public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct);

View file

@ -25,11 +25,10 @@ import jsprit.core.problem.vehicle.Vehicle;
/** /**
* Estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location. * Estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location.
* * <p/>
* <p>If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero. * <p>If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero.
* *
* @author schroeder * @author schroeder
*
*/ */
class AdditionalAccessEgressCalculator { class AdditionalAccessEgressCalculator {
@ -37,11 +36,10 @@ class AdditionalAccessEgressCalculator {
/** /**
* Constructs the estimator that estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location. * Constructs the estimator that estimates additional access/egress costs when operating route with a new vehicle that has different start/end-location.
* * <p/>
* <p>If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero. * <p>If two vehicles have the same start/end-location and departure-time .getCosts(...) must return zero.
* *
* @author schroeder * @author schroeder
*
*/ */
public AdditionalAccessEgressCalculator(VehicleRoutingTransportCosts routingCosts) { public AdditionalAccessEgressCalculator(VehicleRoutingTransportCosts routingCosts) {
this.routingCosts = routingCosts; this.routingCosts = routingCosts;

View file

@ -27,7 +27,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
final class AuxilliaryCostCalculator { final class AuxilliaryCostCalculator {
private final VehicleRoutingTransportCosts routingCosts; private final VehicleRoutingTransportCosts routingCosts;
@ -41,7 +40,6 @@ final class AuxilliaryCostCalculator {
} }
/** /**
*
* @param path activity path to get the costs for * @param path activity path to get the costs for
* @param depTime departure time at first activity in path * @param depTime departure time at first activity in path
* @param driver driver of vehicle * @param driver driver of vehicle

View file

@ -30,13 +30,10 @@ import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* Best insertion that insert the job where additional costs are minimal. * Best insertion that insert the job where additional costs are minimal.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public final class BestInsertion extends AbstractInsertionStrategy { public final class BestInsertion extends AbstractInsertionStrategy {
@ -56,7 +53,7 @@ public final class BestInsertion extends AbstractInsertionStrategy{
public BestInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) { public BestInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
super(vehicleRoutingProblem); super(vehicleRoutingProblem);
bestInsertionCostCalculator = jobInsertionCalculator; bestInsertionCostCalculator = jobInsertionCalculator;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@Override @Override

View file

@ -77,7 +77,9 @@ public class BestInsertionBuilder {
this.forwaredLooking = forwardLooking; this.forwaredLooking = forwardLooking;
this.memory = memory; this.memory = memory;
return this; return this;
}; }
;
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation) { public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation) {
local = false; local = false;
@ -85,12 +87,16 @@ public class BestInsertionBuilder {
this.memory = memory; this.memory = memory;
this.addDefaultCostCalc = addDefaultMarginalCostCalculation; this.addDefaultCostCalc = addDefaultMarginalCostCalculation;
return this; return this;
}; }
;
public BestInsertionBuilder setLocalLevel() { public BestInsertionBuilder setLocalLevel() {
local = true; local = true;
return this; return this;
}; }
;
/** /**
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation * If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
@ -114,7 +120,9 @@ public class BestInsertionBuilder {
public BestInsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) { public BestInsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
this.actInsertionCostsCalculator = activityInsertionCostsCalculator; this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
return this; return this;
}; }
;
public BestInsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) { public BestInsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) {
this.executor = executor; this.executor = executor;
@ -129,8 +137,7 @@ public class BestInsertionBuilder {
JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners); JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners);
if (local) { if (local) {
calcBuilder.setLocalLevel(addDefaultCostCalc); calcBuilder.setLocalLevel(addDefaultCostCalc);
} } else {
else {
calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc); calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc);
} }
calcBuilder.setConstraintManager(constraintManager); calcBuilder.setConstraintManager(constraintManager);
@ -149,8 +156,7 @@ public class BestInsertionBuilder {
InsertionStrategy bestInsertion; InsertionStrategy bestInsertion;
if (executor == null) { if (executor == null) {
bestInsertion = new BestInsertion(jobInsertions, vrp); bestInsertion = new BestInsertion(jobInsertions, vrp);
} } else {
else{
bestInsertion = new BestInsertionConcurrent(jobInsertions, executor, nuOfThreads, vrp); bestInsertion = new BestInsertionConcurrent(jobInsertions, executor, nuOfThreads, vrp);
} }
for (InsertionListener l : iListeners) bestInsertion.addListener(l); for (InsertionListener l : iListeners) bestInsertion.addListener(l);
@ -158,9 +164,9 @@ public class BestInsertionBuilder {
} }
/** /**
* @deprecated this is experimental and can disappear.
* @param timeSlice the time slice * @param timeSlice the time slice
* @param nNeighbors number of neighbors * @param nNeighbors number of neighbors
* @deprecated this is experimental and can disappear.
*/ */
@Deprecated @Deprecated
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) { public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
@ -174,6 +180,4 @@ public class BestInsertionBuilder {
} }
} }

View file

@ -30,12 +30,8 @@ import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
*
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public final class BestInsertionConcurrent extends AbstractInsertionStrategy { public final class BestInsertionConcurrent extends AbstractInsertionStrategy {
@ -94,7 +90,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy{
this.nuOfBatches = nuOfBatches; this.nuOfBatches = nuOfBatches;
bestInsertionCostCalculator = jobInsertionCalculator; bestInsertionCostCalculator = jobInsertionCalculator;
completionService = new ExecutorCompletionService<Insertion>(executorService); completionService = new ExecutorCompletionService<Insertion>(executorService);
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@Override @Override
@ -133,11 +129,8 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy{
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} } catch (ExecutionException e) {
catch (ExecutionException e) { throw new RuntimeException(e);
e.printStackTrace();
logger.error(e.getCause().toString());
System.exit(1);
} }
VehicleRoute newRoute = VehicleRoute.emptyRoute(); VehicleRoute newRoute = VehicleRoute.emptyRoute();
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost); InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
@ -180,8 +173,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy{
for (int i = 0; i < nOfNewRoutes; i++) { for (int i = 0; i < nOfNewRoutes; i++) {
vehicleRoutes.add(VehicleRoute.emptyRoute()); vehicleRoutes.add(VehicleRoute.emptyRoute());
} }
} } else {
else{
vehicleRoutes.add(VehicleRoute.emptyRoute()); vehicleRoutes.add(VehicleRoute.emptyRoute());
} }
/* /*

View file

@ -0,0 +1,179 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.JobActivityFactory;
import jsprit.core.problem.Location;
import jsprit.core.problem.constraint.*;
import jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus;
import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import jsprit.core.problem.driver.Driver;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.misc.JobInsertionContext;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.BreakActivity;
import jsprit.core.problem.solution.route.activity.End;
import jsprit.core.problem.solution.route.activity.Start;
import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.vehicle.Vehicle;
import jsprit.core.util.CalculationUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* Calculator that calculates the best insertion position for a {@link jsprit.core.problem.job.Service}.
*
* @author schroeder
*/
final class BreakInsertionCalculator implements JobInsertionCostsCalculator {
private static final Logger logger = LogManager.getLogger(BreakInsertionCalculator.class);
private HardRouteConstraint hardRouteLevelConstraint;
private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint;
private VehicleRoutingTransportCosts transportCosts;
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
private JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
public BreakInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
super();
this.transportCosts = routingCosts;
hardRouteLevelConstraint = constraintManager;
hardActivityLevelConstraint = constraintManager;
softActivityConstraint = constraintManager;
softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
logger.debug("initialise " + this);
}
public void setJobActivityFactory(JobActivityFactory jobActivityFactory) {
this.activityFactory = jobActivityFactory;
}
@Override
public String toString() {
return "[name=calculatesServiceInsertion]";
}
/**
* Calculates the marginal cost of inserting job i locally. This is based on the
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
*/
@Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
Break breakToInsert = (Break) jobToInsert;
if (newVehicle.getBreak() == null || newVehicle.getBreak() != breakToInsert) {
return InsertionData.createEmptyInsertionData();
}
if (currentRoute.isEmpty()) return InsertionData.createEmptyInsertionData();
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
int insertionIndex = InsertionData.NO_INDEX;
BreakActivity breakAct2Insert = (BreakActivity) activityFactory.createActivities(breakToInsert).get(0);
insertionContext.getAssociatedActivities().add(breakAct2Insert);
/*
check hard constraints at route level
*/
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
return InsertionData.createEmptyInsertionData();
}
/*
check soft constraints at route level
*/
double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext);
double bestCost = bestKnownCosts;
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
/*
generate new start and end for new vehicle
*/
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
start.setEndTime(newVehicleDepartureTime);
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
Location bestLocation = null;
TourActivity prevAct = start;
double prevActStartTime = newVehicleDepartureTime;
int actIndex = 0;
Iterator<TourActivity> activityIterator = currentRoute.getActivities().iterator();
boolean tourEnd = false;
while (!tourEnd) {
TourActivity nextAct;
if (activityIterator.hasNext()) nextAct = activityIterator.next();
else {
nextAct = end;
tourEnd = true;
}
boolean breakThis = true;
List<Location> locations = Arrays.asList(prevAct.getLocation(), nextAct.getLocation());
for (Location location : locations) {
breakAct2Insert.setLocation(location);
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, breakAct2Insert, nextAct, prevActStartTime);
if (status.equals(ConstraintsStatus.FULFILLED)) {
//from job2insert induced costs at activity level
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, breakAct2Insert, nextAct, prevActStartTime);
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, breakAct2Insert, prevActStartTime);
if (additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost) {
bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts;
insertionIndex = actIndex;
bestLocation = location;
}
breakThis = false;
} else if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
breakThis = false;
}
}
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle);
prevActStartTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
prevAct = nextAct;
actIndex++;
if (breakThis) break;
}
if (insertionIndex == InsertionData.NO_INDEX) {
return InsertionData.createEmptyInsertionData();
}
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
breakAct2Insert.setLocation(bestLocation);
insertionData.getEvents().add(new InsertBreak(currentRoute, newVehicle, breakAct2Insert, insertionIndex));
insertionData.getEvents().add(new SwitchVehicle(currentRoute, newVehicle, newVehicleDepartureTime));
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
return insertionData;
}
}

View file

@ -20,10 +20,12 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsC
public static class KnowledgeInjection implements InsertionStartsListener { public static class KnowledgeInjection implements InsertionStartsListener {
private CalculatesServiceInsertionWithTimeScheduling c; private CalculatesServiceInsertionWithTimeScheduling c;
public KnowledgeInjection(CalculatesServiceInsertionWithTimeScheduling c) { public KnowledgeInjection(CalculatesServiceInsertionWithTimeScheduling c) {
super(); super();
this.c = c; this.c = c;
} }
@Override @Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) { public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
List<Double> knowledge = new ArrayList<Double>(); List<Double> knowledge = new ArrayList<Double>();
@ -70,8 +72,7 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsC
if (!departureTimeKnowledge.isEmpty()) { if (!departureTimeKnowledge.isEmpty()) {
departureTime = departureTimeKnowledge.get(random.nextInt(departureTimeKnowledge.size())); departureTime = departureTimeKnowledge.get(random.nextInt(departureTimeKnowledge.size()));
} }
} } else if (!currentRoute.getVehicle().getId().equals(newVehicle.getId())) {
else if(!currentRoute.getVehicle().getId().equals(newVehicle.getId())){
departureTime = currentRoute.getDepartureTime(); departureTime = currentRoute.getDepartureTime();
} }

View file

@ -57,8 +57,7 @@ class CalculatesServiceInsertionWithTimeSchedulingInSlices implements JobInserti
double currentStart; double currentStart;
if (currentRoute.getStart() == null) { if (currentRoute.getStart() == null) {
currentStart = newVehicleDepartureTime; currentStart = newVehicleDepartureTime;
} } else currentStart = currentRoute.getStart().getEndTime();
else currentStart = currentRoute.getStart().getEndTime();
vehicleDepartureTimes.add(currentStart); vehicleDepartureTimes.add(currentStart);
// double earliestDeparture = newVehicle.getEarliestDeparture(); // double earliestDeparture = newVehicle.getEarliestDeparture();

View file

@ -0,0 +1,40 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
import jsprit.core.algorithm.recreate.listener.JobInsertedListener;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection;
/**
* Created by schroeder on 22/07/15.
*/
public class ConfigureLocalActivityInsertionCalculator implements InsertionStartsListener, JobInsertedListener {
private VehicleRoutingProblem vrp;
private LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator;
private int nuOfJobsToRecreate;
public ConfigureLocalActivityInsertionCalculator(VehicleRoutingProblem vrp, LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator) {
this.vrp = vrp;
this.localActivityInsertionCostsCalculator = localActivityInsertionCostsCalculator;
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5, completenessRatio));
}
@Override
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
nuOfJobsToRecreate--;
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5, completenessRatio));
}
}

View file

@ -0,0 +1,83 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.Location;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.job.Shipment;
/**
* Created by schroeder on 15/10/15.
*/
public class DefaultScorer implements ScoringFunction {
private VehicleRoutingProblem vrp;
private double tw_param = -0.5;
private double depotDistance_param = +0.1;
private double minTimeWindowScore = -100000;
public DefaultScorer(VehicleRoutingProblem vrp) {
this.vrp = vrp;
}
public void setTimeWindowParam(double tw_param) {
this.tw_param = tw_param;
}
public void setDepotDistanceParam(double depotDistance_param) {
this.depotDistance_param = depotDistance_param;
}
@Override
public double score(InsertionData best, Job job) {
double score;
if (job instanceof Service) {
score = scoreService(best, job);
} else if (job instanceof Shipment) {
score = scoreShipment(best, job);
} else throw new IllegalStateException("not supported");
return score;
}
private double scoreShipment(InsertionData best, Job job) {
Shipment shipment = (Shipment) job;
double maxDepotDistance_1 = Math.max(
getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getPickupLocation()),
getDistance(best.getSelectedVehicle().getStartLocation(), shipment.getDeliveryLocation())
);
double maxDepotDistance_2 = Math.max(
getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getPickupLocation()),
getDistance(best.getSelectedVehicle().getEndLocation(), shipment.getDeliveryLocation())
);
double maxDepotDistance = Math.max(maxDepotDistance_1, maxDepotDistance_2);
double minTimeToOperate = Math.min(shipment.getPickupTimeWindow().getEnd() - shipment.getPickupTimeWindow().getStart(),
shipment.getDeliveryTimeWindow().getEnd() - shipment.getDeliveryTimeWindow().getStart());
return Math.max(tw_param * minTimeToOperate, minTimeWindowScore) + depotDistance_param * maxDepotDistance;
}
private double scoreService(InsertionData best, Job job) {
Location location = ((Service) job).getLocation();
double maxDepotDistance = 0;
if (location != null) {
maxDepotDistance = Math.max(
getDistance(best.getSelectedVehicle().getStartLocation(), location),
getDistance(best.getSelectedVehicle().getEndLocation(), location)
);
}
return Math.max(tw_param * (((Service) job).getTimeWindow().getEnd() - ((Service) job).getTimeWindow().getStart()), minTimeWindowScore) +
depotDistance_param * maxDepotDistance;
}
private double getDistance(Location loc1, Location loc2) {
return vrp.getTransportCosts().getTransportCost(loc1, loc2, 0., null, null);
}
@Override
public String toString() {
return "[name=defaultScorer][twParam=" + tw_param + "][depotDistanceParam=" + depotDistance_param + "]";
}
}

View file

@ -13,6 +13,7 @@ class EventListeners {
public EventListeners() { public EventListeners() {
listeners.add(new InsertActivityListener()); listeners.add(new InsertActivityListener());
listeners.add(new SwitchVehicleListener()); listeners.add(new SwitchVehicleListener());
listeners.add(new InsertBreakListener());
} }
public void inform(Event event) { public void inform(Event event) {

View file

@ -0,0 +1,42 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.vehicle.Vehicle;
/**
* Created by schroeder on 19/05/15.
*/
class InsertBreak implements Event {
private VehicleRoute vehicleRoute;
private Vehicle newVehicle;
private TourActivity activity;
private int index;
public InsertBreak(VehicleRoute vehicleRoute, Vehicle newVehicle, TourActivity activity, int index) {
this.vehicleRoute = vehicleRoute;
this.newVehicle = newVehicle;
this.activity = activity;
this.index = index;
}
public Vehicle getNewVehicle() {
return newVehicle;
}
public VehicleRoute getVehicleRoute() {
return vehicleRoute;
}
public TourActivity getActivity() {
return activity;
}
public int getIndex() {
return index;
}
}

View file

@ -0,0 +1,37 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.solution.route.VehicleRoute;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Created by schroeder on 19/05/15.
*/
class InsertBreakListener implements EventListener {
private static final Logger logger = LogManager.getLogger();
@Override
public void inform(Event event) {
if (event instanceof InsertBreak) {
InsertBreak insertActivity = (InsertBreak) event;
if (!insertActivity.getNewVehicle().isReturnToDepot()) {
if (insertActivity.getIndex() >= insertActivity.getVehicleRoute().getActivities().size()) {
insertActivity.getVehicleRoute().getEnd().setLocation(insertActivity.getActivity().getLocation());
}
}
VehicleRoute vehicleRoute = ((InsertBreak) event).getVehicleRoute();
if (!vehicleRoute.isEmpty()) {
if (vehicleRoute.getVehicle() != ((InsertBreak) event).getNewVehicle()) {
if (vehicleRoute.getVehicle().getBreak() != null) {
boolean removed = vehicleRoute.getTourActivities().removeJob(vehicleRoute.getVehicle().getBreak());
if (removed)
logger.trace("remove old break " + vehicleRoute.getVehicle().getBreak());
}
}
}
insertActivity.getVehicleRoute().getTourActivities().addActivity(insertActivity.getIndex(), ((InsertBreak) event).getActivity());
}
}
}

View file

@ -75,8 +75,7 @@ class Inserter {
} }
TourActivity activity = vehicleRoutingProblem.copyAndGetActivities(job).get(0); TourActivity activity = vehicleRoutingProblem.copyAndGetActivities(job).get(0);
route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), activity); route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), activity);
} } else delegator.handleJobInsertion(job, iData, route);
else delegator.handleJobInsertion(job, iData, route);
} }
private void setEndLocation(VehicleRoute route, Service service) { private void setEndLocation(VehicleRoute route, Service service) {
@ -115,8 +114,7 @@ class Inserter {
} }
route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), deliverShipment); route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), deliverShipment);
route.getTourActivities().addActivity(iData.getPickupInsertionIndex(), pickupShipment); route.getTourActivities().addActivity(iData.getPickupInsertionIndex(), pickupShipment);
} } else delegator.handleJobInsertion(job, iData, route);
else delegator.handleJobInsertion(job, iData, route);
} }
private void setEndLocation(VehicleRoute route, Shipment shipment) { private void setEndLocation(VehicleRoute route, Shipment shipment) {
@ -145,7 +143,8 @@ class Inserter {
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute) { public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute) {
insertionListeners.informBeforeJobInsertion(job, insertionData, vehicleRoute); insertionListeners.informBeforeJobInsertion(job, insertionData, vehicleRoute);
if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job."); 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 (job == null) throw new IllegalStateException("cannot insert null-job");
if (!(vehicleRoute.getVehicle().getId().equals(insertionData.getSelectedVehicle().getId()))) { if (!(vehicleRoute.getVehicle().getId().equals(insertionData.getSelectedVehicle().getId()))) {
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle()); insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());

View file

@ -30,6 +30,9 @@ import java.util.concurrent.ExecutorService;
public class InsertionBuilder { public class InsertionBuilder {
private boolean fastRegret;
public enum Strategy { public enum Strategy {
REGRET, BEST REGRET, BEST
} }
@ -70,6 +73,8 @@ public class InsertionBuilder {
private Strategy strategy = Strategy.BEST; private Strategy strategy = Strategy.BEST;
private boolean isFastRegret = false;
public InsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) { public InsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
super(); super();
this.vrp = vrp; this.vrp = vrp;
@ -98,6 +103,12 @@ public class InsertionBuilder {
return this; return this;
} }
public InsertionBuilder setFastRegret(boolean fastRegret) {
this.isFastRegret = fastRegret;
return this;
}
public InsertionBuilder setLocalLevel() { public InsertionBuilder setLocalLevel() {
local = true; local = true;
return this; return this;
@ -140,8 +151,7 @@ public class InsertionBuilder {
JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners); JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners);
if (local) { if (local) {
calcBuilder.setLocalLevel(addDefaultCostCalc); calcBuilder.setLocalLevel(addDefaultCostCalc);
} } else {
else {
calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc); calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc);
} }
calcBuilder.setConstraintManager(constraintManager); calcBuilder.setConstraintManager(constraintManager);
@ -165,24 +175,39 @@ public class InsertionBuilder {
} else { } else {
insertion = new BestInsertionConcurrent(costCalculator, executor, nuOfThreads, vrp); insertion = new BestInsertionConcurrent(costCalculator, executor, nuOfThreads, vrp);
} }
} } else if (strategy.equals(Strategy.REGRET)) {
else if(strategy.equals(Strategy.REGRET)){
if (executor == null) { if (executor == null) {
insertion = new RegretInsertion(costCalculator, vrp); if(isFastRegret){
RegretInsertionFast regret = new RegretInsertionFast(costCalculator, vrp, fleetManager);
regret.setSwitchAllowed(allowVehicleSwitch);
insertion = regret;
} }
else { else {
insertion = new RegretInsertionConcurrent(costCalculator,vrp,executor); RegretInsertion regret = new RegretInsertion(costCalculator, vrp);
insertion = regret;
} }
} else {
if(isFastRegret){
RegretInsertionConcurrentFast regret = new RegretInsertionConcurrentFast(costCalculator, vrp, executor, fleetManager);
regret.setSwitchAllowed(allowVehicleSwitch);
insertion = regret;
} }
else throw new IllegalStateException("you should never get here"); else{
RegretInsertionConcurrent regret = new RegretInsertionConcurrent(costCalculator, vrp, executor);
insertion = regret;
}
}
} else throw new IllegalStateException("you should never get here");
for (InsertionListener l : iListeners) insertion.addListener(l); for (InsertionListener l : iListeners) insertion.addListener(l);
return insertion; return insertion;
} }
/** /**
* @deprecated this is experimental and can disappear.
* @param timeSlice the time slice * @param timeSlice the time slice
* @param nNeighbors number of neighbors * @param nNeighbors number of neighbors
* @deprecated this is experimental and can disappear.
*/ */
@Deprecated @Deprecated
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) { public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
@ -197,6 +222,4 @@ public class InsertionBuilder {
} }
} }

View file

@ -27,7 +27,6 @@ import java.util.List;
* and departureTime of vehicle at vehicle's start location (e.g. depot). * and departureTime of vehicle at vehicle's start location (e.g. depot).
* *
* @author stefan * @author stefan
*
*/ */
public class InsertionData { public class InsertionData {
@ -162,5 +161,4 @@ public class InsertionData {
} }
} }

View file

@ -0,0 +1,157 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.Vehicle;
import jsprit.core.problem.vehicle.VehicleFleetManager;
import jsprit.core.problem.vehicle.VehicleImpl;
import java.util.*;
/**
* Created by schroeder on 15/10/15.
*/
class InsertionDataUpdater {
static boolean update(boolean addAllAvailable, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet<VersionedInsertionData> insertionDataSet, int updateRound, Job unassignedJob, Collection<VehicleRoute> routes) {
for(VehicleRoute route : routes) {
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
relevantVehicles.add(route.getVehicle());
if(addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())){
relevantVehicles.addAll(fleetManager.getAvailableVehicles(route.getVehicle()));
}
} else relevantVehicles.addAll(fleetManager.getAvailableVehicles());
for (Vehicle v : relevantVehicles) {
double depTime = v.getEarliestDeparture();
InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, v, depTime, route.getDriver(), Double.MAX_VALUE);
if (iData instanceof InsertionData.NoInsertionFound) {
continue;
}
insertionDataSet.add(new VersionedInsertionData(iData, updateRound, route));
}
}
return true;
}
static VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
for(VehicleRoute r : routes){
if(r.getVehicle().getBreak() == job) return r;
}
return null;
}
static Comparator<VersionedInsertionData> getComparator(){
return new Comparator<VersionedInsertionData>() {
@Override
public int compare(VersionedInsertionData o1, VersionedInsertionData o2) {
if(o1.getiData().getInsertionCost() < o2.getiData().getInsertionCost()) return -1;
return 1;
}
};
}
static ScoredJob getBest(boolean switchAllowed, Set<String> initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet<VersionedInsertionData>[] priorityQueues, Map<VehicleRoute, Integer> updates, List<Job> unassignedJobList, List<Job> badJobs) {
ScoredJob bestScoredJob = null;
for(Job j : unassignedJobList){
VehicleRoute bestRoute = null;
InsertionData best = null;
InsertionData secondBest = null;
TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[j.getIndex()];
Iterator<VersionedInsertionData> iterator = priorityQueue.iterator();
while(iterator.hasNext()){
VersionedInsertionData versionedIData = iterator.next();
if(bestRoute != null){
if(versionedIData.getRoute() == bestRoute){
continue;
}
}
if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue;
if(!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) {
if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
if (!switchAllowed) continue;
if (initialVehicleIds.contains(versionedIData.getRoute().getVehicle().getId())) continue;
}
}
if(versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) {
if (fleetManager.isLocked(versionedIData.getiData().getSelectedVehicle())) {
Vehicle available = fleetManager.getAvailableVehicle(versionedIData.getiData().getSelectedVehicle().getVehicleTypeIdentifier());
if (available != null) {
InsertionData oldData = versionedIData.getiData();
InsertionData newData = new InsertionData(oldData.getInsertionCost(), oldData.getPickupInsertionIndex(),
oldData.getDeliveryInsertionIndex(), available, oldData.getSelectedDriver());
newData.setVehicleDepartureTime(oldData.getVehicleDepartureTime());
for(Event e : oldData.getEvents()){
if(e instanceof SwitchVehicle){
newData.getEvents().add(new SwitchVehicle(versionedIData.getRoute(),available,oldData.getVehicleDepartureTime()));
}
else newData.getEvents().add(e);
}
versionedIData = new VersionedInsertionData(newData, versionedIData.getVersion(), versionedIData.getRoute());
} else continue;
}
}
int currentDataVersion = updates.get(versionedIData.getRoute());
if(versionedIData.getVersion() == currentDataVersion){
if(best == null) {
best = versionedIData.getiData();
bestRoute = versionedIData.getRoute();
}
else {
secondBest = versionedIData.getiData();
break;
}
}
}
VehicleRoute emptyRoute = VehicleRoute.emptyRoute();
InsertionData iData = insertionCostsCalculator.getInsertionData(emptyRoute, j, null, -1, null, Double.MAX_VALUE);
if(!(iData instanceof InsertionData.NoInsertionFound)){
if (best == null) {
best = iData;
bestRoute = emptyRoute;
} else if (iData.getInsertionCost() < best.getInsertionCost()) {
secondBest = best;
best = iData;
bestRoute = emptyRoute;
} else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) {
secondBest = iData;
}
}
if (best == null) {
badJobs.add(j);
continue;
}
double score = score(j, best, secondBest, scoringFunction);
ScoredJob scoredJob;
if (bestRoute == emptyRoute) {
scoredJob = new ScoredJob(j, score, best, bestRoute, true);
} else scoredJob = new ScoredJob(j, score, best, bestRoute, false);
if(bestScoredJob == null){
bestScoredJob = scoredJob;
}
else if(scoredJob.getScore() > bestScoredJob.getScore()){
bestScoredJob = scoredJob;
}
}
return bestScoredJob;
}
static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
if (best == null) {
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
}
double score;
if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
//if only one vehicle, I want the job to be inserted with min iCosts
//if there are more vehicles, I want this job to be prioritized since there are no alternatives
score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob);
} else {
score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
}
return score;
}
}

View file

@ -23,18 +23,17 @@ import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection; import java.util.Collection;
/** /**
* Basic interface for insertion strategies * Basic interface for insertion strategies
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public interface InsertionStrategy { public interface InsertionStrategy {
/** /**
* Inserts unassigned jobs into vehicle routes. * Inserts unassigned jobs into vehicle routes.
*
* @param vehicleRoutes existing vehicle routes * @param vehicleRoutes existing vehicle routes
* @param unassignedJobs jobs to be inserted * @param unassignedJobs jobs to be inserted
*/ */

View file

@ -46,7 +46,7 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos
super(); super();
this.standardServiceInsertion = standardInsertionCalculator; this.standardServiceInsertion = standardInsertionCalculator;
this.stateGetter = stateGetter; this.stateGetter = stateGetter;
logger.debug("inialise " + this); logger.debug("inialise {}", this);
} }
@Override @Override
@ -66,10 +66,10 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos
return insertionData; return insertionData;
} }
private double getFixCostContribution(final VehicleRoute currentRoute, private double getFixCostContribution(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle) {
final Job jobToInsert, final Vehicle newVehicle) { Capacity currentMaxLoadInRoute = getCurrentMaxLoadInRoute(currentRoute);
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert); double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute);
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert); double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute);
double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost; double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost;
double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost; double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost;
return fixcost_contribution; return fixcost_contribution;
@ -77,7 +77,7 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos
public void setWeightOfFixCost(double weight) { public void setWeightOfFixCost(double weight) {
weight_deltaFixCost = weight; weight_deltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to " + weight); logger.debug("set weightOfFixCostSaving to {}", weight);
} }
@Override @Override
@ -89,9 +89,8 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos
solution_completeness_ratio = ratio; solution_completeness_ratio = ratio;
} }
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) { private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentMaxLoadInRoute) {
Capacity load = Capacity.addup(getCurrentMaxLoadInRoute(route), job.getSize()); Capacity load = Capacity.addup(currentMaxLoadInRoute, job.getSize());
// double load = getCurrentMaxLoadInRoute(route) + job.getCapacityDemand();
double currentFix = 0.0; double currentFix = 0.0;
if (route.getVehicle() != null) { if (route.getVehicle() != null) {
if (!(route.getVehicle() instanceof NoVehicle)) { if (!(route.getVehicle() instanceof NoVehicle)) {
@ -104,11 +103,8 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos
return newVehicle.getType().getVehicleCostParams().fix - currentFix; return newVehicle.getType().getVehicleCostParams().fix - currentFix;
} }
private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job) { private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentLoad) {
Capacity currentLoad = getCurrentMaxLoadInRoute(route);
// int currentLoad = getCurrentMaxLoadInRoute(route);
Capacity load = Capacity.addup(currentLoad, job.getSize()); Capacity load = Capacity.addup(currentLoad, job.getSize());
// double load = currentLoad + job.getCapacityDemand();
double currentRelFix = 0.0; double currentRelFix = 0.0;
if (route.getVehicle() != null) { if (route.getVehicle() != null) {
if (!(route.getVehicle() instanceof NoVehicle)) { if (!(route.getVehicle() instanceof NoVehicle)) {

View file

@ -32,8 +32,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class JobInsertionCostsCalculatorBuilder { public class JobInsertionCostsCalculatorBuilder {
private static class CalculatorPlusListeners { private static class CalculatorPlusListeners {
@ -97,7 +95,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Constructs the builder. * Constructs the builder.
* * <p/>
* <p>Some calculators require information from the overall algorithm or the higher-level insertion procedure. Thus listeners inform them. * <p>Some calculators require information from the overall algorithm or the higher-level insertion procedure. Thus listeners inform them.
* These listeners are cached in the according list and can thus be added when its time to add them. * These listeners are cached in the according list and can thus be added when its time to add them.
* *
@ -112,8 +110,8 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets activityStates. MUST be set. * Sets activityStates. MUST be set.
* @param stateManager
* *
* @param stateManager
* @return * @return
*/ */
public JobInsertionCostsCalculatorBuilder setStateManager(RouteAndActivityStateGetter stateManager) { public JobInsertionCostsCalculatorBuilder setStateManager(RouteAndActivityStateGetter stateManager) {
@ -145,8 +143,9 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets a flag to build a calculator based on local calculations. * Sets a flag to build a calculator based on local calculations.
* * <p/>
* <p>Insertion of a job and job-activity is evaluated based on the previous and next activity. * <p>Insertion of a job and job-activity is evaluated based on the previous and next activity.
*
* @param addDefaultCostCalc * @param addDefaultCostCalc
*/ */
public JobInsertionCostsCalculatorBuilder setLocalLevel(boolean addDefaultCostCalc) { public JobInsertionCostsCalculatorBuilder setLocalLevel(boolean addDefaultCostCalc) {
@ -200,15 +199,17 @@ public class JobInsertionCostsCalculatorBuilder {
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null. * @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
*/ */
public JobInsertionCostsCalculator build() { public JobInsertionCostsCalculator build() {
if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))"); if (vrp == null)
if(states == null) throw new IllegalStateException("states is null, but is must be set (this.setStateManager(states))"); throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))"); if (states == null)
throw new IllegalStateException("states is null, but is must be set (this.setStateManager(states))");
if (fleetManager == null)
throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))");
JobInsertionCostsCalculator baseCalculator = null; JobInsertionCostsCalculator baseCalculator = null;
CalculatorPlusListeners standardLocal = null; CalculatorPlusListeners standardLocal = null;
if (local) { if (local) {
standardLocal = createStandardLocal(vrp, states); standardLocal = createStandardLocal(vrp, states);
} } else {
else{
checkServicesOnly(); checkServicesOnly();
standardLocal = createStandardRoute(vrp, states, forwardLooking, memory); standardLocal = createStandardRoute(vrp, states, forwardLooking, memory);
} }
@ -259,10 +260,11 @@ public class JobInsertionCostsCalculatorBuilder {
if (constraintManager == null) throw new IllegalStateException("constraint-manager is null"); if (constraintManager == null) throw new IllegalStateException("constraint-manager is null");
ActivityInsertionCostsCalculator actInsertionCalc; ActivityInsertionCostsCalculator actInsertionCalc;
ConfigureLocalActivityInsertionCalculator configLocal = null;
if (activityInsertionCostCalculator == null && addDefaultCostCalc) { if (activityInsertionCostCalculator == null && addDefaultCostCalc) {
actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts()); actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), statesManager);
} configLocal = new ConfigureLocalActivityInsertionCalculator(vrp, (LocalActivityInsertionCostsCalculator) actInsertionCalc);
else if(activityInsertionCostCalculator == null && !addDefaultCostCalc){ } else if (activityInsertionCostCalculator == null && !addDefaultCostCalc) {
actInsertionCalc = new ActivityInsertionCostsCalculator() { actInsertionCalc = new ActivityInsertionCostsCalculator() {
@Override @Override
@ -272,8 +274,7 @@ public class JobInsertionCostsCalculatorBuilder {
} }
}; };
} } else {
else{
actInsertionCalc = activityInsertionCostCalculator; actInsertionCalc = activityInsertionCostCalculator;
} }
@ -290,13 +291,21 @@ public class JobInsertionCostsCalculatorBuilder {
ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager); ServiceInsertionCalculator serviceInsertion = new ServiceInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager);
serviceInsertion.setJobActivityFactory(activityFactory); serviceInsertion.setJobActivityFactory(activityFactory);
BreakInsertionCalculator breakInsertionCalculator = new BreakInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager);
breakInsertionCalculator.setJobActivityFactory(activityFactory);
JobCalculatorSwitcher switcher = new JobCalculatorSwitcher(); JobCalculatorSwitcher switcher = new JobCalculatorSwitcher();
switcher.put(Shipment.class, shipmentInsertion); switcher.put(Shipment.class, shipmentInsertion);
switcher.put(Service.class, serviceInsertion); switcher.put(Service.class, serviceInsertion);
switcher.put(Pickup.class, serviceInsertion); switcher.put(Pickup.class, serviceInsertion);
switcher.put(Delivery.class, serviceInsertion); switcher.put(Delivery.class, serviceInsertion);
switcher.put(Break.class, breakInsertionCalculator);
return new CalculatorPlusListeners(switcher); CalculatorPlusListeners calculatorPlusListeners = new CalculatorPlusListeners(switcher);
if (configLocal != null) {
calculatorPlusListeners.insertionListener.add(configLocal);
}
return calculatorPlusListeners;
} }
private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, RouteAndActivityStateGetter activityStates2, double weightOfFixedCosts) { private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, RouteAndActivityStateGetter activityStates2, double weightOfFixedCosts) {
@ -313,8 +322,7 @@ public class JobInsertionCostsCalculatorBuilder {
RouteLevelActivityInsertionCostsEstimator routeLevelActivityInsertionCostsEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityStates2); RouteLevelActivityInsertionCostsEstimator routeLevelActivityInsertionCostsEstimator = new RouteLevelActivityInsertionCostsEstimator(vrp.getTransportCosts(), vrp.getActivityCosts(), activityStates2);
routeLevelActivityInsertionCostsEstimator.setForwardLooking(forwardLooking); routeLevelActivityInsertionCostsEstimator.setForwardLooking(forwardLooking);
routeLevelCostEstimator = routeLevelActivityInsertionCostsEstimator; routeLevelCostEstimator = routeLevelActivityInsertionCostsEstimator;
} } else if (activityInsertionCostCalculator == null && !addDefaultCostCalc) {
else if(activityInsertionCostCalculator == null && !addDefaultCostCalc){
routeLevelCostEstimator = new ActivityInsertionCostsCalculator() { routeLevelCostEstimator = new ActivityInsertionCostsCalculator() {
final ActivityInsertionCosts noInsertionCosts = new ActivityInsertionCosts(0., 0.); final ActivityInsertionCosts noInsertionCosts = new ActivityInsertionCosts(0., 0.);
@ -326,8 +334,7 @@ public class JobInsertionCostsCalculatorBuilder {
} }
}; };
} } else {
else{
routeLevelCostEstimator = activityInsertionCostCalculator; routeLevelCostEstimator = activityInsertionCostCalculator;
} }
ServiceInsertionOnRouteLevelCalculator jobInsertionCalculator = new ServiceInsertionOnRouteLevelCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), routeLevelCostEstimator, constraintManager, constraintManager); ServiceInsertionOnRouteLevelCalculator jobInsertionCalculator = new ServiceInsertionOnRouteLevelCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), routeLevelCostEstimator, constraintManager, constraintManager);

View file

@ -1,4 +1,3 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder * Copyright (C) 2014 Stefan Schroeder
* *
@ -18,22 +17,24 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.algorithm.state.InternalStates;
import jsprit.core.problem.cost.VehicleRoutingActivityCosts; import jsprit.core.problem.cost.VehicleRoutingActivityCosts;
import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import jsprit.core.problem.misc.JobInsertionContext; import jsprit.core.problem.misc.JobInsertionContext;
import jsprit.core.problem.solution.route.activity.End; import jsprit.core.problem.solution.route.activity.End;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
import jsprit.core.problem.vehicle.Vehicle;
import jsprit.core.util.CalculationUtils; import jsprit.core.util.CalculationUtils;
/** /**
* Calculates activity insertion costs locally, i.e. by comparing the additional costs of insertion the new activity k between * Calculates activity insertion costs locally, i.e. by comparing the additional costs of insertion the new activity k between
* activity i (prevAct) and j (nextAct). * activity i (prevAct) and j (nextAct).
* Additional costs are then basically calculated as delta c = c_ik + c_kj - c_ij. * Additional costs are then basically calculated as delta c = c_ik + c_kj - c_ij.
* * <p/>
* <p>Note once time has an effect on costs this class requires activity endTimes. * <p>Note once time has an effect on costs this class requires activity endTimes.
* *
* @author stefan * @author stefan
*
*/ */
class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator { class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCalculator {
@ -41,11 +42,17 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
private VehicleRoutingActivityCosts activityCosts; private VehicleRoutingActivityCosts activityCosts;
private double activityCostsWeight = 1.;
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts) { private double solutionCompletenessRatio = 1.;
private RouteAndActivityStateGetter stateManager;
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) {
super(); super();
this.routingCosts = routingCosts; this.routingCosts = routingCosts;
this.activityCosts = actCosts; this.activityCosts = actCosts;
this.stateManager = stateManager;
} }
@Override @Override
@ -55,35 +62,49 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct; double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct); double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct);
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
//open routes if (isEnd(nextAct) && !toDepot(iFacts.getNewVehicle())) return tp_costs_prevAct_newAct;
if(nextAct instanceof End){
if(!iFacts.getNewVehicle().isReturnToDepot()){
return tp_costs_prevAct_newAct;
}
}
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
double endTime_nextAct_new = CalculationUtils.getActivityEndTime(nextAct_arrTime, nextAct);
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); 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 totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + solutionCompletenessRatio * activityCostsWeight * (act_costs_newAct + act_costs_nextAct);
double oldCosts = 0.;
if (iFacts.getRoute().isEmpty()) { if (iFacts.getRoute().isEmpty()) {
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); oldCosts += tp_costs_prevAct_nextAct;
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); } else {
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
}
else{
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
double arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); double arrTime_nextAct = depTimeAtPrevAct + routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
double endTime_nextAct_old = CalculationUtils.getActivityEndTime(arrTime_nextAct, nextAct);
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
oldCosts = tp_costs_prevAct_nextAct + actCost_nextAct;
double endTimeDelay_nextAct = Math.max(0, endTime_nextAct_new - endTime_nextAct_old);
Double futureWaiting = stateManager.getActivityState(nextAct, iFacts.getRoute().getVehicle(), InternalStates.FUTURE_WAITING, Double.class);
if (futureWaiting == null) futureWaiting = 0.;
double waitingTime_savings_timeUnit = Math.min(futureWaiting, endTimeDelay_nextAct);
double waitingTime_savings = waitingTime_savings_timeUnit * iFacts.getRoute().getVehicle().getType().getVehicleCostParams().perWaitingTimeUnit;
oldCosts += solutionCompletenessRatio * activityCostsWeight * waitingTime_savings;
oldCosts += tp_costs_prevAct_nextAct + solutionCompletenessRatio * activityCostsWeight * actCost_nextAct;
} }
return totalCosts - oldCosts; return totalCosts - oldCosts;
} }
private boolean toDepot(Vehicle newVehicle) {
return newVehicle.isReturnToDepot();
}
private boolean isEnd(TourActivity nextAct) {
return nextAct instanceof End;
}
public void setSolutionCompletenessRatio(double solutionCompletenessRatio) {
this.solutionCompletenessRatio = solutionCompletenessRatio;
}
} }

View file

@ -17,170 +17,33 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.problem.Location;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.job.Shipment;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
* Insertion based on regret approach. * Insertion based on regret approach.
* * <p/>
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference * <p>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. * 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 * 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. * customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class RegretInsertion extends AbstractInsertionStrategy { public class RegretInsertion extends AbstractInsertionStrategy {
static class ScoredJob {
private Job job;
private double score;
private InsertionData insertionData;
private VehicleRoute route;
private boolean newRoute;
ScoredJob(Job job, double score, InsertionData insertionData, VehicleRoute route, boolean isNewRoute) { private static Logger logger = LogManager.getLogger(RegretInsertionFast.class);
this.job = job;
this.score = score;
this.insertionData = insertionData;
this.route = route;
this.newRoute = isNewRoute;
}
public boolean isNewRoute() {
return newRoute;
}
public Job getJob() {
return job;
}
public double getScore() {
return score;
}
public InsertionData getInsertionData() {
return insertionData;
}
public VehicleRoute getRoute() {
return route;
}
}
static class BadJob extends ScoredJob {
BadJob(Job job) {
super(job, 0., null, null, false);
}
}
/**
* Scorer to include other impacts on score such as time-window length or distance to depot.
*
* @author schroeder
*
*/
static interface ScoringFunction {
public double score(InsertionData best, Job job);
}
/**
* Scorer that includes the length of the time-window when scoring a job. The wider the time-window, the lower the score.
*
* <p>This is the default scorer, i.e.: score = (secondBest - firstBest) + this.TimeWindowScorer.score(job)
*
* @author schroeder
*
*/
public static class DefaultScorer implements ScoringFunction {
private VehicleRoutingProblem vrp;
private double tw_param = - 0.5;
private double depotDistance_param = + 0.1;
private double minTimeWindowScore = - 100000;
public DefaultScorer(VehicleRoutingProblem vrp) {
this.vrp = vrp;
}
public void setTimeWindowParam(double tw_param){ this.tw_param = tw_param; }
public void setDepotDistanceParam(double depotDistance_param){ this.depotDistance_param = depotDistance_param; }
@Override
public double score(InsertionData best, Job job) {
double score;
if(job instanceof Service){
score = scoreService(best, job);
}
else if(job instanceof Shipment){
score = scoreShipment(best,job);
}
else throw new IllegalStateException("not supported");
return score;
}
private double scoreShipment(InsertionData best, Job job) {
Shipment shipment = (Shipment)job;
double maxDepotDistance_1 = Math.max(
getDistance(best.getSelectedVehicle().getStartLocation(),shipment.getPickupLocation()),
getDistance(best.getSelectedVehicle().getStartLocation(),shipment.getDeliveryLocation())
);
double maxDepotDistance_2 = Math.max(
getDistance(best.getSelectedVehicle().getEndLocation(),shipment.getPickupLocation()),
getDistance(best.getSelectedVehicle().getEndLocation(),shipment.getDeliveryLocation())
);
double maxDepotDistance = Math.max(maxDepotDistance_1,maxDepotDistance_2);
double minTimeToOperate = Math.min(shipment.getPickupTimeWindow().getEnd()-shipment.getPickupTimeWindow().getStart(),
shipment.getDeliveryTimeWindow().getEnd()-shipment.getDeliveryTimeWindow().getStart());
return Math.max(tw_param * minTimeToOperate,minTimeWindowScore) + depotDistance_param * maxDepotDistance;
}
private double scoreService(InsertionData best, Job job) {
double maxDepotDistance = Math.max(
getDistance(best.getSelectedVehicle().getStartLocation(), ((Service) job).getLocation()),
getDistance(best.getSelectedVehicle().getEndLocation(), ((Service) job).getLocation())
);
return Math.max(tw_param * (((Service)job).getTimeWindow().getEnd() - ((Service)job).getTimeWindow().getStart()),minTimeWindowScore) +
depotDistance_param * maxDepotDistance;
}
private double getDistance(Location loc1, Location loc2) {
return vrp.getTransportCosts().getTransportCost(loc1,loc2,0.,null,null);
}
@Override
public String toString() {
return "[name=defaultScorer][twParam="+tw_param+"][depotDistanceParam=" + depotDistance_param + "]";
}
}
private static Logger logger = LogManager.getLogger(RegretInsertion.class);
private ScoringFunction scoringFunction; private ScoringFunction scoringFunction;
@ -189,7 +52,7 @@ public class RegretInsertion extends AbstractInsertionStrategy {
/** /**
* Sets the scoring function. * Sets the scoring function.
* * <p/>
* <p>By default, the this.TimeWindowScorer is used. * <p>By default, the this.TimeWindowScorer is used.
* *
* @param scoringFunction to score * @param scoringFunction to score
@ -203,7 +66,7 @@ public class RegretInsertion extends AbstractInsertionStrategy {
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem); this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.insertionCostsCalculator = jobInsertionCalculator; this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem; this.vrp = vehicleRoutingProblem;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@Override @Override
@ -214,15 +77,34 @@ public class RegretInsertion extends AbstractInsertionStrategy {
/** /**
* Runs insertion. * Runs insertion.
* * <p/>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables. * <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*
*/ */
@Override @Override
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) { public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size()); List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
Iterator<Job> jobIterator = unassignedJobs.iterator();
while (jobIterator.hasNext()){
Job job = jobIterator.next();
if(job instanceof Break){
VehicleRoute route = findRoute(routes,job);
if(route == null){
badJobs.add(job);
}
else {
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
if (iData instanceof InsertionData.NoInsertionFound) {
badJobs.add(job);
} else {
insertJob(job, iData, route);
}
}
jobIterator.remove();
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
while (!jobs.isEmpty()) { while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs); List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>(); List<Job> badJobList = new ArrayList<Job>();
@ -242,11 +124,18 @@ public class RegretInsertion extends AbstractInsertionStrategy {
return badJobs; return badJobs;
} }
private ScoredJob nextJob(Collection<VehicleRoute> routes, List<Job> unassignedJobList, List<Job> badJobs) { private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
for(VehicleRoute r : routes){
if(r.getVehicle().getBreak() == job) return r;
}
return null;
}
private ScoredJob nextJob(Collection<VehicleRoute> routes, Collection<Job> unassignedJobList, List<Job> badJobs) {
ScoredJob bestScoredJob = null; ScoredJob bestScoredJob = null;
for (Job unassignedJob : unassignedJobList) { for (Job unassignedJob : unassignedJobList) {
ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction); ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction);
if(scoredJob instanceof BadJob){ if (scoredJob instanceof ScoredJob.BadJob) {
badJobs.add(unassignedJob); badJobs.add(unassignedJob);
continue; continue;
} }
@ -254,6 +143,10 @@ public class RegretInsertion extends AbstractInsertionStrategy {
else { else {
if (scoredJob.getScore() > bestScoredJob.getScore()) { if (scoredJob.getScore() > bestScoredJob.getScore()) {
bestScoredJob = scoredJob; bestScoredJob = scoredJob;
} else if (scoredJob.getScore() == bestScoredJob.getScore()) {
if (scoredJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
bestScoredJob = scoredJob;
}
} }
} }
} }
@ -299,14 +192,13 @@ public class RegretInsertion extends AbstractInsertionStrategy {
} }
} }
if (best == null) { if (best == null) {
return new RegretInsertion.BadJob(unassignedJob); return new ScoredJob.BadJob(unassignedJob);
} }
double score = score(unassignedJob, best, secondBest, scoringFunction); double score = score(unassignedJob, best, secondBest, scoringFunction);
ScoredJob scoredJob; ScoredJob scoredJob;
if (bestRoute == emptyRoute) { if (bestRoute == emptyRoute) {
scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true); scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, true);
} } else scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false);
else scoredJob = new ScoredJob(unassignedJob, score, best, bestRoute, false);
return scoredJob; return scoredJob;
} }
@ -320,8 +212,7 @@ public class RegretInsertion extends AbstractInsertionStrategy {
//if only one vehicle, I want the job to be inserted with min iCosts //if only one vehicle, I want the job to be inserted with min iCosts
//if there are more vehicles, I want this job to be prioritized since there are no alternatives //if there are more vehicles, I want this job to be prioritized since there are no alternatives
score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob); score = Integer.MAX_VALUE - best.getInsertionCost() + scoringFunction.score(best, unassignedJob);
} } else {
else{
score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); score = (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob);
} }
return score; return score;

View file

@ -17,10 +17,8 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.algorithm.recreate.RegretInsertion.DefaultScorer;
import jsprit.core.algorithm.recreate.RegretInsertion.ScoredJob;
import jsprit.core.algorithm.recreate.RegretInsertion.ScoringFunction;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -28,24 +26,24 @@ import org.apache.logging.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
/** /**
* Insertion based on regret approach. * Insertion based on regret approach.
* * <p/>
* <p>Basically calculates the insertion cost of the firstBest and the secondBest alternative. The score is then calculated as difference * <p>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. * 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 * 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. * customer immediatedly. If difference is not that high, it might not impact solution if this customer is inserted later.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class RegretInsertionConcurrent extends AbstractInsertionStrategy { public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
private static Logger logger = LogManager.getLogger(RegretInsertionConcurrent.class); private static Logger logger = LogManager.getLogger(RegretInsertionConcurrentFast.class);
private ScoringFunction scoringFunction; private ScoringFunction scoringFunction;
@ -55,7 +53,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
/** /**
* Sets the scoring function. * Sets the scoring function.
* * <p/>
* <p>By default, the this.TimeWindowScorer is used. * <p>By default, the this.TimeWindowScorer is used.
* *
* @param scoringFunction to score * @param scoringFunction to score
@ -81,15 +79,36 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
/** /**
* Runs insertion. * Runs insertion.
* * <p/>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables. * <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
* *
* @throws java.lang.RuntimeException if smth went wrong with thread execution
*/ */
@Override @Override
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) { public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size()); List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
Iterator<Job> jobIterator = unassignedJobs.iterator();
while (jobIterator.hasNext()){
Job job = jobIterator.next();
if(job instanceof Break){
VehicleRoute route = findRoute(routes,job);
if(route == null){
badJobs.add(job);
}
else {
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
if (iData instanceof InsertionData.NoInsertionFound) {
badJobs.add(job);
} else {
insertJob(job, iData, route);
}
}
jobIterator.remove();
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
while (!jobs.isEmpty()) { while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs); List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>(); List<Job> badJobList = new ArrayList<Job>();
@ -127,34 +146,35 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
for (int i = 0; i < unassignedJobList.size(); i++) { for (int i = 0; i < unassignedJobList.size(); i++) {
Future<ScoredJob> fsj = completionService.take(); Future<ScoredJob> fsj = completionService.take();
ScoredJob sJob = fsj.get(); ScoredJob sJob = fsj.get();
if(sJob instanceof RegretInsertion.BadJob){ if (sJob instanceof ScoredJob.BadJob) {
badJobList.add(sJob.getJob()); badJobList.add(sJob.getJob());
continue; continue;
} }
if (bestScoredJob == null) { if (bestScoredJob == null) {
bestScoredJob = sJob; bestScoredJob = sJob;
} } else if (sJob.getScore() > bestScoredJob.getScore()) {
else if(sJob.getScore() > bestScoredJob.getScore()){ bestScoredJob = sJob;
} else if (sJob.getScore() == bestScoredJob.getScore()) {
if (sJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
bestScoredJob = sJob; bestScoredJob = sJob;
} }
} }
} }
catch(InterruptedException e){ } catch (InterruptedException e) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} } catch (ExecutionException e) {
catch (ExecutionException e) { throw new RuntimeException(e);
e.printStackTrace();
logger.error(e.getCause().toString());
System.exit(1);
} }
return bestScoredJob; return bestScoredJob;
} }
private VehicleRoute findRoute(Collection<VehicleRoute> routes, Job job) {
for(VehicleRoute r : routes){
if(r.getVehicle().getBreak() == job) return r;
}
return null;
}
} }

View file

@ -0,0 +1,196 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.VehicleFleetManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
/**
* Insertion based on regret approach.
* <p/>
* <p>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
*/
public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy {
private static Logger logger = LogManager.getLogger(RegretInsertionConcurrentFast.class);
private ScoringFunction scoringFunction;
private final JobInsertionCostsCalculator insertionCostsCalculator;
private final ExecutorService executor;
private VehicleFleetManager fleetManager;
private Set<String> initialVehicleIds;
private boolean switchAllowed = true;
/**
* Sets the scoring function.
* <p/>
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction to score
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
}
public RegretInsertionConcurrentFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService, VehicleFleetManager fleetManager) {
super(vehicleRoutingProblem);
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem;
this.executor = executorService;
this.fleetManager = fleetManager;
this.initialVehicleIds = getInitialVehicleIds(vehicleRoutingProblem);
logger.debug("initialise " + this);
}
@Override
public String toString() {
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
}
public void setSwitchAllowed(boolean switchAllowed) {
this.switchAllowed = switchAllowed;
}
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
Set<String> ids = new HashSet<String>();
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
ids.add(r.getVehicle().getId());
}
return ids;
}
/**
* Runs insertion.
* <p/>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*
* @throws java.lang.RuntimeException if smth went wrong with thread execution
*/
@Override
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
Iterator<Job> jobIterator = unassignedJobs.iterator();
while (jobIterator.hasNext()){
Job job = jobIterator.next();
if(job instanceof Break){
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
if(route == null){
badJobs.add(job);
}
else {
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
if (iData instanceof InsertionData.NoInsertionFound) {
badJobs.add(job);
} else {
insertJob(job, iData, route);
}
}
jobIterator.remove();
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
VehicleRoute lastModified = null;
boolean firstRun = true;
int updateRound = 0;
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be.");
if(firstRun){
firstRun = false;
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
for(VehicleRoute r : routes) updates.put(r,updateRound);
}
else{
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
updates.put(lastModified,updateRound);
}
updateRound++;
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, scoringFunction, priorityQueues, updates, unassignedJobList, badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
routes.add(bestScoredJob.getRoute());
}
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
jobs.remove(bestScoredJob.getJob());
lastModified = bestScoredJob.getRoute();
}
else lastModified = null;
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
}
}
return badJobs;
}
private void updateInsertionData(final TreeSet<VersionedInsertionData>[] priorityQueues, final Collection<VehicleRoute> routes, List<Job> unassignedJobList, final int updateRound) {
List<Callable<Boolean>> tasks = new ArrayList<Callable<Boolean>>();
for (final Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
}
final TreeSet<VersionedInsertionData> priorityQueue = priorityQueues[unassignedJob.getIndex()];
tasks.add(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return InsertionDataUpdater.update(switchAllowed,initialVehicleIds,fleetManager, insertionCostsCalculator, priorityQueue, updateRound, unassignedJob, routes);
}
});
}
try {
List<Future<Boolean>> futures = executor.invokeAll(tasks);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}

View file

@ -0,0 +1,173 @@
/*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.VehicleFleetManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
/**
* Insertion based on regret approach.
* <p/>
* <p>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
*/
public class RegretInsertionFast extends AbstractInsertionStrategy {
private static Logger logger = LogManager.getLogger(RegretInsertionFast.class);
private ScoringFunction scoringFunction;
private JobInsertionCostsCalculator insertionCostsCalculator;
private VehicleFleetManager fleetManager;
private Set<String> initialVehicleIds;
private boolean switchAllowed = true;
public RegretInsertionFast(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, VehicleFleetManager fleetManager) {
super(vehicleRoutingProblem);
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.insertionCostsCalculator = jobInsertionCalculator;
this.fleetManager = fleetManager;
this.vrp = vehicleRoutingProblem;
this.initialVehicleIds = getInitialVehicleIds(vehicleRoutingProblem);
logger.debug("initialise {}", this);
}
/**
* Sets the scoring function.
* <p/>
* <p>By default, the this.TimeWindowScorer is used.
*
* @param scoringFunction to score
*/
public void setScoringFunction(ScoringFunction scoringFunction) {
this.scoringFunction = scoringFunction;
}
public void setSwitchAllowed(boolean switchAllowed) {
this.switchAllowed = switchAllowed;
}
private Set<String> getInitialVehicleIds(VehicleRoutingProblem vehicleRoutingProblem) {
Set<String> ids = new HashSet<String>();
for(VehicleRoute r : vehicleRoutingProblem.getInitialVehicleRoutes()){
ids.add(r.getVehicle().getId());
}
return ids;
}
@Override
public String toString() {
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
}
/**
* Runs insertion.
* <p/>
* <p>Before inserting a job, all unassigned jobs are scored according to its best- and secondBest-insertion plus additional scoring variables.
*/
@Override
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
Iterator<Job> jobIterator = unassignedJobs.iterator();
while (jobIterator.hasNext()){
Job job = jobIterator.next();
if(job instanceof Break){
VehicleRoute route = InsertionDataUpdater.findRoute(routes, job);
if(route == null){
badJobs.add(job);
}
else {
InsertionData iData = insertionCostsCalculator.getInsertionData(route, job, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, Double.MAX_VALUE);
if (iData instanceof InsertionData.NoInsertionFound) {
badJobs.add(job);
} else {
insertJob(job, iData, route);
}
}
jobIterator.remove();
}
}
List<Job> jobs = new ArrayList<Job>(unassignedJobs);
TreeSet<VersionedInsertionData>[] priorityQueues = new TreeSet[vrp.getJobs().values().size() + 2];
VehicleRoute lastModified = null;
boolean firstRun = true;
int updateRound = 0;
Map<VehicleRoute,Integer> updates = new HashMap<VehicleRoute, Integer>();
while (!jobs.isEmpty()) {
List<Job> unassignedJobList = new ArrayList<Job>(jobs);
List<Job> badJobList = new ArrayList<Job>();
if(!firstRun && lastModified == null) throw new IllegalStateException("fooo");
if(firstRun){
firstRun = false;
updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound);
for(VehicleRoute r : routes) updates.put(r,updateRound);
}
else{
updateInsertionData(priorityQueues, Arrays.asList(lastModified), unassignedJobList, updateRound);
updates.put(lastModified,updateRound);
}
updateRound++;
ScoredJob bestScoredJob = InsertionDataUpdater.getBest(switchAllowed,initialVehicleIds,fleetManager,insertionCostsCalculator,scoringFunction,priorityQueues,updates,unassignedJobList,badJobList);
if (bestScoredJob != null) {
if (bestScoredJob.isNewRoute()) {
routes.add(bestScoredJob.getRoute());
}
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
jobs.remove(bestScoredJob.getJob());
lastModified = bestScoredJob.getRoute();
}
else lastModified = null;
for (Job bad : badJobList) {
jobs.remove(bad);
badJobs.add(bad);
}
}
return badJobs;
}
private void updateInsertionData(TreeSet<VersionedInsertionData>[] priorityQueues, Collection<VehicleRoute> routes, List<Job> unassignedJobList, int updateRound) {
for (Job unassignedJob : unassignedJobList) {
if(priorityQueues[unassignedJob.getIndex()] == null){
priorityQueues[unassignedJob.getIndex()] = new TreeSet<VersionedInsertionData>(InsertionDataUpdater.getComparator());
}
InsertionDataUpdater.update(switchAllowed, initialVehicleIds,fleetManager,insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes);
}
}
}

View file

@ -1,4 +1,3 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder * Copyright (C) 2014 Stefan Schroeder
* *
@ -52,11 +51,15 @@ class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCost
@Override @Override
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) { public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
List<TourActivity> path = new ArrayList<TourActivity>(); List<TourActivity> path = new ArrayList<TourActivity>();
path.add(prevAct); path.add(newAct); path.add(nextAct); path.add(prevAct);
path.add(newAct);
path.add(nextAct);
int actIndex; int actIndex;
if (prevAct instanceof Start) actIndex = 0; if (prevAct instanceof Start) actIndex = 0;
else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(nextAct); else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(nextAct);
if(nuOfActivities2LookForward > 0 && !(nextAct instanceof End)){ path.addAll(getForwardLookingPath(iFacts.getRoute(),actIndex)); } if (nuOfActivities2LookForward > 0 && !(nextAct instanceof End)) {
path.addAll(getForwardLookingPath(iFacts.getRoute(), actIndex));
}
/* /*
* calculates the path costs with new vehicle, c(forwardPath,newVehicle). * calculates the path costs with new vehicle, c(forwardPath,newVehicle).
@ -69,8 +72,7 @@ class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCost
Double cost_at_act; Double cost_at_act;
if (act instanceof End) { if (act instanceof End) {
cost_at_act = stateManager.getRouteState(vehicleRoute, InternalStates.COSTS, Double.class); cost_at_act = stateManager.getRouteState(vehicleRoute, InternalStates.COSTS, Double.class);
} } else {
else{
cost_at_act = stateManager.getActivityState(act, InternalStates.COSTS, Double.class); cost_at_act = stateManager.getActivityState(act, InternalStates.COSTS, Double.class);
} }
if (cost_at_act == null) cost_at_act = 0.; if (cost_at_act == null) cost_at_act = 0.;

View file

@ -0,0 +1,57 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute;
/**
* Created by schroeder on 15/10/15.
*/
class ScoredJob {
static class BadJob extends ScoredJob {
BadJob(Job job) {
super(job, 0., null, null, false);
}
}
private Job job;
private double score;
private InsertionData insertionData;
private VehicleRoute route;
private boolean newRoute;
ScoredJob(Job job, double score, InsertionData insertionData, VehicleRoute route, boolean isNewRoute) {
this.job = job;
this.score = score;
this.insertionData = insertionData;
this.route = route;
this.newRoute = isNewRoute;
}
public boolean isNewRoute() {
return newRoute;
}
public Job getJob() {
return job;
}
public double getScore() {
return score;
}
public InsertionData getInsertionData() {
return insertionData;
}
public VehicleRoute getRoute() {
return route;
}
}

View file

@ -0,0 +1,12 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.job.Job;
/**
* Created by schroeder on 15/10/15.
*/
public interface ScoringFunction {
public double score(InsertionData best, Job job);
}

View file

@ -41,7 +41,6 @@ import java.util.Iterator;
* Calculator that calculates the best insertion position for a {@link Service}. * Calculator that calculates the best insertion position for a {@link Service}.
* *
* @author schroeder * @author schroeder
*
*/ */
final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { final class ServiceInsertionCalculator implements JobInsertionCostsCalculator {
@ -72,7 +71,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
softRouteConstraint = constraintManager; softRouteConstraint = constraintManager;
this.additionalTransportCostsCalculator = additionalTransportCostsCalculator; this.additionalTransportCostsCalculator = additionalTransportCostsCalculator;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts); additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public void setJobActivityFactory(JobActivityFactory jobActivityFactory) { public void setJobActivityFactory(JobActivityFactory jobActivityFactory) {
@ -87,7 +86,6 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
/** /**
* Calculates the marginal cost of inserting job i locally. This is based on the * Calculates the marginal cost of inserting job i locally. This is based on the
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1. * assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
*
*/ */
@Override @Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) { public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {

View file

@ -45,8 +45,6 @@ import java.util.List;
import java.util.PriorityQueue; import java.util.PriorityQueue;
final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator { final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator {
private static final Logger logger = LogManager.getLogger(ServiceInsertionOnRouteLevelCalculator.class); private static final Logger logger = LogManager.getLogger(ServiceInsertionOnRouteLevelCalculator.class);
@ -81,7 +79,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
public void setMemorySize(int memorySize) { public void setMemorySize(int memorySize) {
this.memorySize = memorySize; this.memorySize = memorySize;
logger.debug("set [solutionMemory="+memorySize+"]"); logger.debug("set [solutionMemory={}]", memorySize);
} }
public ServiceInsertionOnRouteLevelCalculator(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteConstraint hardRouteLevelConstraint, HardActivityConstraint hardActivityLevelConstraint) { public ServiceInsertionOnRouteLevelCalculator(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteConstraint hardRouteLevelConstraint, HardActivityConstraint hardActivityLevelConstraint) {
@ -92,7 +90,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
this.hardRouteLevelConstraint = hardRouteLevelConstraint; this.hardRouteLevelConstraint = hardRouteLevelConstraint;
this.hardActivityLevelConstraint = hardActivityLevelConstraint; this.hardActivityLevelConstraint = hardActivityLevelConstraint;
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts); auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts);
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@ -102,7 +100,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
void setNuOfActsForwardLooking(int nOfActsForwardLooking) { void setNuOfActsForwardLooking(int nOfActsForwardLooking) {
this.nuOfActsForwardLooking = nOfActsForwardLooking; this.nuOfActsForwardLooking = nOfActsForwardLooking;
logger.debug("set [forwardLooking="+nOfActsForwardLooking+"]"); logger.debug("set [forwardLooking={}]", nOfActsForwardLooking);
} }
@Override @Override
@ -115,13 +113,13 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
* have local effects but affects the entire route). * have local effects but affects the entire route).
* Calculation is conducted by two steps. In the first step, promising insertion positions are identified by appromiximating their * Calculation is conducted by two steps. In the first step, promising insertion positions are identified by appromiximating their
* marginal insertion cost. In the second step, marginal cost of the best M positions are calculated exactly. * marginal insertion cost. In the second step, marginal cost of the best M positions are calculated exactly.
*
*
*/ */
@Override @Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double best_known_insertion_costs) { public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double best_known_insertion_costs) {
if(jobToInsert == null) throw new IllegalStateException("job is null. cannot calculate the insertion of a null-job."); if (jobToInsert == null)
if(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("no vehicle given. set para vehicle!"); throw new IllegalStateException("job is null. cannot calculate the insertion of a null-job.");
if (newVehicle == null || newVehicle instanceof NoVehicle)
throw new IllegalStateException("no vehicle given. set para vehicle!");
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime); JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) { if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
@ -182,8 +180,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
if (insertion_cost_approximation < best_known_insertion_costs) { if (insertion_cost_approximation < best_known_insertion_costs) {
bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver)); bestInsertionsQueue.add(new InsertionData(insertion_cost_approximation, InsertionData.NO_INDEX, actIndex, newVehicle, newDriver));
} }
} } else if (hardActivityConstraintsStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
else if(hardActivityConstraintsStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
loopBroken = true; loopBroken = true;
break; break;
} }
@ -250,8 +247,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
best_insertion_index = insertion.getDeliveryInsertionIndex(); best_insertion_index = insertion.getDeliveryInsertionIndex();
best_insertion_costs = insertion.getInsertionCost(); best_insertion_costs = insertion.getInsertionCost();
} }
} } else {
else{
for (int i = 0; i < memorySize; i++) { for (int i = 0; i < memorySize; i++) {
InsertionData data = bestInsertionsQueue.poll(); InsertionData data = bestInsertionsQueue.poll();
@ -293,8 +289,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
if (start == null) { if (start == null) {
start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE); start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
start.setEndTime(newVehicleDepartureTime); start.setEndTime(newVehicleDepartureTime);
} } else {
else{
start.setLocation(Location.newInstance(newVehicle.getStartLocation().getId())); start.setLocation(Location.newInstance(newVehicle.getStartLocation().getId()));
start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture()); start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture());
start.setTheoreticalLatestOperationStartTime(Double.MAX_VALUE); start.setTheoreticalLatestOperationStartTime(Double.MAX_VALUE);
@ -303,8 +298,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
if (end == null) { if (end == null) {
end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival()); end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
} } else {
else{
end.setLocation(Location.newInstance(newVehicle.getEndLocation().getId())); end.setLocation(Location.newInstance(newVehicle.getEndLocation().getId()));
end.setTheoreticalEarliestOperationStartTime(0.0); end.setTheoreticalEarliestOperationStartTime(0.0);
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival()); end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
@ -315,8 +309,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
Double prevCost; Double prevCost;
if (act instanceof End) { if (act instanceof End) {
prevCost = stateManager.getRouteState(vehicleRoute, InternalStates.COSTS, Double.class); prevCost = stateManager.getRouteState(vehicleRoute, InternalStates.COSTS, Double.class);
} } else prevCost = stateManager.getActivityState(act, InternalStates.COSTS, Double.class);
else prevCost = stateManager.getActivityState(act, InternalStates.COSTS,Double.class);
if (prevCost == null) prevCost = 0.; if (prevCost == null) prevCost = 0.;
return prevCost; return prevCost;
} }
@ -328,8 +321,7 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
public int compare(InsertionData o1, InsertionData o2) { public int compare(InsertionData o1, InsertionData o2) {
if (o1.getInsertionCost() < o2.getInsertionCost()) { if (o1.getInsertionCost() < o2.getInsertionCost()) {
return -1; return -1;
} } else {
else {
return 1; return 1;
} }

View file

@ -37,8 +37,6 @@ import org.apache.logging.log4j.Logger;
import java.util.List; import java.util.List;
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
private static final Logger logger = LogManager.getLogger(ShipmentInsertionCalculator.class); private static final Logger logger = LogManager.getLogger(ShipmentInsertionCalculator.class);
@ -68,7 +66,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
this.softRouteConstraint = constraintManager; this.softRouteConstraint = constraintManager;
this.transportCosts = routingCosts; this.transportCosts = routingCosts;
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts); additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public void setJobActivityFactory(JobActivityFactory activityFactory) { public void setJobActivityFactory(JobActivityFactory activityFactory) {
@ -83,7 +81,6 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
/** /**
* Calculates the marginal cost of inserting job i locally. This is based on the * Calculates the marginal cost of inserting job i locally. This is based on the
* assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1. * assumption that cost changes can entirely covered by only looking at the predecessor i-1 and its successor i+1.
*
*/ */
@Override @Override
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) { public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownCosts) {
@ -131,12 +128,11 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
TourActivity nextAct; TourActivity nextAct;
if (i < activities.size()) { if (i < activities.size()) {
nextAct = activities.get(i); nextAct = activities.get(i);
} } else {
else{
nextAct = end; nextAct = end;
tourEnd = true; tourEnd = true;
} }
// logger.info("activity: " + i + ", act-size: " + activities.size()); // logger.info("activity: {}, act-size: {}", i, activities.size());
ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime); ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) { if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) {
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActEndTime, newDriver, newVehicle); double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActEndTime, newDriver, newVehicle);
@ -144,8 +140,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
prevAct = nextAct; prevAct = nextAct;
i++; i++;
continue; continue;
} } else if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
else if(pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
break; break;
} }
double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime); double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
@ -174,8 +169,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
TourActivity nextAct_deliveryLoop; TourActivity nextAct_deliveryLoop;
if (j < activities.size()) { if (j < activities.size()) {
nextAct_deliveryLoop = activities.get(j); nextAct_deliveryLoop = activities.get(j);
} } else {
else{
nextAct_deliveryLoop = end; nextAct_deliveryLoop = end;
tourEnd_deliveryLoop = true; tourEnd_deliveryLoop = true;
} }
@ -191,8 +185,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
pickupInsertionIndex = i; pickupInsertionIndex = i;
deliveryInsertionIndex = j; deliveryInsertionIndex = j;
} }
} } else if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
else if(deliverShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
break; break;
} }
//update prevAct and endTime //update prevAct and endTime

View file

@ -1,15 +1,33 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.problem.job.Break;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /**
* Created by schroeder on 19/05/15. * Created by schroeder on 19/05/15.
*/ */
class SwitchVehicleListener implements EventListener { class SwitchVehicleListener implements EventListener {
private static final Logger logger = LogManager.getLogger();
@Override @Override
public void inform(Event event) { public void inform(Event event) {
if (event instanceof SwitchVehicle) { if (event instanceof SwitchVehicle) {
SwitchVehicle switchVehicle = (SwitchVehicle) event; SwitchVehicle switchVehicle = (SwitchVehicle) event;
if (vehiclesDifferent((SwitchVehicle) event)) {
logger.trace("switch vehicle ({} to {})",((SwitchVehicle) event).getRoute().getVehicle().getId(),((SwitchVehicle) event).getVehicle().getId());
Break aBreak = ((SwitchVehicle) event).getRoute().getVehicle().getBreak();
if (aBreak != null) {
boolean removed = ((SwitchVehicle) event).getRoute().getTourActivities().removeJob(aBreak);
if (removed) logger.trace("remove {}",aBreak.getId());
}
}
switchVehicle.getRoute().setVehicleAndDepartureTime(switchVehicle.getVehicle(), ((SwitchVehicle) event).getDepartureTime()); switchVehicle.getRoute().setVehicleAndDepartureTime(switchVehicle.getVehicle(), ((SwitchVehicle) event).getDepartureTime());
} }
} }
private boolean vehiclesDifferent(SwitchVehicle event) {
return !event.getRoute().getVehicle().getId().equals(event.getVehicle().getId());
}
} }

View file

@ -54,8 +54,7 @@ public class VariableTransportCostCalculator implements SoftActivityConstraint{
if (iFacts.getRoute().isEmpty()) { if (iFacts.getRoute().isEmpty()) {
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
oldCosts = tp_costs_prevAct_nextAct; oldCosts = tp_costs_prevAct_nextAct;
} } else {
else{
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
oldCosts = tp_costs_prevAct_nextAct; oldCosts = tp_costs_prevAct_nextAct;
} }

View file

@ -47,11 +47,10 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
/** /**
* true if a vehicle(-type) is allowed to take over the whole route that was previously served by another vehicle * true if a vehicle(-type) is allowed to take over the whole route that was previously served by another vehicle
* * <p/>
* <p>vehicleSwitch allowed makes sense if fleet consists of vehicles with different capacities such that one * <p>vehicleSwitch allowed makes sense if fleet consists of vehicles with different capacities such that one
* can start with a small vehicle, but as the number of customers grows bigger vehicles can be operated, i.e. * can start with a small vehicle, but as the number of customers grows bigger vehicles can be operated, i.e.
* bigger vehicles can take over the route that was previously served by a small vehicle. * bigger vehicles can take over the route that was previously served by a small vehicle.
*
*/ */
private boolean vehicleSwitchAllowed = false; private boolean vehicleSwitchAllowed = false;
@ -94,6 +93,9 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
} }
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) { public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle vehicle, double newVehicleDepartureTime, final Driver driver, final double bestKnownCost) {
if(vehicle != null){
return insertionCalculator.getInsertionData(currentRoute, jobToInsert, vehicle, newVehicleDepartureTime, driver, bestKnownCost);
}
Vehicle selectedVehicle = currentRoute.getVehicle(); Vehicle selectedVehicle = currentRoute.getVehicle();
Driver selectedDriver = currentRoute.getDriver(); Driver selectedDriver = currentRoute.getDriver();
InsertionData bestIData = InsertionData.createEmptyInsertionData(); InsertionData bestIData = InsertionData.createEmptyInsertionData();
@ -104,8 +106,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
if (vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)) { if (vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)) {
relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle)); relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle));
} }
} } else { //if no vehicle has been assigned, i.e. it is an empty route
else{ //if no vehicle has been assigned, i.e. it is an empty route
relevantVehicles.addAll(fleetManager.getAvailableVehicles()); relevantVehicles.addAll(fleetManager.getAvailableVehicles());
} }
for (Vehicle v : relevantVehicles) { for (Vehicle v : relevantVehicles) {
@ -124,6 +125,10 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
return bestIData; return bestIData;
} }
VehicleFleetManager getFleetManager(){
return fleetManager;
}
private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) { private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) {
return initialVehicleIds.contains(selectedVehicle.getId()); return initialVehicleIds.contains(selectedVehicle.getId());
} }

View file

@ -0,0 +1,33 @@
package jsprit.core.algorithm.recreate;
import jsprit.core.problem.solution.route.VehicleRoute;
/**
* Created by schroeder on 15/10/15.
*/
class VersionedInsertionData {
private InsertionData iData;
private VehicleRoute route;
private int version;
public VersionedInsertionData(InsertionData iData, int version, VehicleRoute route) {
this.iData = iData;
this.version = version;
this.route = route;
}
public InsertionData getiData() {
return iData;
}
public int getVersion() {
return version;
}
public VehicleRoute getRoute() {
return route;
}
}

View file

@ -21,7 +21,6 @@ import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection; import java.util.Collection;
public interface InsertionEndsListener extends InsertionListener { public interface InsertionEndsListener extends InsertionListener {
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes); public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes);

View file

@ -19,11 +19,7 @@ package jsprit.core.algorithm.recreate.listener;
import jsprit.core.algorithm.listener.SearchStrategyModuleListener; import jsprit.core.algorithm.listener.SearchStrategyModuleListener;
public interface InsertionListener extends SearchStrategyModuleListener { public interface InsertionListener extends SearchStrategyModuleListener {
} }

View file

@ -22,7 +22,6 @@ import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection; import java.util.Collection;
public interface InsertionStartsListener extends InsertionListener { public interface InsertionStartsListener extends InsertionListener {
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs); public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);

View file

@ -20,10 +20,6 @@ import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
public interface JobInsertedListener extends InsertionListener { public interface JobInsertedListener extends InsertionListener {
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime); public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime);

View file

@ -63,7 +63,7 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes) { public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes) {
ruinListeners.ruinStarts(vehicleRoutes); ruinListeners.ruinStarts(vehicleRoutes);
Collection<Job> unassigned = ruinRoutes(vehicleRoutes); Collection<Job> unassigned = ruinRoutes(vehicleRoutes);
logger.trace("ruin: " + "[ruined=" + unassigned.size() + "]"); logger.trace("ruin: [ruined={}]", unassigned.size());
ruinListeners.ruinEnds(vehicleRoutes, unassigned); ruinListeners.ruinEnds(vehicleRoutes, unassigned);
return unassigned; return unassigned;
} }
@ -116,7 +116,7 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
if (jobIsInitial(job)) return false; if (jobIsInitial(job)) return false;
boolean removed = route.getTourActivities().removeJob(job); boolean removed = route.getTourActivities().removeJob(job);
if (removed) { if (removed) {
logger.trace("ruin: " + job.getId()); logger.trace("ruin: {}", job.getId());
ruinListeners.removed(job, route); ruinListeners.removed(job, route);
return true; return true;
} }

View file

@ -3,8 +3,6 @@ package jsprit.core.algorithm.ruin;
import jsprit.core.problem.Location; import jsprit.core.problem.Location;
import jsprit.core.problem.cost.VehicleRoutingTransportCosts; import jsprit.core.problem.cost.VehicleRoutingTransportCosts;
import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.job.Shipment;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.util.RandomNumberGeneration; import jsprit.core.util.RandomNumberGeneration;
@ -30,24 +28,24 @@ public class DBSCANClusterer {
private int id; private int id;
public LocationWrapper(Job job) { public LocationWrapper(Job job, List<Location> locations) {
this.locations = getLocations(job); this.locations = locations;
objCounter++; objCounter++;
this.job = job; this.job = job;
this.id = objCounter; this.id = objCounter;
} }
private List<Location> getLocations(Job job){ // private List<Location> getLocations(Job job){
List<Location> locs = new ArrayList<Location>(); // List<Location> locs = new ArrayList<Location>();
if(job instanceof Service) { // if(job instanceof Service) {
locs.add(((Service) job).getLocation()); // locs.add(((Service) job).getLocation());
} // }
else if(job instanceof Shipment){ // else if(job instanceof Shipment){
locs.add(((Shipment) job).getPickupLocation()); // locs.add(((Shipment) job).getPickupLocation());
locs.add(((Shipment) job).getDeliveryLocation()); // locs.add(((Shipment) job).getDeliveryLocation());
} // }
return locs; // return locs;
} // }
public List<Location> getLocations() { public List<Location> getLocations() {
return locations; return locations;
@ -126,14 +124,29 @@ public class DBSCANClusterer {
} }
public List<List<Job>> getClusters(VehicleRoute route) { public List<List<Job>> getClusters(VehicleRoute route) {
List<LocationWrapper> locations = new ArrayList<LocationWrapper>(route.getTourActivities().getJobs().size()); List<LocationWrapper> locations = getLocationWrappers(route);
for(Job j : route.getTourActivities().getJobs()){
locations.add(new LocationWrapper(j));
}
List<Cluster<LocationWrapper>> clusterResults = getClusters(route, locations); List<Cluster<LocationWrapper>> clusterResults = getClusters(route, locations);
return makeList(clusterResults); return makeList(clusterResults);
} }
private List<LocationWrapper> getLocationWrappers(VehicleRoute route) {
List<LocationWrapper> locations = new ArrayList<LocationWrapper>(route.getTourActivities().getJobs().size());
Map<Job, List<Location>> jobs2locations = new HashMap<Job, List<Location>>();
for (TourActivity act : route.getActivities()) {
if (act instanceof TourActivity.JobActivity) {
Job job = ((TourActivity.JobActivity) act).getJob();
if (!jobs2locations.containsKey(job)) {
jobs2locations.put(job, new ArrayList<Location>());
}
jobs2locations.get(job).add(act.getLocation());
}
}
for (Job j : jobs2locations.keySet()) {
locations.add(new LocationWrapper(j, jobs2locations.get(j)));
}
return locations;
}
private List<Cluster<LocationWrapper>> getClusters(VehicleRoute route, List<LocationWrapper> locations) { private List<Cluster<LocationWrapper>> getClusters(VehicleRoute route, List<LocationWrapper> locations) {
double sampledDistance; double sampledDistance;
if (epsDistance != null) sampledDistance = epsDistance; if (epsDistance != null) sampledDistance = epsDistance;
@ -162,10 +175,7 @@ public class DBSCANClusterer {
public List<Job> getRandomCluster(VehicleRoute route) { public List<Job> getRandomCluster(VehicleRoute route) {
if (route.isEmpty()) return Collections.emptyList(); if (route.isEmpty()) return Collections.emptyList();
List<LocationWrapper> locations = new ArrayList<LocationWrapper>(route.getTourActivities().getJobs().size()); List<LocationWrapper> locations = getLocationWrappers(route);
for(Job j : route.getTourActivities().getJobs()){
locations.add(new LocationWrapper(j));
}
List<Cluster<LocationWrapper>> clusterResults = getClusters(route, locations); List<Cluster<LocationWrapper>> clusterResults = getClusters(route, locations);
if (clusterResults.isEmpty()) return Collections.emptyList(); if (clusterResults.isEmpty()) return Collections.emptyList();
Cluster<LocationWrapper> randomCluster = RandomUtils.nextItem(clusterResults, random); Cluster<LocationWrapper> randomCluster = RandomUtils.nextItem(clusterResults, random);

View file

@ -13,4 +13,6 @@ public interface JobNeighborhoods {
public void initialise(); public void initialise();
public double getMaxDistance();
} }

View file

@ -22,11 +22,13 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
private JobDistance jobDistance; private JobDistance jobDistance;
private double maxDistance = 0.;
public JobNeighborhoodsImpl(VehicleRoutingProblem vrp, JobDistance jobDistance) { public JobNeighborhoodsImpl(VehicleRoutingProblem vrp, JobDistance jobDistance) {
super(); super();
this.vrp = vrp; this.vrp = vrp;
this.jobDistance = jobDistance; this.jobDistance = jobDistance;
logger.debug("intialise " + this); logger.debug("intialise {}", this);
} }
@Override @Override
@ -58,6 +60,11 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
calculateDistancesFromJob2Job(); calculateDistancesFromJob2Job();
} }
@Override
public double getMaxDistance() {
return 0;
}
private void calculateDistancesFromJob2Job() { private void calculateDistancesFromJob2Job() {
logger.debug("preprocess distances between locations ..."); logger.debug("preprocess distances between locations ...");
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
@ -79,6 +86,7 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
for (Job j : vrp.getJobs().values()) { for (Job j : vrp.getJobs().values()) {
if (i == j) continue; if (i == j) continue;
double distance = jobDistance.getDistance(i, j); double distance = jobDistance.getDistance(i, j);
if (distance > maxDistance) maxDistance = distance;
ReferencedJob refNode = new ReferencedJob(j, distance); ReferencedJob refNode = new ReferencedJob(j, distance);
treeSet.add(refNode); treeSet.add(refNode);
nuOfDistancesStored++; nuOfDistancesStored++;
@ -86,8 +94,8 @@ class JobNeighborhoodsImpl implements JobNeighborhoods {
} }
stopWatch.stop(); stopWatch.stop();
logger.debug("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " + logger.debug("preprocessing comp-time: {}; nuOfDistances stored: {}; estimated memory: {}" +
(distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes"); " bytes", stopWatch, nuOfDistancesStored, (distanceNodeTree.keySet().size() * 64 + nuOfDistancesStored * 92));
} }
} }

View file

@ -24,12 +24,14 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
private int capacity; private int capacity;
private double maxDistance = 0.;
public JobNeighborhoodsImplWithCapRestriction(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) { public JobNeighborhoodsImplWithCapRestriction(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) {
super(); super();
this.vrp = vrp; this.vrp = vrp;
this.jobDistance = jobDistance; this.jobDistance = jobDistance;
this.capacity = capacity; this.capacity = capacity;
logger.debug("intialise " + this); logger.debug("initialize {}", this);
} }
@Override @Override
@ -59,11 +61,16 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
@Override @Override
public void initialise() { public void initialise() {
logger.debug("calculates distances from EACH job to EACH job --> n^2="+Math.pow(vrp.getJobs().values().size(), 2) + " calculations, but 'only' "+(vrp.getJobs().values().size()*capacity)+ " are cached."); logger.debug("calculates distances from EACH job to EACH job --> n^2={} calculations, but 'only' {} are cached.", Math.pow(vrp.getJobs().values().size(), 2), (vrp.getJobs().values().size() * capacity));
if (capacity == 0) return; if (capacity == 0) return;
calculateDistancesFromJob2Job(); calculateDistancesFromJob2Job();
} }
@Override
public double getMaxDistance() {
return maxDistance;
}
private void calculateDistancesFromJob2Job() { private void calculateDistancesFromJob2Job() {
logger.debug("preprocess distances between locations ..."); logger.debug("preprocess distances between locations ...");
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
@ -85,12 +92,12 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
for (Job j : vrp.getJobs().values()) { for (Job j : vrp.getJobs().values()) {
if (i == j) continue; if (i == j) continue;
double distance = jobDistance.getDistance(i, j); double distance = jobDistance.getDistance(i, j);
if (distance > maxDistance) maxDistance = distance;
ReferencedJob refNode = new ReferencedJob(j, distance); ReferencedJob refNode = new ReferencedJob(j, distance);
if (treeSet.size() < capacity) { if (treeSet.size() < capacity) {
treeSet.add(refNode); treeSet.add(refNode);
nuOfDistancesStored++; nuOfDistancesStored++;
} } else {
else{
if (treeSet.last().getDistance() > distance) { if (treeSet.last().getDistance() > distance) {
treeSet.pollLast(); treeSet.pollLast();
treeSet.add(refNode); treeSet.add(refNode);
@ -101,8 +108,8 @@ class JobNeighborhoodsImplWithCapRestriction implements JobNeighborhoods {
} }
stopWatch.stop(); stopWatch.stop();
logger.debug("preprocessing comp-time: " + stopWatch + "; nuOfDistances stored: " + nuOfDistancesStored + "; estimated memory: " + logger.debug("preprocessing comp-time: {}; nuOfDistances stored: {}; estimated memory: {}" +
(distanceNodeTree.keySet().size()*64+nuOfDistancesStored*92) + " bytes"); " bytes", stopWatch, nuOfDistancesStored, (distanceNodeTree.keySet().size() * 64 + nuOfDistancesStored * 92));
} }
@Override @Override

View file

@ -29,7 +29,8 @@ class NearestNeighborhoodIterator implements Iterator<Job> {
public boolean hasNext() { public boolean hasNext() {
if (jobCount < nJobs) { if (jobCount < nJobs) {
boolean hasNext = jobIter.hasNext(); boolean hasNext = jobIter.hasNext();
if(!hasNext) log.warn("more jobs are requested then iterator can iterate over. probably the number of neighbors memorized in JobNeighborhoods is too small"); if (!hasNext)
log.warn("more jobs are requested then iterator can iterate over. probably the number of neighbors memorized in JobNeighborhoods is too small");
return hasNext; return hasNext;
} }
return false; return false;

View file

@ -0,0 +1,38 @@
package jsprit.core.algorithm.ruin;
import jsprit.core.algorithm.ruin.listener.RuinListener;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Collection;
/**
* Created by schroeder on 04/08/15.
*/
public class RuinBreaks implements RuinListener {
private final static Logger logger = LogManager.getLogger();
@Override
public void ruinStarts(Collection<VehicleRoute> routes) {
}
@Override
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
for (VehicleRoute r : routes) {
Break aBreak = r.getVehicle().getBreak();
if (aBreak != null) {
r.getTourActivities().removeJob(aBreak);
logger.trace("ruin: {}", aBreak.getId());
unassignedJobs.add(aBreak);
}
}
}
@Override
public void removed(Job job, VehicleRoute fromRoute) {
}
}

View file

@ -35,7 +35,6 @@ import java.util.*;
* customer are removed randomly from current solution. * customer are removed randomly from current solution.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public final class RuinClusters extends AbstractRuinStrategy implements IterationStartsListener { public final class RuinClusters extends AbstractRuinStrategy implements IterationStartsListener {
@ -87,7 +86,7 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio
} }
}); });
this.jobNeighborhoods = jobNeighborhoods; this.jobNeighborhoods = jobNeighborhoods;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public void setNoClusters(int noClusters) { public void setNoClusters(int noClusters) {
@ -96,7 +95,7 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio
/** /**
* Removes a fraction of jobs from vehicleRoutes. * Removes a fraction of jobs from vehicleRoutes.
* * <p/>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined). * <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/ */
@Override @Override
@ -116,6 +115,7 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio
} }
private void ruin(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2BeRemoved, List<Job> unassignedJobs) { private void ruin(Collection<VehicleRoute> vehicleRoutes, int nOfJobs2BeRemoved, List<Job> unassignedJobs) {
if (vrp.getJobs().values().size() == 0) return;
Map<Job, VehicleRoute> mappedRoutes = map(vehicleRoutes); Map<Job, VehicleRoute> mappedRoutes = map(vehicleRoutes);
int toRemove = nOfJobs2BeRemoved; int toRemove = nOfJobs2BeRemoved;
@ -129,8 +129,7 @@ public final class RuinClusters extends AbstractRuinStrategy implements Iteratio
if (lastRemoved.isEmpty()) { if (lastRemoved.isEmpty()) {
target = RandomUtils.nextJob(vrp.getJobs().values(), random); target = RandomUtils.nextJob(vrp.getJobs().values(), random);
targetRoute = mappedRoutes.get(target); targetRoute = mappedRoutes.get(target);
} } else {
else{
target = RandomUtils.nextJob(lastRemoved, random); target = RandomUtils.nextJob(lastRemoved, random);
Iterator<Job> neighborIterator = jobNeighborhoods.getNearestNeighborsIterator(nOfJobs2BeRemoved, target); Iterator<Job> neighborIterator = jobNeighborhoods.getNearestNeighborsIterator(nOfJobs2BeRemoved, target);
while (neighborIterator.hasNext()) { while (neighborIterator.hasNext()) {

View file

@ -28,13 +28,11 @@ import java.util.*;
/** /**
*
* RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by * RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by
* the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary * the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary
* measure). * measure).
* *
* @author stefan * @author stefan
*
*/ */
public final class RuinRadial extends AbstractRuinStrategy { public final class RuinRadial extends AbstractRuinStrategy {
@ -68,7 +66,7 @@ public final class RuinRadial extends AbstractRuinStrategy {
JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, noJobsToMemorize); JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, noJobsToMemorize);
jobNeighborhoodsImpl.initialise(); jobNeighborhoodsImpl.initialise();
jobNeighborhoods = jobNeighborhoodsImpl; jobNeighborhoods = jobNeighborhoodsImpl;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public RuinRadial(VehicleRoutingProblem vrp, int noJobs2beRemoved, JobDistance jobDistance) { public RuinRadial(VehicleRoutingProblem vrp, int noJobs2beRemoved, JobDistance jobDistance) {
@ -87,7 +85,7 @@ public final class RuinRadial extends AbstractRuinStrategy {
JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, noJobsToMemorize); JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, noJobsToMemorize);
jobNeighborhoodsImpl.initialise(); jobNeighborhoodsImpl.initialise();
jobNeighborhoods = jobNeighborhoodsImpl; jobNeighborhoods = jobNeighborhoodsImpl;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public RuinRadial(VehicleRoutingProblem vrp, int noJobs2beRemoved, JobNeighborhoods neighborhoods) { public RuinRadial(VehicleRoutingProblem vrp, int noJobs2beRemoved, JobNeighborhoods neighborhoods) {
@ -103,7 +101,7 @@ public final class RuinRadial extends AbstractRuinStrategy {
}; };
jobNeighborhoods = neighborhoods; jobNeighborhoods = neighborhoods;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@Override @Override
@ -130,6 +128,7 @@ public final class RuinRadial extends AbstractRuinStrategy {
/** /**
* Removes targetJob and its neighborhood and returns the removed jobs. * Removes targetJob and its neighborhood and returns the removed jobs.
*
* @deprecated will be private * @deprecated will be private
*/ */
@Deprecated @Deprecated

View file

@ -27,13 +27,11 @@ import java.util.*;
/** /**
*
* RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by * RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by
* the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary * the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary
* measure). * measure).
* *
* @author stefan * @author stefan
*
*/ */
public final class RuinRadialMultipleCenters extends AbstractRuinStrategy { public final class RuinRadialMultipleCenters extends AbstractRuinStrategy {
@ -62,7 +60,7 @@ public final class RuinRadialMultipleCenters extends AbstractRuinStrategy {
JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, noJobsToMemorize); JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, noJobsToMemorize);
jobNeighborhoodsImpl.initialise(); jobNeighborhoodsImpl.initialise();
jobNeighborhoods = jobNeighborhoodsImpl; jobNeighborhoods = jobNeighborhoodsImpl;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
public void setNumberOfRuinCenters(int noCenters) { public void setNumberOfRuinCenters(int noCenters) {
@ -100,6 +98,7 @@ public final class RuinRadialMultipleCenters extends AbstractRuinStrategy {
/** /**
* Removes targetJob and its neighborhood and returns the removed jobs. * Removes targetJob and its neighborhood and returns the removed jobs.
*
* @deprecated will be private * @deprecated will be private
*/ */
@Deprecated @Deprecated
@ -129,8 +128,7 @@ public final class RuinRadialMultipleCenters extends AbstractRuinStrategy {
for (Job j : available) { for (Job j : available) {
if (i >= randomIndex) { if (i >= randomIndex) {
return j; return j;
} } else i++;
else i++;
} }
return null; return null;
} }

View file

@ -33,7 +33,6 @@ import java.util.List;
* customer are removed randomly from current solution. * customer are removed randomly from current solution.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public final class RuinRandom extends AbstractRuinStrategy { public final class RuinRandom extends AbstractRuinStrategy {
@ -60,12 +59,12 @@ public final class RuinRandom extends AbstractRuinStrategy {
return selectNuOfJobs2BeRemoved(); return selectNuOfJobs2BeRemoved();
} }
}); });
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
/** /**
* Removes a fraction of jobs from vehicleRoutes. * Removes a fraction of jobs from vehicleRoutes.
* * <p/>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined). * <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/ */
@Override @Override

View file

@ -23,13 +23,8 @@ import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection; import java.util.Collection;
/** /**
*
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public interface RuinStrategy { public interface RuinStrategy {

View file

@ -34,7 +34,6 @@ import java.util.*;
* customer are removed randomly from current solution. * customer are removed randomly from current solution.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public final class RuinWorst extends AbstractRuinStrategy { public final class RuinWorst extends AbstractRuinStrategy {
@ -64,12 +63,12 @@ public final class RuinWorst extends AbstractRuinStrategy {
return initialNumberJobsToRemove; return initialNumberJobsToRemove;
} }
}); });
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
/** /**
* Removes a fraction of jobs from vehicleRoutes. * Removes a fraction of jobs from vehicleRoutes.
* * <p/>
* <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined). * <p>The number of jobs is calculated as follows: Math.ceil(vrp.getJobs().values().size() * fractionOfAllNodes2beRuined).
*/ */
@Override @Override
@ -120,8 +119,7 @@ public final class RuinWorst extends AbstractRuinStrategy {
Job job = ((TourActivity.JobActivity) actToEval).getJob(); Job job = ((TourActivity.JobActivity) actToEval).getJob();
if (!savingsMap.containsKey(job)) { if (!savingsMap.containsKey(job)) {
savingsMap.put(job, savings); savingsMap.put(job, savings);
} } else {
else {
double s = savingsMap.get(job); double s = savingsMap.get(job);
savingsMap.put(job, s + savings); savingsMap.put(job, s + savings);
} }
@ -132,8 +130,7 @@ public final class RuinWorst extends AbstractRuinStrategy {
Job job = ((TourActivity.JobActivity) actToEval).getJob(); Job job = ((TourActivity.JobActivity) actToEval).getJob();
if (!savingsMap.containsKey(job)) { if (!savingsMap.containsKey(job)) {
savingsMap.put(job, savings); savingsMap.put(job, savings);
} } else {
else {
double s = savingsMap.get(job); double s = savingsMap.get(job);
savingsMap.put(job, s + savings); savingsMap.put(job, s + savings);
} }

View file

@ -24,14 +24,12 @@ import jsprit.core.problem.job.Shipment;
import jsprit.core.util.EuclideanDistanceCalculator; import jsprit.core.util.EuclideanDistanceCalculator;
/** /**
* Calculator that calculates average distance between two jobs based on the input-transport costs. * Calculator that calculates average distance between two jobs based on the input-transport costs.
* * <p/>
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs. * <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class AvgServiceAndShipmentDistance implements JobDistance { public class AvgServiceAndShipmentDistance implements JobDistance {
@ -45,7 +43,7 @@ public class AvgServiceAndShipmentDistance implements JobDistance {
/** /**
* Calculates and returns the average distance between two jobs based on the input-transport costs. * Calculates and returns the average distance between two jobs based on the input-transport costs.
* * <p/>
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs. * <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
*/ */
@Override @Override
@ -54,17 +52,13 @@ public class AvgServiceAndShipmentDistance implements JobDistance {
if (i instanceof Service && j instanceof Service) { if (i instanceof Service && j instanceof Service) {
return calcDist((Service) i, (Service) j); return calcDist((Service) i, (Service) j);
} } else if (i instanceof Service && j instanceof Shipment) {
else if(i instanceof Service && j instanceof Shipment){
return calcDist((Service) i, (Shipment) j); return calcDist((Service) i, (Shipment) j);
} } else if (i instanceof Shipment && j instanceof Service) {
else if(i instanceof Shipment && j instanceof Service){
return calcDist((Service) j, (Shipment) i); return calcDist((Service) j, (Shipment) i);
} } else if (i instanceof Shipment && j instanceof Shipment) {
else if(i instanceof Shipment && j instanceof Shipment){
return calcDist((Shipment) i, (Shipment) j); return calcDist((Shipment) i, (Shipment) j);
} } else {
else{
throw new IllegalStateException("this supports only shipments or services"); throw new IllegalStateException("this supports only shipments or services");
} }
} }
@ -90,8 +84,7 @@ public class AvgServiceAndShipmentDistance implements JobDistance {
private double calcDist(Location location_i, Location location_j) { private double calcDist(Location location_i, Location location_j) {
try { try {
return costs.getTransportCost(location_i, location_j, 0.0, null, null); return costs.getTransportCost(location_i, location_j, 0.0, null, null);
} } catch (IllegalStateException e) {
catch(IllegalStateException e){
// now try the euclidean distance between these two services // now try the euclidean distance between these two services
} }
return EuclideanDistanceCalculator.calculateDistance(location_i.getCoordinate(), location_j.getCoordinate()); return EuclideanDistanceCalculator.calculateDistance(location_i.getCoordinate(), location_j.getCoordinate());

Some files were not shown because too many files have changed in this diff Show more