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:
parent
0b3b07a7de
commit
02c3c96e9c
523 changed files with 77426 additions and 74576 deletions
13
.editorconfig
Normal file
13
.editorconfig
Normal 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
|
||||||
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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++) {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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("---------------------------------------------------------------------");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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("---------------------------------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -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)) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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.;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,6 @@ public interface JobNeighborhoods {
|
||||||
|
|
||||||
public void initialise();
|
public void initialise();
|
||||||
|
|
||||||
|
public double getMaxDistance();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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()) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue