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,74 +1,75 @@
|
||||||
<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"
|
||||||
<parent>
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<groupId>jsprit</groupId>
|
<parent>
|
||||||
<artifactId>jsprit</artifactId>
|
<groupId>jsprit</groupId>
|
||||||
<version>1.6.1-SNAPSHOT</version>
|
<artifactId>jsprit</artifactId>
|
||||||
</parent>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
</parent>
|
||||||
<artifactId>jsprit-analysis</artifactId>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<packaging>jar</packaging>
|
<artifactId>jsprit-analysis</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.m2e</groupId>
|
<groupId>org.eclipse.m2e</groupId>
|
||||||
<artifactId>lifecycle-mapping</artifactId>
|
<artifactId>lifecycle-mapping</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<lifecycleMappingMetadata>
|
<lifecycleMappingMetadata>
|
||||||
<pluginExecutions>
|
<pluginExecutions>
|
||||||
<pluginExecution>
|
<pluginExecution>
|
||||||
<pluginExecutionFilter>
|
<pluginExecutionFilter>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-enforcer-plugin</artifactId>
|
<artifactId>maven-enforcer-plugin</artifactId>
|
||||||
<versionRange>[1.0.0,)</versionRange>
|
<versionRange>[1.0.0,)</versionRange>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>enforce</goal>
|
<goal>enforce</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</pluginExecutionFilter>
|
</pluginExecutionFilter>
|
||||||
<action>
|
<action>
|
||||||
<ignore />
|
<ignore/>
|
||||||
</action>
|
</action>
|
||||||
</pluginExecution>
|
</pluginExecution>
|
||||||
</pluginExecutions>
|
</pluginExecutions>
|
||||||
</lifecycleMappingMetadata>
|
</lifecycleMappingMetadata>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<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>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>jsprit-core</artifactId>
|
<artifactId>jsprit-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<type>jar</type>
|
<type>jar</type>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>gs-core</artifactId>
|
<artifactId>gs-core</artifactId>
|
||||||
<groupId>org.graphstream</groupId>
|
<groupId>org.graphstream</groupId>
|
||||||
<version>1.3</version>
|
<version>1.3</version>
|
||||||
<optional>false</optional>
|
<optional>false</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<artifactId>gs-ui</artifactId>
|
<artifactId>gs-ui</artifactId>
|
||||||
<groupId>org.graphstream</groupId>
|
<groupId>org.graphstream</groupId>
|
||||||
<version>1.3</version>
|
<version>1.3</version>
|
||||||
<optional>false</optional>
|
<optional>false</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -89,11 +89,10 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
File dgsFile = new File(dgsFileLocation);
|
File dgsFile = new File(dgsFileLocation);
|
||||||
fos = new FileOutputStream(dgsFile);
|
fos = new FileOutputStream(dgsFile);
|
||||||
fileSink = new FileSinkDGS();
|
fileSink = new FileSinkDGS();
|
||||||
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);
|
||||||
|
|
@ -109,37 +108,37 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
new AlgorithmEventsRecorder(vrp, dgsFileLocation);
|
new AlgorithmEventsRecorder(vrp, dgsFileLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRecordingRange(int startIteration, int endIteration){
|
public void setRecordingRange(int startIteration, int endIteration) {
|
||||||
this.start_recording_at = startIteration;
|
this.start_recording_at = startIteration;
|
||||||
this.end_recording_at = endIteration;
|
this.end_recording_at = endIteration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void ruinStarts(Collection<VehicleRoute> routes) {
|
public void ruinStarts(Collection<VehicleRoute> routes) {
|
||||||
if(!record()) return;
|
if (!record()) return;
|
||||||
fileSink.stepBegins(graph.getId(),0,BEFORE_RUIN_RENDER_SOLUTION);
|
fileSink.stepBegins(graph.getId(), 0, BEFORE_RUIN_RENDER_SOLUTION);
|
||||||
markAllNodesAsInserted();
|
markAllNodesAsInserted();
|
||||||
addRoutes(routes);
|
addRoutes(routes);
|
||||||
fileSink.stepBegins(graph.getId(),0,RUIN);
|
fileSink.stepBegins(graph.getId(), 0, RUIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markAllNodesAsInserted() {
|
private void markAllNodesAsInserted() {
|
||||||
for(Job j : vrp.getJobs().values()){
|
for (Job j : vrp.getJobs().values()) {
|
||||||
markInserted(j);
|
markInserted(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRoutes(Collection<VehicleRoute> routes) {
|
private void addRoutes(Collection<VehicleRoute> routes) {
|
||||||
for(VehicleRoute route : routes){
|
for (VehicleRoute route : routes) {
|
||||||
String prevNode = makeStartId(route.getVehicle());
|
String prevNode = makeStartId(route.getVehicle());
|
||||||
for(TourActivity act : route.getActivities()){
|
for (TourActivity act : route.getActivities()) {
|
||||||
String actNodeId = getNodeId(act);
|
String actNodeId = getNodeId(act);
|
||||||
addEdge(prevNode+"_"+actNodeId,prevNode,actNodeId);
|
addEdge(prevNode + "_" + actNodeId, prevNode, actNodeId);
|
||||||
prevNode = actNodeId;
|
prevNode = actNodeId;
|
||||||
}
|
}
|
||||||
if(route.getVehicle().isReturnToDepot()) {
|
if (route.getVehicle().isReturnToDepot()) {
|
||||||
String lastNode = makeEndId(route.getVehicle());
|
String lastNode = makeEndId(route.getVehicle());
|
||||||
addEdge(prevNode+"_"+lastNode,prevNode,lastNode);
|
addEdge(prevNode + "_" + lastNode, prevNode, lastNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -147,13 +146,12 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
private String getNodeId(TourActivity act) {
|
private String getNodeId(TourActivity act) {
|
||||||
String nodeId = null;
|
String nodeId = null;
|
||||||
if(act instanceof TourActivity.JobActivity){
|
if (act instanceof TourActivity.JobActivity) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,28 +169,29 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removed(Job job, VehicleRoute fromRoute) {
|
public void removed(Job job, VehicleRoute fromRoute) {
|
||||||
if(!record()) return;
|
if (!record()) return;
|
||||||
if(job instanceof Service) removeService(job, fromRoute);
|
if (job instanceof Service) removeService(job, fromRoute);
|
||||||
else if(job instanceof Shipment) removeShipment(job,fromRoute);
|
else if (job instanceof Shipment) removeShipment(job, fromRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeShipment(Job job, VehicleRoute fromRoute) {
|
private void removeShipment(Job job, VehicleRoute fromRoute) {
|
||||||
Shipment shipment = (Shipment)job;
|
Shipment shipment = (Shipment) job;
|
||||||
String fromNodeId = getFromNodeId(shipment);
|
String fromNodeId = getFromNodeId(shipment);
|
||||||
String toNodeId = getToNodeId(shipment);
|
String toNodeId = getToNodeId(shipment);
|
||||||
// removeNodeAndBelongingEdges(fromNodeId,fromRoute);
|
// removeNodeAndBelongingEdges(fromNodeId,fromRoute);
|
||||||
// removeNodeAndBelongingEdges(toNodeId,fromRoute);
|
// removeNodeAndBelongingEdges(toNodeId,fromRoute);
|
||||||
|
|
||||||
Edge enteringToNode = getEnteringEdge(toNodeId);
|
Edge enteringToNode = getEnteringEdge(toNodeId);
|
||||||
if(enteringToNode.getNode0().getId().equals(fromNodeId)){
|
if (enteringToNode.getNode0().getId().equals(fromNodeId)) {
|
||||||
markRemoved(graph.getNode(fromNodeId));
|
markRemoved(graph.getNode(fromNodeId));
|
||||||
markRemoved(graph.getNode(toNodeId));
|
markRemoved(graph.getNode(toNodeId));
|
||||||
// i -> from -> to -> j: rem(i,from), rem(from,to), rem(to,j), add(i,j)
|
// i -> from -> to -> j: rem(i,from), rem(from,to), rem(to,j), add(i,j)
|
||||||
Edge enteringFromNode = getEnteringEdge(fromNodeId);
|
Edge enteringFromNode = getEnteringEdge(fromNodeId);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,22 +199,23 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
removeEdge(leavingToNode.getId());
|
removeEdge(leavingToNode.getId());
|
||||||
Node from = enteringFromNode.getNode0();
|
Node from = enteringFromNode.getNode0();
|
||||||
Node to = leavingToNode.getNode1();
|
Node to = leavingToNode.getNode1();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Edge getLeavingEdge(String toNodeId) {
|
private Edge getLeavingEdge(String toNodeId) {
|
||||||
Collection<Edge> edges = graph.getNode(toNodeId).getLeavingEdgeSet();
|
Collection<Edge> edges = graph.getNode(toNodeId).getLeavingEdgeSet();
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -224,10 +224,12 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
private Edge getEnteringEdge(String toNodeId) {
|
private Edge getEnteringEdge(String toNodeId) {
|
||||||
Collection<Edge> enteringEdges = graph.getNode(toNodeId).getEnteringEdgeSet();
|
Collection<Edge> enteringEdges = graph.getNode(toNodeId).getEnteringEdgeSet();
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -253,8 +255,8 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
Edge entering = getEnteringEdge(nodeId);
|
Edge entering = getEnteringEdge(nodeId);
|
||||||
removeEdge(entering.getId());
|
removeEdge(entering.getId());
|
||||||
|
|
||||||
if(node.getLeavingEdgeSet().isEmpty()){
|
if (node.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,13 +264,13 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
removeEdge((leaving.getId()));
|
removeEdge((leaving.getId()));
|
||||||
Node from = entering.getNode0();
|
Node from = entering.getNode0();
|
||||||
Node to = leaving.getNode1();
|
Node to = leaving.getNode1();
|
||||||
if(!fromRoute.getActivities().isEmpty()){
|
if (!fromRoute.getActivities().isEmpty()) {
|
||||||
addEdge(makeEdgeId(from,to),from.getId(),to.getId());
|
addEdge(makeEdgeId(from, to), from.getId(), to.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markRemoved(Node node) {
|
private void markRemoved(Node node) {
|
||||||
node.setAttribute("ui.class","removed");
|
node.setAttribute("ui.class", "removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String makeEdgeId(Node from, Node to) {
|
private String makeEdgeId(Node from, Node to) {
|
||||||
|
|
@ -278,7 +280,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
|
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
|
||||||
fileSink.stepBegins(graph.getId(),0,BEFORE_RUIN_RENDER_SOLUTION);
|
fileSink.stepBegins(graph.getId(), 0, BEFORE_RUIN_RENDER_SOLUTION);
|
||||||
addRoutes(solution.getRoutes());
|
addRoutes(solution.getRoutes());
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +289,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
try {
|
try {
|
||||||
fileSink.end();
|
fileSink.end();
|
||||||
fos.close();
|
fos.close();
|
||||||
if(gzipOs != null) gzipOs.close();
|
if (gzipOs != null) gzipOs.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
@ -299,28 +301,27 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseGraph(VehicleRoutingProblem problem) {
|
private void initialiseGraph(VehicleRoutingProblem problem) {
|
||||||
for(Vehicle vehicle : problem.getVehicles()){
|
for (Vehicle vehicle : problem.getVehicles()) {
|
||||||
addVehicle(vehicle);
|
addVehicle(vehicle);
|
||||||
}
|
}
|
||||||
for(Job job : problem.getJobs().values()){
|
for (Job job : problem.getJobs().values()) {
|
||||||
addJob(job);
|
addJob(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addJob(Job job) {
|
private void addJob(Job job) {
|
||||||
if(job instanceof Service){
|
if (job instanceof Service) {
|
||||||
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());
|
||||||
String toNodeId = getToNodeId(shipment);
|
String toNodeId = getToNodeId(shipment);
|
||||||
addNode(toNodeId,shipment.getDeliveryLocation().getCoordinate());
|
addNode(toNodeId, shipment.getDeliveryLocation().getCoordinate());
|
||||||
markShipment(shipment);
|
markShipment(shipment);
|
||||||
if(renderShipments) {
|
if (renderShipments) {
|
||||||
Edge e = graph.addEdge("shipment_" + fromNodeId + "_" + toNodeId, fromNodeId, toNodeId, true);
|
Edge e = graph.addEdge("shipment_" + fromNodeId + "_" + toNodeId, fromNodeId, toNodeId, true);
|
||||||
e.addAttribute("ui.class", "shipment");
|
e.addAttribute("ui.class", "shipment");
|
||||||
}
|
}
|
||||||
|
|
@ -333,35 +334,34 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markPickup(String id) {
|
private void markPickup(String id) {
|
||||||
graph.getNode(id).addAttribute("ui.class","pickup");
|
graph.getNode(id).addAttribute("ui.class", "pickup");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markDelivery(String id) {
|
private void markDelivery(String id) {
|
||||||
graph.getNode(id).addAttribute("ui.class","delivery");
|
graph.getNode(id).addAttribute("ui.class", "delivery");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addVehicle(Vehicle vehicle) {
|
private void addVehicle(Vehicle vehicle) {
|
||||||
String startId = makeStartId(vehicle);
|
String startId = makeStartId(vehicle);
|
||||||
Node node = graph.addNode(startId);
|
Node node = graph.addNode(startId);
|
||||||
node.addAttribute("x",vehicle.getStartLocation().getCoordinate().getX());
|
node.addAttribute("x", vehicle.getStartLocation().getCoordinate().getX());
|
||||||
node.addAttribute("y", vehicle.getStartLocation().getCoordinate().getY());
|
node.addAttribute("y", vehicle.getStartLocation().getCoordinate().getY());
|
||||||
node.addAttribute("ui.class","depot");
|
node.addAttribute("ui.class", "depot");
|
||||||
|
|
||||||
String endId = makeEndId(vehicle);
|
String endId = makeEndId(vehicle);
|
||||||
if(!startId.equals(endId)){
|
if (!startId.equals(endId)) {
|
||||||
Node endNode = graph.addNode(endId);
|
Node endNode = graph.addNode(endId);
|
||||||
endNode.addAttribute("x", vehicle.getEndLocation().getCoordinate().getX());
|
endNode.addAttribute("x", vehicle.getEndLocation().getCoordinate().getX());
|
||||||
endNode.addAttribute("y", vehicle.getEndLocation().getCoordinate().getY());
|
endNode.addAttribute("y", vehicle.getEndLocation().getCoordinate().getY());
|
||||||
endNode.addAttribute("ui.class","depot");
|
endNode.addAttribute("ui.class", "depot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,7 +370,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
}
|
}
|
||||||
|
|
||||||
private String makeEndId(Vehicle vehicle) {
|
private String makeEndId(Vehicle vehicle) {
|
||||||
if(vehicle.getStartLocation().getId().equals(vehicle.getEndLocation().getId())) return makeStartId(vehicle);
|
if (vehicle.getStartLocation().getId().equals(vehicle.getEndLocation().getId())) return makeStartId(vehicle);
|
||||||
return vehicle.getId() + "_end";
|
return vehicle.getId() + "_end";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -382,20 +382,20 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
if(!record()) return;
|
if (!record()) return;
|
||||||
fileSink.stepBegins(graph.getId(),0,CLEAR_SOLUTION);
|
fileSink.stepBegins(graph.getId(), 0, CLEAR_SOLUTION);
|
||||||
removeRoutes(vehicleRoutes);
|
removeRoutes(vehicleRoutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeRoutes(Collection<VehicleRoute> vehicleRoutes) {
|
private void removeRoutes(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
for (VehicleRoute route : vehicleRoutes) {
|
||||||
String prevNode = makeStartId(route.getVehicle());
|
String prevNode = makeStartId(route.getVehicle());
|
||||||
for(TourActivity act : route.getActivities()){
|
for (TourActivity act : route.getActivities()) {
|
||||||
String actNode = getNodeId(act);
|
String actNode = getNodeId(act);
|
||||||
removeEdge(prevNode + "_" + actNode);
|
removeEdge(prevNode + "_" + actNode);
|
||||||
prevNode = actNode;
|
prevNode = actNode;
|
||||||
}
|
}
|
||||||
if(route.getVehicle().isReturnToDepot()) {
|
if (route.getVehicle().isReturnToDepot()) {
|
||||||
String lastNode = makeEndId(route.getVehicle());
|
String lastNode = makeEndId(route.getVehicle());
|
||||||
removeEdge(prevNode + "_" + lastNode);
|
removeEdge(prevNode + "_" + lastNode);
|
||||||
}
|
}
|
||||||
|
|
@ -404,25 +404,25 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
|
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
|
||||||
if(!record()) return;
|
if (!record()) return;
|
||||||
markInserted(job);
|
markInserted(job);
|
||||||
handleVehicleSwitch(data, route);
|
handleVehicleSwitch(data, route);
|
||||||
insertJob(job, data, route);
|
insertJob(job, data, route);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertJob(Job job, InsertionData data, VehicleRoute route) {
|
private void insertJob(Job job, InsertionData data, VehicleRoute route) {
|
||||||
if(job instanceof Service) insertService(job,data,route);
|
if (job instanceof Service) insertService(job, data, route);
|
||||||
else if(job instanceof Shipment) insertShipment(job,data,route);
|
else if (job instanceof Shipment) insertShipment(job, data, route);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertShipment(Job job, InsertionData data, VehicleRoute route) {
|
private void insertShipment(Job job, InsertionData data, VehicleRoute route) {
|
||||||
String fromNodeId = getFromNodeId((Shipment) job);
|
String fromNodeId = getFromNodeId((Shipment) job);
|
||||||
String toNodeId = getToNodeId((Shipment) job);
|
String toNodeId = getToNodeId((Shipment) job);
|
||||||
insertNode(toNodeId,data.getDeliveryInsertionIndex(),data,route);
|
insertNode(toNodeId, data.getDeliveryInsertionIndex(), data, route);
|
||||||
|
|
||||||
List<AbstractActivity> del = vrp.getActivities(job);
|
List<AbstractActivity> del = vrp.getActivities(job);
|
||||||
VehicleRoute copied = VehicleRoute.copyOf(route);
|
VehicleRoute copied = VehicleRoute.copyOf(route);
|
||||||
copied.getTourActivities().addActivity(data.getDeliveryInsertionIndex(),del.get(1));
|
copied.getTourActivities().addActivity(data.getDeliveryInsertionIndex(), del.get(1));
|
||||||
|
|
||||||
insertNode(fromNodeId, data.getPickupInsertionIndex(), data, copied);
|
insertNode(fromNodeId, data.getPickupInsertionIndex(), data, copied);
|
||||||
}
|
}
|
||||||
|
|
@ -436,19 +436,17 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
String node_i;
|
String node_i;
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
String edgeId_1 = node_i + "_" + nodeId;
|
String edgeId_1 = node_i + "_" + nodeId;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
@ -456,7 +454,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
addEdge(edgeId_1, node_i, nodeId);
|
addEdge(edgeId_1, node_i, nodeId);
|
||||||
|
|
||||||
if(!(isLast(insertionIndex,route) && !data.getSelectedVehicle().isReturnToDepot())) {
|
if (!(isLast(insertionIndex, route) && !data.getSelectedVehicle().isReturnToDepot())) {
|
||||||
addEdge(edgeId_2, nodeId, node_j);
|
addEdge(edgeId_2, nodeId, node_j);
|
||||||
if (!route.getActivities().isEmpty()) {
|
if (!route.getActivities().isEmpty()) {
|
||||||
removeEdge(node_i + "_" + node_j);
|
removeEdge(node_i + "_" + node_j);
|
||||||
|
|
@ -466,38 +464,37 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
|
|
||||||
private void handleVehicleSwitch(InsertionData data, VehicleRoute route) {
|
private void handleVehicleSwitch(InsertionData data, VehicleRoute route) {
|
||||||
boolean vehicleSwitch = false;
|
boolean vehicleSwitch = false;
|
||||||
if(!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||||
if (!route.getVehicle().getId().equals(data.getSelectedVehicle().getId())) {
|
if (!route.getVehicle().getId().equals(data.getSelectedVehicle().getId())) {
|
||||||
vehicleSwitch = true;
|
vehicleSwitch = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(vehicleSwitch && !route.getActivities().isEmpty()){
|
if (vehicleSwitch && !route.getActivities().isEmpty()) {
|
||||||
String oldStart = makeStartId(route.getVehicle());
|
String oldStart = makeStartId(route.getVehicle());
|
||||||
String firstAct = ((TourActivity.JobActivity)route.getActivities().get(0)).getJob().getId();
|
String firstAct = ((TourActivity.JobActivity) route.getActivities().get(0)).getJob().getId();
|
||||||
String oldEnd = makeEndId(route.getVehicle());
|
String oldEnd = makeEndId(route.getVehicle());
|
||||||
String lastAct = ((TourActivity.JobActivity)route.getActivities().get(route.getActivities().size()-1)).getJob().getId();
|
String lastAct = ((TourActivity.JobActivity) route.getActivities().get(route.getActivities().size() - 1)).getJob().getId();
|
||||||
removeEdge(oldStart + "_" + firstAct);
|
removeEdge(oldStart + "_" + firstAct);
|
||||||
|
|
||||||
if(route.getVehicle().isReturnToDepot()) {
|
if (route.getVehicle().isReturnToDepot()) {
|
||||||
removeEdge(lastAct + "_" + oldEnd);
|
removeEdge(lastAct + "_" + oldEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
String newStart = makeStartId(data.getSelectedVehicle());
|
String newStart = makeStartId(data.getSelectedVehicle());
|
||||||
String newEnd = makeEndId(data.getSelectedVehicle());
|
String newEnd = makeEndId(data.getSelectedVehicle());
|
||||||
addEdge(newStart + "_" + firstAct,newStart,firstAct);
|
addEdge(newStart + "_" + firstAct, newStart, firstAct);
|
||||||
|
|
||||||
if(data.getSelectedVehicle().isReturnToDepot()) {
|
if (data.getSelectedVehicle().isReturnToDepot()) {
|
||||||
addEdge(lastAct + "_" + newEnd, lastAct, newEnd);
|
addEdge(lastAct + "_" + newEnd, lastAct, newEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,7 +504,7 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markEdgeRemoved(String edgeId) {
|
private void markEdgeRemoved(String edgeId) {
|
||||||
graph.getEdge(edgeId).addAttribute("ui.class","removed");
|
graph.getEdge(edgeId).addAttribute("ui.class", "removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFirst(int index) {
|
private boolean isFirst(int index) {
|
||||||
|
|
@ -518,19 +515,19 @@ public class AlgorithmEventsRecorder implements RuinListener, IterationStartsLis
|
||||||
return index == route.getActivities().size();
|
return index == route.getActivities().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addEdge(String edgeId, String fromNode, String toNode) {
|
private void addEdge(String edgeId, String fromNode, String toNode) {
|
||||||
graph.addEdge(edgeId,fromNode,toNode,true);
|
graph.addEdge(edgeId, fromNode, toNode, true);
|
||||||
markEdgeInserted(edgeId);
|
markEdgeInserted(edgeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markEdgeInserted(String edgeId) {
|
private void markEdgeInserted(String edgeId) {
|
||||||
graph.getEdge(edgeId).addAttribute("ui.class","inserted");
|
graph.getEdge(edgeId).addAttribute("ui.class", "inserted");
|
||||||
graph.getEdge(edgeId).removeAttribute("ui.class");
|
graph.getEdge(edgeId).removeAttribute("ui.class");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
if(!record()) return;
|
if (!record()) return;
|
||||||
fileSink.stepBegins(graph.getId(),0,RECREATE);
|
fileSink.stepBegins(graph.getId(), 0, RECREATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class AlgorithmEventsViewer {
|
||||||
this.delayContainer = delayContainer;
|
this.delayContainer = delayContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRuinDelay(long ruinDelay){
|
public void setRuinDelay(long ruinDelay) {
|
||||||
this.ruinDelay = ruinDelay;
|
this.ruinDelay = ruinDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,16 +131,14 @@ public class AlgorithmEventsViewer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stepBegins(String sourceId, long timeId, double step) {
|
public void stepBegins(String sourceId, long timeId, double step) {
|
||||||
if(step == AlgorithmEventsRecorder.RECREATE) {
|
if (step == AlgorithmEventsRecorder.RECREATE) {
|
||||||
delayContainer.delay = recreateDelay;
|
delayContainer.delay = recreateDelay;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -156,15 +154,15 @@ public class AlgorithmEventsViewer {
|
||||||
|
|
||||||
private long delay = 2;
|
private long delay = 2;
|
||||||
|
|
||||||
public void setRecreationDelay(long delay_in_ms){
|
public void setRecreationDelay(long delay_in_ms) {
|
||||||
this.delayRecreation = delay_in_ms;
|
this.delayRecreation = delay_in_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRuinDelay(long delay_in_ms){
|
public void setRuinDelay(long delay_in_ms) {
|
||||||
this.delayRuin = delay_in_ms;
|
this.delayRuin = delay_in_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void display(String dgsFile){
|
public void display(String dgsFile) {
|
||||||
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
|
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
|
||||||
Graph graph = GraphStreamViewer.createMultiGraph("g", GraphStreamViewer.StyleSheets.BLUE_FOREST);
|
Graph graph = GraphStreamViewer.createMultiGraph("g", GraphStreamViewer.StyleSheets.BLUE_FOREST);
|
||||||
Viewer viewer = graph.display();
|
Viewer viewer = graph.display();
|
||||||
|
|
@ -185,13 +183,13 @@ public class AlgorithmEventsViewer {
|
||||||
while (fs.nextEvents()) {
|
while (fs.nextEvents()) {
|
||||||
sleep(delayContainer.delay);
|
sleep(delayContainer.delay);
|
||||||
}
|
}
|
||||||
} catch( IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.end();
|
fs.end();
|
||||||
} catch( IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
fs.removeSink(graph);
|
fs.removeSink(graph);
|
||||||
|
|
|
||||||
|
|
@ -30,59 +30,58 @@ 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 {
|
||||||
|
|
||||||
private static Logger log = LogManager.getLogger(AlgorithmSearchProgressChartListener.class);
|
private static Logger log = LogManager.getLogger(AlgorithmSearchProgressChartListener.class);
|
||||||
|
|
||||||
private String filename;
|
private String filename;
|
||||||
|
|
||||||
private XYLineChartBuilder chartBuilder;
|
private XYLineChartBuilder chartBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs chart listener with target png-file (filename plus path).
|
* Constructs chart listener with target png-file (filename plus path).
|
||||||
*
|
*
|
||||||
* @param pngFileName
|
* @param pngFileName
|
||||||
*/
|
*/
|
||||||
public AlgorithmSearchProgressChartListener(String pngFileName) {
|
public AlgorithmSearchProgressChartListener(String pngFileName) {
|
||||||
super();
|
super();
|
||||||
this.filename = pngFileName;
|
this.filename = pngFileName;
|
||||||
if(!this.filename.endsWith("png")){
|
if (!this.filename.endsWith("png")) {
|
||||||
this.filename += ".png";
|
this.filename += ".png";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
double worst = 0.0;
|
double worst = 0.0;
|
||||||
double best = Double.MAX_VALUE;
|
double best = Double.MAX_VALUE;
|
||||||
double sum = 0.0;
|
double sum = 0.0;
|
||||||
for(VehicleRoutingProblemSolution sol : solutions){
|
for (VehicleRoutingProblemSolution sol : solutions) {
|
||||||
if(sol.getCost() > worst) worst = Math.min(sol.getCost(),Double.MAX_VALUE);
|
if (sol.getCost() > worst) worst = Math.min(sol.getCost(), Double.MAX_VALUE);
|
||||||
if(sol.getCost() < best) best = sol.getCost();
|
if (sol.getCost() < best) best = sol.getCost();
|
||||||
sum += Math.min(sol.getCost(),Double.MAX_VALUE);
|
sum += Math.min(sol.getCost(), Double.MAX_VALUE);
|
||||||
}
|
}
|
||||||
chartBuilder.addData("best", i, best);
|
chartBuilder.addData("best", i, best);
|
||||||
chartBuilder.addData("worst", i, worst);
|
chartBuilder.addData("worst", i, worst);
|
||||||
chartBuilder.addData("avg", i, sum/(double)solutions.size());
|
chartBuilder.addData("avg", i, sum / (double) solutions.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmStarts(VehicleRoutingProblem problem,VehicleRoutingAlgorithm algorithm,Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
chartBuilder = XYLineChartBuilder.newInstance("search-progress", "iterations", "results");
|
chartBuilder = XYLineChartBuilder.newInstance("search-progress", "iterations", "results");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,433 +33,444 @@ import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class ComputationalLaboratory {
|
public class ComputationalLaboratory {
|
||||||
|
|
||||||
public static interface LabListener {
|
public static interface LabListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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{
|
|
||||||
|
|
||||||
public void calculationStarts(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run);
|
public void calculationStarts(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run);
|
||||||
|
|
||||||
public void calculationEnds(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run, final Collection<VehicleRoutingProblemSolution> solutions);
|
public void calculationEnds(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run, final Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static interface LabStartsAndEndsListener extends LabListener {
|
public static interface LabStartsAndEndsListener extends LabListener {
|
||||||
|
|
||||||
public void labStarts(List<BenchmarkInstance> instances, int noAlgorithms, int runs);
|
public void labStarts(List<BenchmarkInstance> instances, int noAlgorithms, int runs);
|
||||||
|
|
||||||
public void labEnds();
|
public void labEnds();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 {
|
|
||||||
|
|
||||||
public static class Key {
|
public static class Key {
|
||||||
private String instanceName;
|
private String instanceName;
|
||||||
private String algorithmName;
|
private String algorithmName;
|
||||||
private int run;
|
private int run;
|
||||||
private String indicatorName;
|
private String indicatorName;
|
||||||
|
|
||||||
public Key(String instanceName, String algorithmName, int run,String indicatorName) {
|
public Key(String instanceName, String algorithmName, int run, String indicatorName) {
|
||||||
super();
|
super();
|
||||||
this.instanceName = instanceName;
|
this.instanceName = instanceName;
|
||||||
this.algorithmName = algorithmName;
|
this.algorithmName = algorithmName;
|
||||||
this.run = run;
|
this.run = run;
|
||||||
this.indicatorName = indicatorName;
|
this.indicatorName = indicatorName;
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime
|
|
||||||
* result
|
|
||||||
+ ((algorithmName == null) ? 0 : algorithmName
|
|
||||||
.hashCode());
|
|
||||||
result = prime
|
|
||||||
* result
|
|
||||||
+ ((indicatorName == null) ? 0 : indicatorName
|
|
||||||
.hashCode());
|
|
||||||
result = prime
|
|
||||||
* result
|
|
||||||
+ ((instanceName == null) ? 0 : instanceName.hashCode());
|
|
||||||
result = prime * result + run;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
Key other = (Key) obj;
|
|
||||||
if (algorithmName == null) {
|
|
||||||
if (other.algorithmName != null)
|
|
||||||
return false;
|
|
||||||
} else if (!algorithmName.equals(other.algorithmName))
|
|
||||||
return false;
|
|
||||||
if (indicatorName == null) {
|
|
||||||
if (other.indicatorName != null)
|
|
||||||
return false;
|
|
||||||
} else if (!indicatorName.equals(other.indicatorName))
|
|
||||||
return false;
|
|
||||||
if (instanceName == null) {
|
|
||||||
if (other.instanceName != null)
|
|
||||||
return false;
|
|
||||||
} else if (!instanceName.equals(other.instanceName))
|
|
||||||
return false;
|
|
||||||
if (run != other.run)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
public String getInstanceName() {
|
|
||||||
return instanceName;
|
|
||||||
}
|
|
||||||
public String getAlgorithmName() {
|
|
||||||
return algorithmName;
|
|
||||||
}
|
|
||||||
public int getRun() {
|
|
||||||
return run;
|
|
||||||
}
|
|
||||||
public String getIndicatorName() {
|
|
||||||
return indicatorName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public int hashCode() {
|
||||||
return "[algorithm="+algorithmName+"][instance="+instanceName+"][run="+run+"][indicator="+indicatorName+"]";
|
final int prime = 31;
|
||||||
}
|
int result = 1;
|
||||||
|
result = prime
|
||||||
|
* result
|
||||||
|
+ ((algorithmName == null) ? 0 : algorithmName
|
||||||
|
.hashCode());
|
||||||
|
result = prime
|
||||||
|
* result
|
||||||
|
+ ((indicatorName == null) ? 0 : indicatorName
|
||||||
|
.hashCode());
|
||||||
|
result = prime
|
||||||
|
* result
|
||||||
|
+ ((instanceName == null) ? 0 : instanceName.hashCode());
|
||||||
|
result = prime * result + run;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Key other = (Key) obj;
|
||||||
|
if (algorithmName == null) {
|
||||||
|
if (other.algorithmName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!algorithmName.equals(other.algorithmName))
|
||||||
|
return false;
|
||||||
|
if (indicatorName == null) {
|
||||||
|
if (other.indicatorName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!indicatorName.equals(other.indicatorName))
|
||||||
|
return false;
|
||||||
|
if (instanceName == null) {
|
||||||
|
if (other.instanceName != null)
|
||||||
|
return false;
|
||||||
|
} else if (!instanceName.equals(other.instanceName))
|
||||||
|
return false;
|
||||||
|
if (run != other.run)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private final static String SOLUTION_INDICATOR_NAME = "vehicle-routing-problem-solution";
|
public String getInstanceName() {
|
||||||
|
return instanceName;
|
||||||
|
}
|
||||||
|
|
||||||
private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>();
|
public String getAlgorithmName() {
|
||||||
|
return algorithmName;
|
||||||
|
}
|
||||||
|
|
||||||
private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>();
|
public int getRun() {
|
||||||
/**
|
return run;
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @param instanceName
|
|
||||||
* @param algorithmName
|
|
||||||
* @param run
|
|
||||||
* @param indicatorName
|
|
||||||
* @param 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.");
|
|
||||||
Key key = new Key(instanceName,algorithmName,run,indicatorName);
|
|
||||||
data.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSolution(String instanceName, String algorithmName, int run, VehicleRoutingProblemSolution solution){
|
public String getIndicatorName() {
|
||||||
Key key = new Key(instanceName,algorithmName,run,SOLUTION_INDICATOR_NAME);
|
return indicatorName;
|
||||||
solutions.put(key, solution);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Returns a collections of indicator values representing the calculated values of individual runs.
|
public String toString() {
|
||||||
*
|
return "[algorithm=" + algorithmName + "][instance=" + instanceName + "][run=" + run + "][indicator=" + indicatorName + "]";
|
||||||
* @param instanceName
|
}
|
||||||
* @param algorithmName
|
|
||||||
* @param indicator
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Collection<Double> getData(String instanceName, String algorithmName, String indicator){
|
|
||||||
List<Double> values = new ArrayList<Double>();
|
|
||||||
for(Key key : data.keySet()){
|
|
||||||
if(key.getAlgorithmName().equals(algorithmName) && key.getInstanceName().equals(instanceName) && key.getIndicatorName().equals(indicator)){
|
|
||||||
values.add(data.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Returns indicator value.
|
|
||||||
*
|
|
||||||
* @param instanceName
|
|
||||||
* @param algorithmName
|
|
||||||
* @param run
|
|
||||||
* @param indicator
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Double getDate(String instanceName, String algorithmName, int run, String indicator){
|
|
||||||
return data.get(new Key(instanceName,algorithmName,run,indicator));
|
|
||||||
}
|
|
||||||
|
|
||||||
public VehicleRoutingProblemSolution getSolution(String instanceName, String algorithmName, int run){
|
private final static String SOLUTION_INDICATOR_NAME = "vehicle-routing-problem-solution";
|
||||||
return solutions.get(new Key(instanceName,algorithmName,run,"solution"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>();
|
||||||
* Returns all keys that have been created. A key is a unique combination of algorithmName, instanceName, run and indicator.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Set<Key> getDataKeySet(){
|
|
||||||
return data.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<Key> getSolutionKeySet(){
|
private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>();
|
||||||
return solutions.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public VehicleRoutingProblemSolution getSolution(Key solutionKey){
|
/**
|
||||||
return solutions.get(solutionKey);
|
* 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.
|
||||||
|
*
|
||||||
|
* @param instanceName
|
||||||
|
* @param algorithmName
|
||||||
|
* @param run
|
||||||
|
* @param indicatorName
|
||||||
|
* @param 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.");
|
||||||
|
Key key = new Key(instanceName, algorithmName, run, indicatorName);
|
||||||
|
data.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<VehicleRoutingProblemSolution> getSolutions(){
|
public void addSolution(String instanceName, String algorithmName, int run, VehicleRoutingProblemSolution solution) {
|
||||||
return solutions.values();
|
Key key = new Key(instanceName, algorithmName, run, SOLUTION_INDICATOR_NAME);
|
||||||
}
|
solutions.put(key, solution);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns date associated to specified key.
|
* Returns a collections of indicator values representing the calculated values of individual runs.
|
||||||
*
|
*
|
||||||
* @param key
|
* @param instanceName
|
||||||
* @return
|
* @param algorithmName
|
||||||
*/
|
* @param indicator
|
||||||
public Double getData(Key key){
|
* @return
|
||||||
return data.get(key);
|
*/
|
||||||
}
|
public Collection<Double> getData(String instanceName, String algorithmName, String indicator) {
|
||||||
|
List<Double> values = new ArrayList<Double>();
|
||||||
|
for (Key key : data.keySet()) {
|
||||||
|
if (key.getAlgorithmName().equals(algorithmName) && key.getInstanceName().equals(instanceName) && key.getIndicatorName().equals(indicator)) {
|
||||||
|
values.add(data.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Returns indicator value.
|
||||||
|
*
|
||||||
|
* @param instanceName
|
||||||
|
* @param algorithmName
|
||||||
|
* @param run
|
||||||
|
* @param indicator
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Double getDate(String instanceName, String algorithmName, int run, String indicator) {
|
||||||
|
return data.get(new Key(instanceName, algorithmName, run, indicator));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingProblemSolution getSolution(String instanceName, String algorithmName, int run) {
|
||||||
|
return solutions.get(new Key(instanceName, algorithmName, run, "solution"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all keys that have been created. A key is a unique combination of algorithmName, instanceName, run and indicator.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Set<Key> getDataKeySet() {
|
||||||
|
return data.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Key> getSolutionKeySet() {
|
||||||
|
return solutions.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public VehicleRoutingProblemSolution getSolution(Key solutionKey) {
|
||||||
|
return solutions.get(solutionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<VehicleRoutingProblemSolution> getSolutions() {
|
||||||
|
return solutions.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns date associated to specified key.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Double getData(Key key) {
|
||||||
|
return data.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class Algorithm {
|
private static class Algorithm {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private VehicleRoutingAlgorithmFactory factory;
|
private VehicleRoutingAlgorithmFactory factory;
|
||||||
|
|
||||||
public Algorithm(String name, VehicleRoutingAlgorithmFactory factory) {
|
public Algorithm(String name, VehicleRoutingAlgorithmFactory factory) {
|
||||||
super();
|
super();
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
|
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
|
||||||
|
|
||||||
private int runs = 1;
|
private int runs = 1;
|
||||||
|
|
||||||
private Collection<CalculationListener> listeners = new ArrayList<ComputationalLaboratory.CalculationListener>();
|
private Collection<CalculationListener> listeners = new ArrayList<ComputationalLaboratory.CalculationListener>();
|
||||||
|
|
||||||
private Collection<LabStartsAndEndsListener> startsAndEndslisteners = new ArrayList<LabStartsAndEndsListener>();
|
private Collection<LabStartsAndEndsListener> startsAndEndslisteners = new ArrayList<LabStartsAndEndsListener>();
|
||||||
|
|
||||||
private List<Algorithm> algorithms = new ArrayList<ComputationalLaboratory.Algorithm>();
|
private List<Algorithm> algorithms = new ArrayList<ComputationalLaboratory.Algorithm>();
|
||||||
|
|
||||||
private Set<String> algorithmNames = new HashSet<String>();
|
private Set<String> algorithmNames = new HashSet<String>();
|
||||||
|
|
||||||
private Set<String> instanceNames = new HashSet<String>();
|
private Set<String> instanceNames = new HashSet<String>();
|
||||||
|
|
||||||
private int threads = 1;
|
private int threads = 1;
|
||||||
|
|
||||||
public ComputationalLaboratory() {
|
public ComputationalLaboratory() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds algorithmFactory by name.
|
* Adds algorithmFactory by name.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* @param factory
|
* @param factory
|
||||||
* @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))
|
||||||
algorithms.add(new Algorithm(name,factory));
|
throw new IllegalStateException("there is already a algorithmFactory with the same name (algorithmName=" + name + "). unique names are required.");
|
||||||
algorithmNames.add(name);
|
algorithms.add(new Algorithm(name, factory));
|
||||||
}
|
algorithmNames.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
public Collection<String> getAlgorithmNames() {
|
public Collection<String> getAlgorithmNames() {
|
||||||
return algorithmNames;
|
return algorithmNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<String> getInstanceNames(){
|
public Collection<String> getInstanceNames() {
|
||||||
return instanceNames;
|
return instanceNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds instance by name.
|
* Adds instance by name.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* @param problem
|
* @param problem
|
||||||
* @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))
|
||||||
benchmarkInstances.add(new BenchmarkInstance(name,problem,null,null));
|
throw new IllegalStateException("there is already an instance with the same name (instanceName=" + name + "). unique names are required.");
|
||||||
instanceNames.add(name);
|
benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null));
|
||||||
}
|
instanceNames.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds instance.
|
* Adds instance.
|
||||||
*
|
*
|
||||||
* @param instance the instance to be added
|
* @param instance the instance to be added
|
||||||
* @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))
|
||||||
benchmarkInstances.add(instance);
|
throw new IllegalStateException("there is already an instance with the same name (instanceName=" + instance.name + "). unique names are required.");
|
||||||
instanceNames.add(instance.name);
|
benchmarkInstances.add(instance);
|
||||||
}
|
instanceNames.add(instance.name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds collection of instances.
|
* Adds collection of instances.
|
||||||
*
|
*
|
||||||
* @param instances collection of instances to be added
|
* @param instances collection of instances to be added
|
||||||
* @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 addAllInstances(Collection<BenchmarkInstance> instances){
|
public void addAllInstances(Collection<BenchmarkInstance> instances) {
|
||||||
for(BenchmarkInstance i : instances){
|
for (BenchmarkInstance i : instances) {
|
||||||
addInstance(i);
|
addInstance(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds instance by name, and with best known results.
|
* Adds instance by name, and with best known results.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* @param problem
|
* @param problem
|
||||||
* @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, Double bestKnownResult, Double bestKnownVehicles){
|
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles) {
|
||||||
addInstance(new BenchmarkInstance(name,problem,bestKnownResult,bestKnownVehicles));
|
addInstance(new BenchmarkInstance(name, problem, bestKnownResult, bestKnownVehicles));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds listener to listen computational experiments.
|
* Adds listener to listen computational experiments.
|
||||||
*
|
*
|
||||||
* @param listener
|
* @param listener
|
||||||
*/
|
*/
|
||||||
public void addListener(LabListener listener){
|
public void addListener(LabListener listener) {
|
||||||
if(listener instanceof CalculationListener) {
|
if (listener instanceof CalculationListener) {
|
||||||
listeners.add((CalculationListener) listener);
|
listeners.add((CalculationListener) listener);
|
||||||
}
|
}
|
||||||
if(listener instanceof LabStartsAndEndsListener){
|
if (listener instanceof LabStartsAndEndsListener) {
|
||||||
startsAndEndslisteners.add((LabStartsAndEndsListener) listener);
|
startsAndEndslisteners.add((LabStartsAndEndsListener) listener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets nuOfRuns with same algorithm on same instance.
|
* Sets nuOfRuns with same algorithm on same instance.
|
||||||
* <p>Default is 1
|
* <p>Default is 1
|
||||||
*
|
*
|
||||||
* @param runs
|
* @param runs
|
||||||
*/
|
*/
|
||||||
public void setNuOfRuns(int runs){
|
public void setNuOfRuns(int runs) {
|
||||||
this.runs = runs;
|
this.runs = runs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* with three threads then "myAlgorithm","myInstance",run1 runs on the first thread, "myAlgorithm", "myInstance", run2 on the second etc.
|
* with three threads then "myAlgorithm","myInstance",run1 runs on the first thread, "myAlgorithm", "myInstance", run2 on the second etc.
|
||||||
* <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()) {
|
||||||
throw new IllegalStateException("no algorithm specified. at least one algorithm needs to be specified.");
|
throw new IllegalStateException("no algorithm specified. at least one algorithm needs to be specified.");
|
||||||
}
|
}
|
||||||
if(benchmarkInstances.isEmpty()){
|
if (benchmarkInstances.isEmpty()) {
|
||||||
throw new IllegalStateException("no instance specified. at least one instance needs to be specified.");
|
throw new IllegalStateException("no instance specified. at least one instance needs to be specified.");
|
||||||
}
|
}
|
||||||
informStart();
|
informStart();
|
||||||
System.out.println("start benchmarking [nuAlgorithms="+algorithms.size()+"][nuInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
|
System.out.println("start benchmarking [nuAlgorithms=" + algorithms.size() + "][nuInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
|
||||||
double startTime = System.currentTimeMillis();
|
double startTime = System.currentTimeMillis();
|
||||||
ExecutorService executor = Executors.newFixedThreadPool(threads);
|
ExecutorService executor = Executors.newFixedThreadPool(threads);
|
||||||
for(final Algorithm algorithm : algorithms){
|
for (final Algorithm algorithm : algorithms) {
|
||||||
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
|
||||||
|
public void run() {
|
||||||
|
runAlgorithm(p, algorithm, r + 1);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
});
|
||||||
public void run() {
|
} catch (Exception e) {
|
||||||
runAlgorithm(p, algorithm, r+1);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
|
||||||
|
|
||||||
});
|
} catch (InterruptedException e) {
|
||||||
}
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
System.out.println("benchmarking done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]");
|
||||||
try {
|
informEnd();
|
||||||
executor.shutdown();
|
}
|
||||||
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
|
|
||||||
|
|
||||||
} catch (InterruptedException e) {
|
private void informEnd() {
|
||||||
e.printStackTrace();
|
for (LabStartsAndEndsListener l : startsAndEndslisteners) {
|
||||||
}
|
l.labEnds();
|
||||||
System.out.println("benchmarking done [time="+(System.currentTimeMillis()-startTime)/1000 + "sec]");
|
}
|
||||||
informEnd();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void informEnd() {
|
private void informStart() {
|
||||||
for(LabStartsAndEndsListener l : startsAndEndslisteners){
|
for (LabStartsAndEndsListener l : startsAndEndslisteners) {
|
||||||
l.labEnds();
|
l.labStarts(benchmarkInstances, algorithms.size(), runs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void informStart() {
|
/**
|
||||||
for(LabStartsAndEndsListener l : startsAndEndslisteners){
|
* Sets number of threads.
|
||||||
l.labStarts(benchmarkInstances, algorithms.size(),runs);
|
* <p>By default: <code>nuThreads = Runtime.getRuntime().availableProcessors()+1</code>
|
||||||
}
|
*
|
||||||
}
|
* @param threads
|
||||||
|
*/
|
||||||
|
public void setThreads(int threads) {
|
||||||
|
this.threads = threads;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private void runAlgorithm(BenchmarkInstance p, Algorithm algorithm, int run) {
|
||||||
* Sets number of threads.
|
System.out.println("[algorithm=" + algorithm.name + "][instance=" + p.name + "][run=" + run + "][status=start]");
|
||||||
* <p>By default: <code>nuThreads = Runtime.getRuntime().availableProcessors()+1</code>
|
VehicleRoutingAlgorithm vra = algorithm.factory.createAlgorithm(p.vrp);
|
||||||
*
|
informCalculationStarts(p, algorithm.name, vra, run);
|
||||||
* @param threads
|
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
|
||||||
*/
|
System.out.println("[algorithm=" + algorithm.name + "][instance=" + p.name + "][run=" + run + "][status=finished]");
|
||||||
public void setThreads(int threads) {
|
informCalculationsEnds(p, algorithm.name, vra, run, solutions);
|
||||||
this.threads = threads;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void runAlgorithm(BenchmarkInstance p, Algorithm algorithm, int run) {
|
private void informCalculationStarts(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run) {
|
||||||
System.out.println("[algorithm=" + algorithm.name + "][instance="+p.name+"][run="+run+"][status=start]");
|
for (CalculationListener l : listeners) l.calculationStarts(p, name, vra, run);
|
||||||
VehicleRoutingAlgorithm vra = algorithm.factory.createAlgorithm(p.vrp);
|
}
|
||||||
informCalculationStarts(p, algorithm.name, vra, run);
|
|
||||||
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
|
|
||||||
System.out.println("[algorithm=" + algorithm.name + "][instance="+p.name+"][run="+run+"][status=finished]");
|
|
||||||
informCalculationsEnds(p, algorithm.name, vra, run, solutions);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void informCalculationStarts(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run) {
|
private void informCalculationsEnds(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run,
|
||||||
for(CalculationListener l : listeners) l.calculationStarts(p, name, vra, run);
|
Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
}
|
for (CalculationListener l : listeners) l.calculationEnds(p, name, vra, run, solutions);
|
||||||
|
}
|
||||||
private void informCalculationsEnds(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run,
|
|
||||||
Collection<VehicleRoutingProblemSolution> solutions) {
|
|
||||||
for(CalculationListener l : listeners) l.calculationEnds(p, name, vra, run, solutions);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,184 +36,184 @@ import java.util.concurrent.*;
|
||||||
|
|
||||||
public class ConcurrentBenchmarker {
|
public class ConcurrentBenchmarker {
|
||||||
|
|
||||||
public static interface Cost {
|
public static interface Cost {
|
||||||
public double getCost(VehicleRoutingProblemSolution sol);
|
public double getCost(VehicleRoutingProblemSolution sol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String algorithmConfig = null;
|
||||||
|
|
||||||
private String algorithmConfig = null;
|
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
|
||||||
|
|
||||||
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
|
private int runs = 1;
|
||||||
|
|
||||||
private int runs = 1;
|
private Collection<BenchmarkWriter> writers = new ArrayList<BenchmarkWriter>();
|
||||||
|
|
||||||
private Collection<BenchmarkWriter> writers = new ArrayList<BenchmarkWriter>();
|
private Collection<BenchmarkResult> results = new ArrayList<BenchmarkResult>();
|
||||||
|
|
||||||
private Collection<BenchmarkResult> results = new ArrayList<BenchmarkResult>();
|
private Cost cost = new Cost() {
|
||||||
|
|
||||||
private Cost cost = new Cost(){
|
@Override
|
||||||
|
public double getCost(VehicleRoutingProblemSolution sol) {
|
||||||
|
return sol.getCost();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
};
|
||||||
public double getCost(VehicleRoutingProblemSolution sol) {
|
|
||||||
return sol.getCost();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
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) {
|
||||||
|
super();
|
||||||
public ConcurrentBenchmarker(String algorithmConfig) {
|
this.algorithmConfig = algorithmConfig;
|
||||||
super();
|
|
||||||
this.algorithmConfig = algorithmConfig;
|
|
||||||
// LogManager.getRootLogger().setLevel(Level.ERROR);
|
// LogManager.getRootLogger().setLevel(Level.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConcurrentBenchmarker(VehicleRoutingAlgorithmFactory algorithmFactory){
|
public ConcurrentBenchmarker(VehicleRoutingAlgorithmFactory algorithmFactory) {
|
||||||
this.algorithmFactory = algorithmFactory;
|
this.algorithmFactory = algorithmFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addBenchmarkWriter(BenchmarkWriter writer){
|
public void addBenchmarkWriter(BenchmarkWriter writer) {
|
||||||
writers.add(writer);
|
writers.add(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInstance(String name, VehicleRoutingProblem problem){
|
public void addInstance(String name, VehicleRoutingProblem problem) {
|
||||||
benchmarkInstances.add(new BenchmarkInstance(name,problem,null,null));
|
benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInstane(BenchmarkInstance instance){
|
public void addInstane(BenchmarkInstance instance) {
|
||||||
benchmarkInstances.add(instance);
|
benchmarkInstances.add(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAllInstances(Collection<BenchmarkInstance> instances){
|
public void addAllInstances(Collection<BenchmarkInstance> instances) {
|
||||||
benchmarkInstances.addAll(instances);
|
benchmarkInstances.addAll(instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles){
|
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles) {
|
||||||
benchmarkInstances.add(new BenchmarkInstance(name,problem,bestKnownResult,bestKnownVehicles));
|
benchmarkInstances.add(new BenchmarkInstance(name, problem, bestKnownResult, bestKnownVehicles));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets nuOfRuns with same algorithm on same instance.
|
* Sets nuOfRuns with same algorithm on same instance.
|
||||||
* <p>Default is 1
|
* <p>Default is 1
|
||||||
*
|
*
|
||||||
* @param runs
|
* @param runs
|
||||||
*/
|
*/
|
||||||
public void setNuOfRuns(int runs){
|
public void setNuOfRuns(int runs) {
|
||||||
this.runs = runs;
|
this.runs = runs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(){
|
public void run() {
|
||||||
System.out.println("start benchmarking [nuOfInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
|
System.out.println("start benchmarking [nuOfInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
|
||||||
double startTime = System.currentTimeMillis();
|
double startTime = System.currentTimeMillis();
|
||||||
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1);
|
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
|
||||||
List<Future<BenchmarkResult>> futures = new ArrayList<Future<BenchmarkResult>>();
|
List<Future<BenchmarkResult>> futures = new ArrayList<Future<BenchmarkResult>>();
|
||||||
for(final BenchmarkInstance p : benchmarkInstances){
|
for (final BenchmarkInstance p : benchmarkInstances) {
|
||||||
|
|
||||||
Future<BenchmarkResult> futureResult = executor.submit(new Callable<BenchmarkResult>(){
|
Future<BenchmarkResult> futureResult = executor.submit(new Callable<BenchmarkResult>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BenchmarkResult call() throws Exception {
|
public BenchmarkResult call() throws Exception {
|
||||||
return runAlgoAndGetResult(p);
|
return runAlgoAndGetResult(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
futures.add(futureResult);
|
futures.add(futureResult);
|
||||||
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
for(Future<BenchmarkResult> f : futures){
|
for (Future<BenchmarkResult> f : futures) {
|
||||||
BenchmarkResult r = f.get();
|
BenchmarkResult r = f.get();
|
||||||
print(r,count);
|
print(r, count);
|
||||||
results.add(f.get());
|
results.add(f.get());
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
executor.shutdown();
|
executor.shutdown();
|
||||||
print(results);
|
print(results);
|
||||||
System.out.println("done [time="+(System.currentTimeMillis()-startTime)/1000 + "sec]");
|
System.out.println("done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private BenchmarkResult runAlgoAndGetResult(BenchmarkInstance p) {
|
private BenchmarkResult runAlgoAndGetResult(BenchmarkInstance p) {
|
||||||
double[] vehicles = new double[runs];
|
double[] vehicles = new double[runs];
|
||||||
double[] results = new double[runs];
|
double[] results = new double[runs];
|
||||||
double[] times = new double[runs];
|
double[] times = new double[runs];
|
||||||
|
|
||||||
for(int run=0;run<runs;run++){
|
for (int run = 0; run < runs; run++) {
|
||||||
VehicleRoutingAlgorithm vra = createAlgorithm(p);
|
VehicleRoutingAlgorithm vra = createAlgorithm(p);
|
||||||
StopWatch stopwatch = new StopWatch();
|
StopWatch stopwatch = new StopWatch();
|
||||||
vra.getAlgorithmListeners().addListener(stopwatch,Priority.HIGH);
|
vra.getAlgorithmListeners().addListener(stopwatch, Priority.HIGH);
|
||||||
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
|
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
|
||||||
VehicleRoutingProblemSolution best = Solutions.bestOf(solutions);
|
VehicleRoutingProblemSolution best = Solutions.bestOf(solutions);
|
||||||
vehicles[run] = best.getRoutes().size();
|
vehicles[run] = best.getRoutes().size();
|
||||||
results[run] = cost.getCost(best);
|
results[run] = cost.getCost(best);
|
||||||
times[run] = stopwatch.getCompTimeInSeconds();
|
times[run] = stopwatch.getCompTimeInSeconds();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BenchmarkResult(p, runs, results, times, vehicles);
|
return new BenchmarkResult(p, runs, results, times, vehicles);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(Collection<BenchmarkResult> results) {
|
private void print(Collection<BenchmarkResult> results) {
|
||||||
double sumTime=0.0;
|
double sumTime = 0.0;
|
||||||
double sumResult=0.0;
|
double sumResult = 0.0;
|
||||||
for(BenchmarkResult r : results){
|
for (BenchmarkResult r : results) {
|
||||||
sumTime+=r.getTimesStats().getMean();
|
sumTime += r.getTimesStats().getMean();
|
||||||
sumResult+=r.getResultStats().getMean();
|
sumResult += r.getResultStats().getMean();
|
||||||
// print(r);
|
// print(r);
|
||||||
}
|
}
|
||||||
System.out.println("[avgTime="+round(sumTime/(double)results.size(),2)+"][avgResult="+round(sumResult/(double)results.size(),2)+"]");
|
System.out.println("[avgTime=" + round(sumTime / (double) results.size(), 2) + "][avgResult=" + round(sumResult / (double) results.size(), 2) + "]");
|
||||||
for(BenchmarkWriter writer : writers){
|
for (BenchmarkWriter writer : writers) {
|
||||||
writer.write(results);
|
writer.write(results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(BenchmarkResult r, int count) {
|
private void print(BenchmarkResult r, int count) {
|
||||||
Double avgDelta = null;
|
Double avgDelta = null;
|
||||||
Double bestDelta = null;
|
Double bestDelta = null;
|
||||||
Double worstDelta = null;
|
Double worstDelta = null;
|
||||||
if(r.instance.bestKnownResult != null){
|
if (r.instance.bestKnownResult != null) {
|
||||||
avgDelta = (r.getResultStats().getMean() / r.instance.bestKnownResult - 1) * 100;
|
avgDelta = (r.getResultStats().getMean() / r.instance.bestKnownResult - 1) * 100;
|
||||||
bestDelta = (r.getResultStats().getMin() / r.instance.bestKnownResult - 1) * 100;
|
bestDelta = (r.getResultStats().getMin() / r.instance.bestKnownResult - 1) * 100;
|
||||||
worstDelta = (r.getResultStats().getMax() / r.instance.bestKnownResult - 1) * 100;
|
worstDelta = (r.getResultStats().getMax() / r.instance.bestKnownResult - 1) * 100;
|
||||||
}
|
}
|
||||||
System.out.println("("+count+"/"+benchmarkInstances.size() +")"+ "\t[instance="+r.instance.name+
|
System.out.println("(" + count + "/" + benchmarkInstances.size() + ")" + "\t[instance=" + r.instance.name +
|
||||||
"][avgTime="+round(r.getTimesStats().getMean(),2)+"]" +
|
"][avgTime=" + round(r.getTimesStats().getMean(), 2) + "]" +
|
||||||
"[Result=" + getString(r.getResultStats()) + "]" +
|
"[Result=" + getString(r.getResultStats()) + "]" +
|
||||||
"[Vehicles=" + getString(r.getVehicleStats()) + "]" +
|
"[Vehicles=" + getString(r.getVehicleStats()) + "]" +
|
||||||
"[Delta[%]=" + getString(bestDelta,avgDelta,worstDelta) + "]");
|
"[Delta[%]=" + getString(bestDelta, avgDelta, worstDelta) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getString(Double bestDelta, Double avgDelta,Double worstDelta) {
|
private String getString(Double bestDelta, Double avgDelta, Double worstDelta) {
|
||||||
return "[best="+round(bestDelta,2)+"][avg="+round(avgDelta,2)+"][worst="+round(worstDelta,2)+"]";
|
return "[best=" + round(bestDelta, 2) + "][avg=" + round(avgDelta, 2) + "][worst=" + round(worstDelta, 2) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getString(DescriptiveStatistics stats){
|
private String getString(DescriptiveStatistics stats) {
|
||||||
return "[best="+round(stats.getMin(),2)+"][avg="+round(stats.getMean(),2)+"][worst="+round(stats.getMax(),2)+"][stdDev=" + round(stats.getStandardDeviation(),2)+"]";
|
return "[best=" + round(stats.getMin(), 2) + "][avg=" + round(stats.getMean(), 2) + "][worst=" + round(stats.getMax(), 2) + "][stdDev=" + round(stats.getStandardDeviation(), 2) + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private Double round(Double value, int i) {
|
private Double round(Double value, int i) {
|
||||||
if(value==null) return null;
|
if (value == null) return null;
|
||||||
long roundedVal = Math.round(value*Math.pow(10, i));
|
long roundedVal = Math.round(value * Math.pow(10, i));
|
||||||
return (double)roundedVal/(double)(Math.pow(10, i));
|
return (double) roundedVal / (double) (Math.pow(10, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,55 +46,55 @@ public class GraphStreamViewer {
|
||||||
public static class StyleSheets {
|
public static class StyleSheets {
|
||||||
|
|
||||||
public static String BLUE_FOREST =
|
public static String BLUE_FOREST =
|
||||||
"graph { fill-color: #141F2E; }" +
|
"graph { fill-color: #141F2E; }" +
|
||||||
"node {" +
|
"node {" +
|
||||||
" size: 7px, 7px;" +
|
" size: 7px, 7px;" +
|
||||||
" fill-color: #A0FFA0;" +
|
" fill-color: #A0FFA0;" +
|
||||||
" text-alignment: at-right;" +
|
" text-alignment: at-right;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #999;" +
|
" stroke-color: #999;" +
|
||||||
" stroke-width: 1.0;" +
|
" stroke-width: 1.0;" +
|
||||||
" text-font: couriernew;" +
|
" text-font: couriernew;" +
|
||||||
" text-offset: 2,-5;" +
|
" text-offset: 2,-5;" +
|
||||||
" text-size: 8;" +
|
" text-size: 8;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.pickup {" +
|
"node.pickup {" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.delivery {" +
|
"node.delivery {" +
|
||||||
" fill-color: #f93;" +
|
" fill-color: #f93;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.pickupInRoute {" +
|
"node.pickupInRoute {" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.deliveryInRoute {" +
|
"node.deliveryInRoute {" +
|
||||||
" fill-color: #f93;" +
|
" fill-color: #f93;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.depot {" +
|
"node.depot {" +
|
||||||
" fill-color: #BD2C00;" +
|
" fill-color: #BD2C00;" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" shape: box;" +
|
" shape: box;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.removed {" +
|
"node.removed {" +
|
||||||
" fill-color: #FF8080;" +
|
" fill-color: #FF8080;" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #CCF;" +
|
" stroke-color: #CCF;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
" shadow-mode: gradient-radial;" +
|
" shadow-mode: gradient-radial;" +
|
||||||
" shadow-width: 10px; shadow-color: #EEF, #000; shadow-offset: 0px;" +
|
" shadow-width: 10px; shadow-color: #EEF, #000; shadow-offset: 0px;" +
|
||||||
"}" +
|
"}" +
|
||||||
|
|
||||||
"edge {" +
|
"edge {" +
|
||||||
" fill-color: #D3D3D3;" +
|
" fill-color: #D3D3D3;" +
|
||||||
" arrow-size: 6px,3px;" +
|
" arrow-size: 6px,3px;" +
|
||||||
"}" +
|
"}" +
|
||||||
// "edge.inserted {" +
|
// "edge.inserted {" +
|
||||||
// " fill-color: #A0FFA0;" +
|
// " fill-color: #A0FFA0;" +
|
||||||
// " arrow-size: 6px,3px;" +
|
// " arrow-size: 6px,3px;" +
|
||||||
|
|
@ -107,69 +107,68 @@ public class GraphStreamViewer {
|
||||||
// " shadow-mode: gradient-radial;" +
|
// " shadow-mode: gradient-radial;" +
|
||||||
// " shadow-width: 10px; shadow-color: #EEF, #000; shadow-offset: 0px;" +
|
// " shadow-width: 10px; shadow-color: #EEF, #000; shadow-offset: 0px;" +
|
||||||
// "}" +
|
// "}" +
|
||||||
"edge.shipment {" +
|
"edge.shipment {" +
|
||||||
" fill-color: #999;" +
|
" fill-color: #999;" +
|
||||||
" arrow-size: 6px,3px;" +
|
" arrow-size: 6px,3px;" +
|
||||||
"}" ;
|
"}";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
public static String SIMPLE_WHITE =
|
public static String SIMPLE_WHITE =
|
||||||
"node {" +
|
"node {" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
" text-alignment: at-right;" +
|
" text-alignment: at-right;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #999;" +
|
" stroke-color: #999;" +
|
||||||
" stroke-width: 1.0;" +
|
" stroke-width: 1.0;" +
|
||||||
" text-font: couriernew;" +
|
" text-font: couriernew;" +
|
||||||
" text-offset: 2,-5;" +
|
" text-offset: 2,-5;" +
|
||||||
" text-size: 8;" +
|
" text-size: 8;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.pickup {" +
|
"node.pickup {" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.delivery {" +
|
"node.delivery {" +
|
||||||
" fill-color: #f93;" +
|
" fill-color: #f93;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.pickupInRoute {" +
|
"node.pickupInRoute {" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.deliveryInRoute {" +
|
"node.deliveryInRoute {" +
|
||||||
" fill-color: #f93;" +
|
" fill-color: #f93;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.depot {" +
|
"node.depot {" +
|
||||||
" fill-color: #BD2C00;" +
|
" fill-color: #BD2C00;" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" shape: box;" +
|
" shape: box;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.removed {" +
|
"node.removed {" +
|
||||||
" fill-color: #BD2C00;" +
|
" fill-color: #BD2C00;" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
|
|
||||||
"edge {" +
|
"edge {" +
|
||||||
" fill-color: #333;" +
|
" fill-color: #333;" +
|
||||||
" arrow-size: 6px,3px;" +
|
" arrow-size: 6px,3px;" +
|
||||||
"}" +
|
"}" +
|
||||||
"edge.shipment {" +
|
"edge.shipment {" +
|
||||||
" fill-color: #999;" +
|
" fill-color: #999;" +
|
||||||
" arrow-size: 6px,3px;" +
|
" arrow-size: 6px,3px;" +
|
||||||
"}" ;
|
"}";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Graph createMultiGraph(String name, String style){
|
public static Graph createMultiGraph(String name, String style) {
|
||||||
Graph g = new MultiGraph(name);
|
Graph g = new MultiGraph(name);
|
||||||
g.addAttribute("ui.quality");
|
g.addAttribute("ui.quality");
|
||||||
g.addAttribute("ui.antialias");
|
g.addAttribute("ui.antialias");
|
||||||
|
|
@ -177,162 +176,162 @@ public class GraphStreamViewer {
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ViewPanel createEmbeddedView(Graph graph, double scaling){
|
public static ViewPanel createEmbeddedView(Graph graph, double scaling) {
|
||||||
Viewer viewer = new Viewer(graph,Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
|
Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
|
||||||
ViewPanel view = viewer.addDefaultView(false);
|
ViewPanel view = viewer.addDefaultView(false);
|
||||||
view.setPreferredSize(new Dimension((int) (698 * scaling), (int) (440 * scaling)));
|
view.setPreferredSize(new Dimension((int) (698 * scaling), (int) (440 * scaling)));
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String STYLESHEET =
|
public static String STYLESHEET =
|
||||||
"node {" +
|
"node {" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
" text-alignment: at-right;" +
|
" text-alignment: at-right;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #999;" +
|
" stroke-color: #999;" +
|
||||||
" stroke-width: 1.0;" +
|
" stroke-width: 1.0;" +
|
||||||
" text-font: couriernew;" +
|
" text-font: couriernew;" +
|
||||||
" text-offset: 2,-5;" +
|
" text-offset: 2,-5;" +
|
||||||
" text-size: 8;" +
|
" text-size: 8;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.pickup {" +
|
"node.pickup {" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.delivery {" +
|
"node.delivery {" +
|
||||||
" fill-color: #f93;" +
|
" fill-color: #f93;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.pickupInRoute {" +
|
"node.pickupInRoute {" +
|
||||||
" fill-color: #6CC644;" +
|
" fill-color: #6CC644;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.deliveryInRoute {" +
|
"node.deliveryInRoute {" +
|
||||||
" fill-color: #f93;" +
|
" fill-color: #f93;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.depot {" +
|
"node.depot {" +
|
||||||
" fill-color: #BD2C00;" +
|
" fill-color: #BD2C00;" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" shape: box;" +
|
" shape: box;" +
|
||||||
"}" +
|
"}" +
|
||||||
"node.removed {" +
|
"node.removed {" +
|
||||||
" fill-color: #BD2C00;" +
|
" fill-color: #BD2C00;" +
|
||||||
" size: 10px, 10px;" +
|
" size: 10px, 10px;" +
|
||||||
" stroke-mode: plain;" +
|
" stroke-mode: plain;" +
|
||||||
" stroke-color: #333;" +
|
" stroke-color: #333;" +
|
||||||
" stroke-width: 2.0;" +
|
" stroke-width: 2.0;" +
|
||||||
"}" +
|
"}" +
|
||||||
|
|
||||||
"edge {" +
|
"edge {" +
|
||||||
" fill-color: #333;" +
|
" fill-color: #333;" +
|
||||||
" arrow-size: 6px,3px;" +
|
" arrow-size: 6px,3px;" +
|
||||||
"}" +
|
"}" +
|
||||||
"edge.shipment {" +
|
"edge.shipment {" +
|
||||||
" fill-color: #999;" +
|
" fill-color: #999;" +
|
||||||
" arrow-size: 6px,3px;" +
|
" arrow-size: 6px,3px;" +
|
||||||
"}" ;
|
"}";
|
||||||
|
|
||||||
public static enum Label {
|
public static enum Label {
|
||||||
NO_LABEL, ID, JOB_NAME, ARRIVAL_TIME, DEPARTURE_TIME, ACTIVITY
|
NO_LABEL, ID, JOB_NAME, ARRIVAL_TIME, DEPARTURE_TIME, ACTIVITY
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Center {
|
private static class Center {
|
||||||
final double x;
|
final double x;
|
||||||
final double y;
|
final double y;
|
||||||
|
|
||||||
public Center(double x, double y) {
|
public Center(double x, double y) {
|
||||||
super();
|
super();
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Label label = Label.NO_LABEL;
|
private Label label = Label.NO_LABEL;
|
||||||
|
|
||||||
private long renderDelay_in_ms = 0;
|
private long renderDelay_in_ms = 0;
|
||||||
|
|
||||||
private boolean renderShipments = false;
|
private boolean renderShipments = false;
|
||||||
|
|
||||||
private Center center;
|
private Center center;
|
||||||
|
|
||||||
private VehicleRoutingProblem vrp;
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private VehicleRoutingProblemSolution solution;
|
private VehicleRoutingProblemSolution solution;
|
||||||
|
|
||||||
private double zoomFactor;
|
private double zoomFactor;
|
||||||
|
|
||||||
private double scaling = 1.0;
|
private double scaling = 1.0;
|
||||||
|
|
||||||
|
|
||||||
public GraphStreamViewer(VehicleRoutingProblem vrp) {
|
public GraphStreamViewer(VehicleRoutingProblem vrp) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphStreamViewer(VehicleRoutingProblem vrp, VehicleRoutingProblemSolution solution) {
|
public GraphStreamViewer(VehicleRoutingProblem vrp, VehicleRoutingProblemSolution solution) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
this.solution = solution;
|
this.solution = solution;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphStreamViewer labelWith(Label label){
|
public GraphStreamViewer labelWith(Label label) {
|
||||||
this.label=label;
|
this.label = label;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphStreamViewer setRenderDelay(long ms){
|
public GraphStreamViewer setRenderDelay(long ms) {
|
||||||
this.renderDelay_in_ms=ms;
|
this.renderDelay_in_ms = ms;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public GraphStreamViewer setEnableAutoLayout(boolean enableAutoLayout) {
|
public GraphStreamViewer setEnableAutoLayout(boolean enableAutoLayout) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphStreamViewer setRenderShipments(boolean renderShipments){
|
public GraphStreamViewer setRenderShipments(boolean renderShipments) {
|
||||||
this.renderShipments = renderShipments;
|
this.renderShipments = renderShipments;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GraphStreamViewer setGraphStreamFrameScalingFactor(double factor){
|
public GraphStreamViewer setGraphStreamFrameScalingFactor(double factor) {
|
||||||
this.scaling=factor;
|
this.scaling = factor;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* @param centerY y coordinate of center
|
* @param centerY y coordinate of center
|
||||||
* @param zoomFactor zoom factor
|
* @param zoomFactor zoom factor
|
||||||
* @return the viewer
|
* @return the viewer
|
||||||
*/
|
*/
|
||||||
public GraphStreamViewer setCameraView(double centerX, double centerY, double zoomFactor){
|
public GraphStreamViewer setCameraView(double centerX, double centerY, double zoomFactor) {
|
||||||
center = new Center(centerX,centerY);
|
center = new Center(centerX, centerY);
|
||||||
this.zoomFactor = zoomFactor;
|
this.zoomFactor = zoomFactor;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void display(){
|
public void display() {
|
||||||
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
|
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
|
||||||
|
|
||||||
Graph g = createMultiGraph("g");
|
Graph g = createMultiGraph("g");
|
||||||
|
|
||||||
ViewPanel view = createEmbeddedView(g,scaling);
|
ViewPanel view = createEmbeddedView(g, scaling);
|
||||||
|
|
||||||
createJFrame(view,scaling);
|
createJFrame(view, scaling);
|
||||||
|
|
||||||
render(g, view);
|
render(g, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JFrame createJFrame(ViewPanel view, double scaling) {
|
private JFrame createJFrame(ViewPanel view, double scaling) {
|
||||||
JFrame jframe = new JFrame();
|
JFrame jframe = new JFrame();
|
||||||
|
|
@ -345,11 +344,11 @@ public class GraphStreamViewer {
|
||||||
|
|
||||||
|
|
||||||
JPanel graphStreamPanel = new JPanel();
|
JPanel graphStreamPanel = new JPanel();
|
||||||
graphStreamPanel.setPreferredSize(new Dimension((int)(800*scaling),(int)(460*scaling)));
|
graphStreamPanel.setPreferredSize(new Dimension((int) (800 * scaling), (int) (460 * scaling)));
|
||||||
graphStreamPanel.setBackground(Color.WHITE);
|
graphStreamPanel.setBackground(Color.WHITE);
|
||||||
|
|
||||||
JPanel graphStreamBackPanel = new JPanel();
|
JPanel graphStreamBackPanel = new JPanel();
|
||||||
graphStreamBackPanel.setPreferredSize(new Dimension((int)(700*scaling),(int)(450*scaling)));
|
graphStreamBackPanel.setPreferredSize(new Dimension((int) (700 * scaling), (int) (450 * scaling)));
|
||||||
graphStreamBackPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
|
graphStreamBackPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
|
||||||
graphStreamBackPanel.setBackground(Color.WHITE);
|
graphStreamBackPanel.setBackground(Color.WHITE);
|
||||||
|
|
||||||
|
|
@ -365,7 +364,7 @@ public class GraphStreamViewer {
|
||||||
jframe.add(basicPanel);
|
jframe.add(basicPanel);
|
||||||
|
|
||||||
//conf jframe
|
//conf jframe
|
||||||
jframe.setSize((int)(800*scaling),(int)(580*scaling));
|
jframe.setSize((int) (800 * scaling), (int) (580 * scaling));
|
||||||
jframe.setLocationRelativeTo(null);
|
jframe.setLocationRelativeTo(null);
|
||||||
jframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
jframe.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||||
jframe.setVisible(true);
|
jframe.setVisible(true);
|
||||||
|
|
@ -375,40 +374,39 @@ public class GraphStreamViewer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Graph createMultiGraph(String name) {
|
private Graph createMultiGraph(String name) {
|
||||||
return GraphStreamViewer.createMultiGraph(name,STYLESHEET);
|
return GraphStreamViewer.createMultiGraph(name, STYLESHEET);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void render(Graph g, ViewPanel view) {
|
private void render(Graph g, ViewPanel view) {
|
||||||
if(center != null){
|
if (center != null) {
|
||||||
view.resizeFrame(view.getWidth(), view.getHeight());
|
view.resizeFrame(view.getWidth(), view.getHeight());
|
||||||
alignCamera(view);
|
alignCamera(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Vehicle vehicle : vrp.getVehicles()){
|
for (Vehicle vehicle : vrp.getVehicles()) {
|
||||||
renderVehicle(g,vehicle,label);
|
renderVehicle(g, vehicle, label);
|
||||||
sleep(renderDelay_in_ms);
|
sleep(renderDelay_in_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(solution != null){
|
if (solution != null) {
|
||||||
int routeId = 1;
|
int routeId = 1;
|
||||||
for(VehicleRoute route : solution.getRoutes()){
|
for (VehicleRoute route : solution.getRoutes()) {
|
||||||
renderRoute(g,route,routeId,renderDelay_in_ms,label);
|
renderRoute(g, route, routeId, renderDelay_in_ms, label);
|
||||||
sleep(renderDelay_in_ms);
|
sleep(renderDelay_in_ms);
|
||||||
routeId++;
|
routeId++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void alignCamera(View view) {
|
private void alignCamera(View view) {
|
||||||
view.getCamera().setViewCenter(center.x, center.y, 0);
|
view.getCamera().setViewCenter(center.x, center.y, 0);
|
||||||
|
|
@ -416,53 +414,53 @@ public class GraphStreamViewer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private JLabel createEmptyLabel() {
|
private JLabel createEmptyLabel() {
|
||||||
JLabel emptyLabel1 = new JLabel();
|
JLabel emptyLabel1 = new JLabel();
|
||||||
emptyLabel1.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
emptyLabel1.setPreferredSize(new Dimension((int) (40 * scaling), (int) (25 * scaling)));
|
||||||
return emptyLabel1;
|
return emptyLabel1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JPanel createResultPanel() {
|
private JPanel createResultPanel() {
|
||||||
int width = 800;
|
int width = 800;
|
||||||
int height = 50;
|
int height = 50;
|
||||||
|
|
||||||
JPanel panel = new JPanel();
|
JPanel panel = new JPanel();
|
||||||
panel.setPreferredSize(new Dimension((int)(width*scaling),(int)(height*scaling)));
|
panel.setPreferredSize(new Dimension((int) (width * scaling), (int) (height * scaling)));
|
||||||
panel.setBackground(Color.WHITE);
|
panel.setBackground(Color.WHITE);
|
||||||
|
|
||||||
JPanel subpanel = new JPanel();
|
JPanel subpanel = new JPanel();
|
||||||
subpanel.setLayout(new FlowLayout());
|
subpanel.setLayout(new FlowLayout());
|
||||||
subpanel.setPreferredSize(new Dimension((int)(700*scaling),(int)(40*scaling)));
|
subpanel.setPreferredSize(new Dimension((int) (700 * scaling), (int) (40 * scaling)));
|
||||||
subpanel.setBackground(Color.WHITE);
|
subpanel.setBackground(Color.WHITE);
|
||||||
subpanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY,1));
|
subpanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
|
||||||
|
|
||||||
Font font = Font.decode("couriernew");
|
Font font = Font.decode("couriernew");
|
||||||
|
|
||||||
JLabel jobs = new JLabel("jobs");
|
JLabel jobs = new JLabel("jobs");
|
||||||
jobs.setFont(font);
|
jobs.setFont(font);
|
||||||
jobs.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
jobs.setPreferredSize(new Dimension((int) (40 * scaling), (int) (25 * scaling)));
|
||||||
|
|
||||||
int noJobs = 0;
|
int noJobs = 0;
|
||||||
if(this.vrp != null) noJobs = this.vrp.getJobs().values().size();
|
if (this.vrp != null) noJobs = this.vrp.getJobs().values().size();
|
||||||
|
|
||||||
JFormattedTextField nJobs = new JFormattedTextField(noJobs);
|
JFormattedTextField nJobs = new JFormattedTextField(noJobs);
|
||||||
nJobs.setFont(font);
|
nJobs.setFont(font);
|
||||||
nJobs.setEditable(false);
|
nJobs.setEditable(false);
|
||||||
nJobs.setBorder(BorderFactory.createEmptyBorder());
|
nJobs.setBorder(BorderFactory.createEmptyBorder());
|
||||||
nJobs.setBackground(new Color(230,230,230));
|
nJobs.setBackground(new Color(230, 230, 230));
|
||||||
|
|
||||||
JLabel costs = new JLabel("costs");
|
JLabel costs = new JLabel("costs");
|
||||||
costs.setFont(font);
|
costs.setFont(font);
|
||||||
costs.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
costs.setPreferredSize(new Dimension((int) (40 * scaling), (int) (25 * scaling)));
|
||||||
|
|
||||||
JFormattedTextField costsVal = new JFormattedTextField(getSolutionCosts());
|
JFormattedTextField costsVal = new JFormattedTextField(getSolutionCosts());
|
||||||
costsVal.setFont(font);
|
costsVal.setFont(font);
|
||||||
costsVal.setEditable(false);
|
costsVal.setEditable(false);
|
||||||
costsVal.setBorder(BorderFactory.createEmptyBorder());
|
costsVal.setBorder(BorderFactory.createEmptyBorder());
|
||||||
costsVal.setBackground(new Color(230,230,230));
|
costsVal.setBackground(new Color(230, 230, 230));
|
||||||
|
|
||||||
JLabel vehicles = new JLabel("routes");
|
JLabel vehicles = new JLabel("routes");
|
||||||
vehicles.setFont(font);
|
vehicles.setFont(font);
|
||||||
vehicles.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
vehicles.setPreferredSize(new Dimension((int) (40 * scaling), (int) (25 * scaling)));
|
||||||
// vehicles.setForeground(Color.DARK_GRAY);
|
// vehicles.setForeground(Color.DARK_GRAY);
|
||||||
|
|
||||||
JFormattedTextField vehVal = new JFormattedTextField(getNoRoutes());
|
JFormattedTextField vehVal = new JFormattedTextField(getNoRoutes());
|
||||||
|
|
@ -470,11 +468,11 @@ public class GraphStreamViewer {
|
||||||
vehVal.setEditable(false);
|
vehVal.setEditable(false);
|
||||||
vehVal.setBorder(BorderFactory.createEmptyBorder());
|
vehVal.setBorder(BorderFactory.createEmptyBorder());
|
||||||
// vehVal.setForeground(Color.DARK_GRAY);
|
// vehVal.setForeground(Color.DARK_GRAY);
|
||||||
vehVal.setBackground(new Color(230,230,230));
|
vehVal.setBackground(new Color(230, 230, 230));
|
||||||
|
|
||||||
//platzhalter
|
//platzhalter
|
||||||
JLabel placeholder1 = new JLabel();
|
JLabel placeholder1 = new JLabel();
|
||||||
placeholder1.setPreferredSize(new Dimension((int)(60*scaling),(int)(25*scaling)));
|
placeholder1.setPreferredSize(new Dimension((int) (60 * scaling), (int) (25 * scaling)));
|
||||||
|
|
||||||
JLabel emptyLabel1 = createEmptyLabel();
|
JLabel emptyLabel1 = createEmptyLabel();
|
||||||
|
|
||||||
|
|
@ -494,126 +492,124 @@ public class GraphStreamViewer {
|
||||||
|
|
||||||
panel.add(subpanel);
|
panel.add(subpanel);
|
||||||
|
|
||||||
return panel;
|
return panel;
|
||||||
}
|
|
||||||
|
|
||||||
private Integer getNoRoutes() {
|
|
||||||
if(solution!=null) return solution.getRoutes().size();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Double getSolutionCosts() {
|
|
||||||
if(solution!=null) return solution.getCost();
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderShipment(Graph g, Shipment shipment, Label label, boolean renderShipments) {
|
|
||||||
|
|
||||||
Node n1 = g.addNode(makeId(shipment.getId(),shipment.getPickupLocation().getId()));
|
|
||||||
if(label.equals(Label.ID)) n1.addAttribute("ui.label", shipment.getId());
|
|
||||||
n1.addAttribute("x", shipment.getPickupLocation().getCoordinate().getX());
|
|
||||||
n1.addAttribute("y", shipment.getPickupLocation().getCoordinate().getY());
|
|
||||||
n1.setAttribute("ui.class", "pickup");
|
|
||||||
|
|
||||||
Node n2 = g.addNode(makeId(shipment.getId(),shipment.getDeliveryLocation().getId()));
|
|
||||||
if(label.equals(Label.ID)) n2.addAttribute("ui.label", shipment.getId());
|
|
||||||
n2.addAttribute("x", shipment.getDeliveryLocation().getCoordinate().getX());
|
|
||||||
n2.addAttribute("y", shipment.getDeliveryLocation().getCoordinate().getY());
|
|
||||||
n2.setAttribute("ui.class", "delivery");
|
|
||||||
|
|
||||||
if(renderShipments){
|
|
||||||
Edge s = g.addEdge(shipment.getId(), makeId(shipment.getId(),shipment.getPickupLocation().getId()),
|
|
||||||
makeId(shipment.getId(),shipment.getDeliveryLocation().getId()), true);
|
|
||||||
s.addAttribute("ui.class", "shipment");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sleep(long renderDelay_in_ms2) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(renderDelay_in_ms2);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderService(Graph g, Service service, Label label) {
|
private Integer getNoRoutes() {
|
||||||
Node n = g.addNode(makeId(service.getId(),service.getLocation().getId()));
|
if (solution != null) return solution.getRoutes().size();
|
||||||
if(label.equals(Label.ID)) n.addAttribute("ui.label", service.getId());
|
return 0;
|
||||||
n.addAttribute("x", service.getLocation().getCoordinate().getX());
|
}
|
||||||
n.addAttribute("y", service.getLocation().getCoordinate().getY());
|
|
||||||
if(service.getType().equals("pickup")) n.setAttribute("ui.class", "pickup");
|
|
||||||
if(service.getType().equals("delivery")) n.setAttribute("ui.class", "delivery");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String makeId(String id, String locationId) {
|
private Double getSolutionCosts() {
|
||||||
return id + "_" + locationId;
|
if (solution != null) return solution.getCost();
|
||||||
}
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
private void renderVehicle(Graph g, Vehicle vehicle, Label label) {
|
private void renderShipment(Graph g, Shipment shipment, Label label, boolean renderShipments) {
|
||||||
String nodeId = makeId(vehicle.getId(),vehicle.getStartLocation().getId());
|
|
||||||
|
Node n1 = g.addNode(makeId(shipment.getId(), shipment.getPickupLocation().getId()));
|
||||||
|
if (label.equals(Label.ID)) n1.addAttribute("ui.label", shipment.getId());
|
||||||
|
n1.addAttribute("x", shipment.getPickupLocation().getCoordinate().getX());
|
||||||
|
n1.addAttribute("y", shipment.getPickupLocation().getCoordinate().getY());
|
||||||
|
n1.setAttribute("ui.class", "pickup");
|
||||||
|
|
||||||
|
Node n2 = g.addNode(makeId(shipment.getId(), shipment.getDeliveryLocation().getId()));
|
||||||
|
if (label.equals(Label.ID)) n2.addAttribute("ui.label", shipment.getId());
|
||||||
|
n2.addAttribute("x", shipment.getDeliveryLocation().getCoordinate().getX());
|
||||||
|
n2.addAttribute("y", shipment.getDeliveryLocation().getCoordinate().getY());
|
||||||
|
n2.setAttribute("ui.class", "delivery");
|
||||||
|
|
||||||
|
if (renderShipments) {
|
||||||
|
Edge s = g.addEdge(shipment.getId(), makeId(shipment.getId(), shipment.getPickupLocation().getId()),
|
||||||
|
makeId(shipment.getId(), shipment.getDeliveryLocation().getId()), true);
|
||||||
|
s.addAttribute("ui.class", "shipment");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sleep(long renderDelay_in_ms2) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(renderDelay_in_ms2);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderService(Graph g, Service service, Label label) {
|
||||||
|
Node n = g.addNode(makeId(service.getId(), service.getLocation().getId()));
|
||||||
|
if (label.equals(Label.ID)) n.addAttribute("ui.label", service.getId());
|
||||||
|
n.addAttribute("x", service.getLocation().getCoordinate().getX());
|
||||||
|
n.addAttribute("y", service.getLocation().getCoordinate().getY());
|
||||||
|
if (service.getType().equals("pickup")) n.setAttribute("ui.class", "pickup");
|
||||||
|
if (service.getType().equals("delivery")) n.setAttribute("ui.class", "delivery");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeId(String id, String locationId) {
|
||||||
|
return id + "_" + locationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderVehicle(Graph g, Vehicle vehicle, Label label) {
|
||||||
|
String nodeId = makeId(vehicle.getId(), vehicle.getStartLocation().getId());
|
||||||
Node vehicleStart = g.addNode(nodeId);
|
Node vehicleStart = g.addNode(nodeId);
|
||||||
if(label.equals(Label.ID)) vehicleStart.addAttribute("ui.label", "depot");
|
if (label.equals(Label.ID)) vehicleStart.addAttribute("ui.label", "depot");
|
||||||
// if(label.equals(Label.ACTIVITY)) n.addAttribute("ui.label", "start");
|
// if(label.equals(Label.ACTIVITY)) n.addAttribute("ui.label", "start");
|
||||||
vehicleStart.addAttribute("x", vehicle.getStartLocation().getCoordinate().getX());
|
vehicleStart.addAttribute("x", vehicle.getStartLocation().getCoordinate().getX());
|
||||||
vehicleStart.addAttribute("y", vehicle.getStartLocation().getCoordinate().getY());
|
vehicleStart.addAttribute("y", vehicle.getStartLocation().getCoordinate().getY());
|
||||||
vehicleStart.setAttribute("ui.class", "depot");
|
vehicleStart.setAttribute("ui.class", "depot");
|
||||||
|
|
||||||
if(!vehicle.getStartLocation().getId().equals(vehicle.getEndLocation().getId())){
|
if (!vehicle.getStartLocation().getId().equals(vehicle.getEndLocation().getId())) {
|
||||||
Node vehicleEnd = g.addNode(makeId(vehicle.getId(),vehicle.getEndLocation().getId()));
|
Node vehicleEnd = g.addNode(makeId(vehicle.getId(), vehicle.getEndLocation().getId()));
|
||||||
if(label.equals(Label.ID)) vehicleEnd.addAttribute("ui.label", "depot");
|
if (label.equals(Label.ID)) vehicleEnd.addAttribute("ui.label", "depot");
|
||||||
vehicleEnd.addAttribute("x", vehicle.getEndLocation().getCoordinate().getX());
|
vehicleEnd.addAttribute("x", vehicle.getEndLocation().getCoordinate().getX());
|
||||||
vehicleEnd.addAttribute("y", vehicle.getEndLocation().getCoordinate().getY());
|
vehicleEnd.addAttribute("y", vehicle.getEndLocation().getCoordinate().getY());
|
||||||
vehicleEnd.setAttribute("ui.class", "depot");
|
vehicleEnd.setAttribute("ui.class", "depot");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRoute(Graph g, VehicleRoute route, int routeId, long renderDelay_in_ms, Label label) {
|
private void renderRoute(Graph g, VehicleRoute route, int routeId, long renderDelay_in_ms, Label label) {
|
||||||
int vehicle_edgeId = 1;
|
int vehicle_edgeId = 1;
|
||||||
String prevIdentifier = makeId(route.getVehicle().getId(),route.getVehicle().getStartLocation().getId());
|
String prevIdentifier = makeId(route.getVehicle().getId(), route.getVehicle().getStartLocation().getId());
|
||||||
if(label.equals(Label.ACTIVITY) || label.equals(Label.JOB_NAME)){
|
if (label.equals(Label.ACTIVITY) || label.equals(Label.JOB_NAME)) {
|
||||||
Node n = g.getNode(prevIdentifier);
|
Node n = g.getNode(prevIdentifier);
|
||||||
n.addAttribute("ui.label", "start");
|
n.addAttribute("ui.label", "start");
|
||||||
}
|
}
|
||||||
for(TourActivity act : route.getActivities()){
|
for (TourActivity act : route.getActivities()) {
|
||||||
Job job = ((JobActivity) act).getJob();
|
Job job = ((JobActivity) act).getJob();
|
||||||
String currIdentifier = makeId(job.getId(),act.getLocation().getId());
|
String currIdentifier = makeId(job.getId(), act.getLocation().getId());
|
||||||
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)
|
||||||
prevIdentifier = currIdentifier;
|
g.getNode(currIdentifier).addAttribute("ui.class", "deliveryInRoute");
|
||||||
vehicle_edgeId++;
|
prevIdentifier = currIdentifier;
|
||||||
sleep(renderDelay_in_ms);
|
vehicle_edgeId++;
|
||||||
}
|
sleep(renderDelay_in_ms);
|
||||||
if(route.getVehicle().isReturnToDepot()){
|
}
|
||||||
String lastIdentifier = makeId(route.getVehicle().getId(),route.getVehicle().getEndLocation().getId());
|
if (route.getVehicle().isReturnToDepot()) {
|
||||||
g.addEdge(makeEdgeId(routeId,vehicle_edgeId), prevIdentifier, lastIdentifier, true);
|
String lastIdentifier = makeId(route.getVehicle().getId(), route.getVehicle().getEndLocation().getId());
|
||||||
}
|
g.addEdge(makeEdgeId(routeId, vehicle_edgeId), prevIdentifier, lastIdentifier, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String makeEdgeId(int routeId, int vehicle_edgeId) {
|
private String makeEdgeId(int routeId, int vehicle_edgeId) {
|
||||||
return Integer.valueOf(routeId).toString() + "." + Integer.valueOf(vehicle_edgeId).toString();
|
return Integer.valueOf(routeId).toString() + "." + Integer.valueOf(vehicle_edgeId).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void saveAsPNG(String filename){
|
// public void saveAsPNG(String filename){
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package jsprit.analysis.toolbox;
|
package jsprit.analysis.toolbox;
|
||||||
|
|
||||||
class NoLocationFoundException extends Exception{
|
class NoLocationFoundException extends Exception {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -27,51 +27,51 @@ import org.apache.logging.log4j.Logger;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
public class StopWatch implements AlgorithmStartsListener, AlgorithmEndsListener{
|
public class StopWatch implements AlgorithmStartsListener, AlgorithmEndsListener {
|
||||||
|
|
||||||
private static Logger log = LogManager.getLogger(StopWatch.class);
|
private static Logger log = LogManager.getLogger(StopWatch.class);
|
||||||
|
|
||||||
private double ran;
|
private double ran;
|
||||||
|
|
||||||
private double startTime;
|
private double startTime;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
reset();
|
reset();
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getCompTimeInSeconds(){
|
public double getCompTimeInSeconds() {
|
||||||
return (ran)/1000.0;
|
return (ran) / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@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() {
|
||||||
ran += System.currentTimeMillis() - startTime;
|
ran += System.currentTimeMillis() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(){
|
public void start() {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset(){
|
public void reset() {
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
ran = 0;
|
ran = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "stopWatch: " + getCompTimeInSeconds() + " sec";
|
return "stopWatch: " + getCompTimeInSeconds() + " sec";
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getCurrTimeInSeconds() {
|
public double getCurrTimeInSeconds() {
|
||||||
return (System.currentTimeMillis()-startTime)/1000.0;
|
return (System.currentTimeMillis() - startTime) / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,82 +32,80 @@ import java.io.IOException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author schroeder
|
* @author schroeder
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class XYLineChartBuilder {
|
public class XYLineChartBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper that just saves the chart as specified png-file. The width of the image is 1000 and height 600.
|
* Helper that just saves the chart as specified png-file. The width of the image is 1000 and height 600.
|
||||||
*
|
*
|
||||||
* @param chart
|
* @param chart
|
||||||
* @param pngFilename
|
* @param pngFilename
|
||||||
*/
|
*/
|
||||||
public static void saveChartAsPNG(JFreeChart chart, String pngFilename){
|
public static void saveChartAsPNG(JFreeChart chart, String pngFilename) {
|
||||||
try {
|
try {
|
||||||
ChartUtilities.saveChartAsPNG(new File(pngFilename), chart, 1000, 600);
|
ChartUtilities.saveChartAsPNG(new File(pngFilename), chart, 1000, 600);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new instance of the builder.
|
* Returns a new instance of the builder.
|
||||||
*
|
*
|
||||||
* @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){
|
return new XYLineChartBuilder(chartTitle, xDomainName, yDomainName);
|
||||||
return new XYLineChartBuilder(chartTitle, xDomainName, yDomainName);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private ConcurrentHashMap<String,XYSeries> seriesMap = new ConcurrentHashMap<String, XYSeries>();
|
private ConcurrentHashMap<String, XYSeries> seriesMap = new ConcurrentHashMap<String, XYSeries>();
|
||||||
|
|
||||||
private final String xDomain;
|
private final String xDomain;
|
||||||
|
|
||||||
private final String yDomain;
|
private final String yDomain;
|
||||||
|
|
||||||
private final String chartName;
|
private final String chartName;
|
||||||
|
|
||||||
private XYLineChartBuilder(String chartName, String xDomainName, String yDomainName) {
|
private XYLineChartBuilder(String chartName, String xDomainName, String yDomainName) {
|
||||||
this.xDomain=xDomainName;
|
this.xDomain = xDomainName;
|
||||||
this.yDomain=yDomainName;
|
this.yDomain = yDomainName;
|
||||||
this.chartName=chartName;
|
this.chartName = chartName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds data to the according series (i.e. XYLine).
|
* Adds data to the according series (i.e. XYLine).
|
||||||
*
|
*
|
||||||
* @param seriesName
|
* @param seriesName
|
||||||
* @param xVal
|
* @param xVal
|
||||||
* @param yVal
|
* @param yVal
|
||||||
*/
|
*/
|
||||||
public void addData(String seriesName, double xVal, double yVal){
|
public void addData(String seriesName, double xVal, double yVal) {
|
||||||
if(!seriesMap.containsKey(seriesName)){
|
if (!seriesMap.containsKey(seriesName)) {
|
||||||
seriesMap.put(seriesName, new XYSeries(seriesName,true,true));
|
seriesMap.put(seriesName, new XYSeries(seriesName, true, true));
|
||||||
}
|
}
|
||||||
seriesMap.get(seriesName).add(xVal, yVal);
|
seriesMap.get(seriesName).add(xVal, yVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and returns JFreeChart.
|
* Builds and returns JFreeChart.
|
||||||
* @return
|
*
|
||||||
*/
|
* @return
|
||||||
public JFreeChart build(){
|
*/
|
||||||
XYSeriesCollection collection = new XYSeriesCollection();
|
public JFreeChart build() {
|
||||||
for(XYSeries s : seriesMap.values()){
|
XYSeriesCollection collection = new XYSeriesCollection();
|
||||||
collection.addSeries(s);
|
for (XYSeries s : seriesMap.values()) {
|
||||||
}
|
collection.addSeries(s);
|
||||||
JFreeChart chart = ChartFactory.createXYLineChart(chartName, xDomain, yDomain, collection, PlotOrientation.VERTICAL, true, true, false);
|
}
|
||||||
XYPlot plot = chart.getXYPlot();
|
JFreeChart chart = ChartFactory.createXYLineChart(chartName, xDomain, yDomain, collection, PlotOrientation.VERTICAL, true, true, false);
|
||||||
plot.setBackgroundPaint(Color.WHITE);
|
XYPlot plot = chart.getXYPlot();
|
||||||
plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
|
plot.setBackgroundPaint(Color.WHITE);
|
||||||
plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
|
plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
|
||||||
return chart;
|
plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
|
||||||
}
|
return chart;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,244 +16,241 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
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;
|
public HtmlBenchmarkTableWriter(String filename) {
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
public HtmlBenchmarkTableWriter(String filename) {
|
@Override
|
||||||
this.filename = filename;
|
public void write(Collection<BenchmarkResult> results) {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
try {
|
||||||
public void write(Collection<BenchmarkResult> results) {
|
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filename)));
|
||||||
|
writer.write(openTable() + newline());
|
||||||
|
//table head
|
||||||
|
writer.write(openRow() + newline());
|
||||||
|
writer.write(head("inst") + newline());
|
||||||
|
writer.write(head("runs") + newline());
|
||||||
|
writer.write(head("Ø time [sec]") + newline());
|
||||||
|
writer.write(head("results", 4));
|
||||||
|
writer.write(head("vehicles", 4));
|
||||||
|
writer.write(head("res*") + newline());
|
||||||
|
writer.write(head("veh*") + newline());
|
||||||
|
writer.write(closeRow() + newline());
|
||||||
|
|
||||||
try {
|
writer.write(openRow() + newline());
|
||||||
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filename)));
|
writer.write(head("") + newline());
|
||||||
writer.write(openTable() + newline());
|
writer.write(head("") + newline());
|
||||||
//table head
|
writer.write(head("") + newline());
|
||||||
writer.write(openRow() + newline());
|
writer.write(head("best") + newline());
|
||||||
writer.write(head("inst") + newline());
|
writer.write(head("avg") + newline());
|
||||||
writer.write(head("runs") + newline());
|
writer.write(head("worst") + newline());
|
||||||
writer.write(head("Ø time [sec]") + newline());
|
writer.write(head("stdev") + newline());
|
||||||
writer.write(head("results",4));
|
writer.write(head("best") + newline());
|
||||||
writer.write(head("vehicles",4));
|
writer.write(head("avg") + newline());
|
||||||
writer.write(head("res*") + newline());
|
writer.write(head("worst") + newline());
|
||||||
writer.write(head("veh*") + newline());
|
writer.write(head("stdev") + newline());
|
||||||
writer.write(closeRow() + newline());
|
writer.write(head("") + newline());
|
||||||
|
writer.write(head("") + newline());
|
||||||
|
writer.write(closeRow() + newline());
|
||||||
|
|
||||||
writer.write(openRow() + newline());
|
//data
|
||||||
writer.write(head("") + newline());
|
double sum_avg_time = 0.0;
|
||||||
writer.write(head("") + newline());
|
double sum_best_result = 0.0;
|
||||||
writer.write(head("") + newline());
|
double sum_avg_result = 0.0;
|
||||||
writer.write(head("best") + newline());
|
double sum_worst_result = 0.0;
|
||||||
writer.write(head("avg") + newline());
|
double sum_dev_result = 0.0;
|
||||||
writer.write(head("worst") + newline());
|
|
||||||
writer.write(head("stdev") + newline());
|
|
||||||
writer.write(head("best") + newline());
|
|
||||||
writer.write(head("avg") + newline());
|
|
||||||
writer.write(head("worst") + newline());
|
|
||||||
writer.write(head("stdev") + newline());
|
|
||||||
writer.write(head("") + newline());
|
|
||||||
writer.write(head("") + newline());
|
|
||||||
writer.write(closeRow() + newline());
|
|
||||||
|
|
||||||
//data
|
double sum_best_veh = 0.0;
|
||||||
double sum_avg_time = 0.0;
|
double sum_avg_veh = 0.0;
|
||||||
double sum_best_result = 0.0;
|
double sum_worst_veh = 0.0;
|
||||||
double sum_avg_result = 0.0;
|
double sum_dev_veh = 0.0;
|
||||||
double sum_worst_result = 0.0;
|
|
||||||
double sum_dev_result = 0.0;
|
|
||||||
|
|
||||||
double sum_best_veh = 0.0;
|
Integer runs = null;
|
||||||
double sum_avg_veh = 0.0;
|
Double sum_res_star = null;
|
||||||
double sum_worst_veh = 0.0;
|
Double sum_veh_star = null;
|
||||||
double sum_dev_veh = 0.0;
|
|
||||||
|
|
||||||
Integer runs = null;
|
for (BenchmarkResult result : results) {
|
||||||
Double sum_res_star=null;
|
if (runs == null) runs = result.runs;
|
||||||
Double sum_veh_star=null;
|
writer.write(openRow() + newline());
|
||||||
|
writer.write(date(result.instance.name) + newline());
|
||||||
|
writer.write(date(Integer.valueOf(result.runs).toString()) + newline());
|
||||||
|
|
||||||
for(BenchmarkResult result : results){
|
Double avg_time = round(result.getTimesStats().getMean(), 2);
|
||||||
if(runs==null) runs=result.runs;
|
writer.write(date(Double.valueOf(avg_time).toString()) + newline());
|
||||||
writer.write(openRow() + newline());
|
//bestRes
|
||||||
writer.write(date(result.instance.name) + newline());
|
Double best_result = round(result.getResultStats().getMin(), 2);
|
||||||
writer.write(date(Integer.valueOf(result.runs).toString()) + newline());
|
writer.write(date(Double.valueOf(best_result).toString()) + newline());
|
||||||
|
//avgRes
|
||||||
|
Double avg_result = round(result.getResultStats().getMean(), 2);
|
||||||
|
writer.write(date(Double.valueOf(avg_result).toString()) + newline());
|
||||||
|
//worstRes
|
||||||
|
Double worst_result = round(result.getResultStats().getMax(), 2);
|
||||||
|
writer.write(date(Double.valueOf(worst_result).toString()) + newline());
|
||||||
|
//stdevRes
|
||||||
|
Double std_result = round(result.getResultStats().getStandardDeviation(), 2);
|
||||||
|
writer.write(date(Double.valueOf(std_result).toString()) + newline());
|
||||||
|
//bestVeh
|
||||||
|
Double best_vehicle = round(result.getVehicleStats().getMin(), 2);
|
||||||
|
writer.write(date(Double.valueOf(best_vehicle).toString()) + newline());
|
||||||
|
//avgVeh
|
||||||
|
Double avg_vehicle = round(result.getVehicleStats().getMean(), 2);
|
||||||
|
writer.write(date(Double.valueOf(avg_vehicle).toString()) + newline());
|
||||||
|
//worstVeh
|
||||||
|
Double worst_vehicle = round(result.getVehicleStats().getMax(), 2);
|
||||||
|
writer.write(date(Double.valueOf(worst_vehicle).toString()) + newline());
|
||||||
|
//stdevVeh
|
||||||
|
Double std_vehicle = round(result.getVehicleStats().getStandardDeviation(), 2);
|
||||||
|
writer.write(date(Double.valueOf(std_vehicle).toString()) + newline());
|
||||||
|
//bestKnownRes
|
||||||
|
writer.write(date("" + result.instance.bestKnownResult + newline()));
|
||||||
|
//bestKnownVeh
|
||||||
|
writer.write(date("" + result.instance.bestKnownVehicles + newline()));
|
||||||
|
writer.write(closeRow() + newline());
|
||||||
|
|
||||||
Double avg_time = round(result.getTimesStats().getMean(),2);
|
sum_avg_time += avg_time;
|
||||||
writer.write(date(Double.valueOf(avg_time).toString()) + newline());
|
sum_best_result += best_result;
|
||||||
//bestRes
|
sum_avg_result += avg_result;
|
||||||
Double best_result = round(result.getResultStats().getMin(),2);
|
sum_worst_result += worst_result;
|
||||||
writer.write(date(Double.valueOf(best_result).toString()) + newline());
|
sum_dev_result += std_result;
|
||||||
//avgRes
|
|
||||||
Double avg_result = round(result.getResultStats().getMean(),2);
|
|
||||||
writer.write(date(Double.valueOf(avg_result).toString()) + newline());
|
|
||||||
//worstRes
|
|
||||||
Double worst_result = round(result.getResultStats().getMax(),2);
|
|
||||||
writer.write(date(Double.valueOf(worst_result).toString()) + newline());
|
|
||||||
//stdevRes
|
|
||||||
Double std_result = round(result.getResultStats().getStandardDeviation(),2);
|
|
||||||
writer.write(date(Double.valueOf(std_result).toString()) + newline());
|
|
||||||
//bestVeh
|
|
||||||
Double best_vehicle = round(result.getVehicleStats().getMin(),2);
|
|
||||||
writer.write(date(Double.valueOf(best_vehicle).toString()) + newline());
|
|
||||||
//avgVeh
|
|
||||||
Double avg_vehicle = round(result.getVehicleStats().getMean(),2);
|
|
||||||
writer.write(date(Double.valueOf(avg_vehicle).toString()) + newline());
|
|
||||||
//worstVeh
|
|
||||||
Double worst_vehicle = round(result.getVehicleStats().getMax(),2);
|
|
||||||
writer.write(date(Double.valueOf(worst_vehicle).toString()) + newline());
|
|
||||||
//stdevVeh
|
|
||||||
Double std_vehicle = round(result.getVehicleStats().getStandardDeviation(),2);
|
|
||||||
writer.write(date(Double.valueOf(std_vehicle).toString()) + newline());
|
|
||||||
//bestKnownRes
|
|
||||||
writer.write(date("" + result.instance.bestKnownResult + newline()));
|
|
||||||
//bestKnownVeh
|
|
||||||
writer.write(date("" + result.instance.bestKnownVehicles + newline()));
|
|
||||||
writer.write(closeRow() + newline());
|
|
||||||
|
|
||||||
sum_avg_time+=avg_time;
|
sum_best_veh += best_vehicle;
|
||||||
sum_best_result+=best_result;
|
sum_avg_veh += avg_vehicle;
|
||||||
sum_avg_result+=avg_result;
|
sum_worst_veh += worst_vehicle;
|
||||||
sum_worst_result+=worst_result;
|
sum_dev_veh += std_vehicle;
|
||||||
sum_dev_result+=std_result;
|
|
||||||
|
|
||||||
sum_best_veh+=best_vehicle;
|
if (result.instance.bestKnownResult != null) {
|
||||||
sum_avg_veh+=avg_vehicle;
|
if (sum_res_star == null) sum_res_star = result.instance.bestKnownResult;
|
||||||
sum_worst_veh+=worst_vehicle;
|
else sum_res_star += result.instance.bestKnownResult;
|
||||||
sum_dev_veh+=std_vehicle;
|
}
|
||||||
|
if (result.instance.bestKnownVehicles != null) {
|
||||||
|
if (sum_veh_star == null) sum_veh_star = result.instance.bestKnownVehicles;
|
||||||
|
else sum_veh_star += result.instance.bestKnownVehicles;
|
||||||
|
}
|
||||||
|
|
||||||
if(result.instance.bestKnownResult != null){
|
}
|
||||||
if(sum_res_star==null) sum_res_star=result.instance.bestKnownResult;
|
writer.write(openRow() + newline());
|
||||||
else sum_res_star+=result.instance.bestKnownResult;
|
writer.write(date("Ø") + newline());
|
||||||
}
|
writer.write(date("" + runs) + newline());
|
||||||
if(result.instance.bestKnownVehicles != null){
|
|
||||||
if(sum_veh_star==null) sum_veh_star=result.instance.bestKnownVehicles;
|
|
||||||
else sum_veh_star+=result.instance.bestKnownVehicles;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
Double average_time = round(sum_avg_time / (double) results.size(), 2);
|
||||||
writer.write(openRow() + newline());
|
writer.write(date(Double.valueOf(average_time).toString()) + newline());
|
||||||
writer.write(date("Ø") + newline());
|
//bestRes
|
||||||
writer.write(date(""+runs) + newline());
|
writer.write(date(Double.valueOf(round(sum_best_result / (double) results.size(), 2)).toString()) + newline());
|
||||||
|
//avgRes
|
||||||
|
Double average_result = round(sum_avg_result / (double) results.size(), 2);
|
||||||
|
writer.write(date(Double.valueOf(average_result).toString()) + newline());
|
||||||
|
//worstRes
|
||||||
|
writer.write(date(Double.valueOf(round(sum_worst_result / (double) results.size(), 2)).toString()) + newline());
|
||||||
|
//stdevRes
|
||||||
|
writer.write(date(Double.valueOf(round(sum_dev_result / (double) results.size(), 2)).toString()) + newline());
|
||||||
|
//bestVeh
|
||||||
|
writer.write(date(Double.valueOf(round(sum_best_veh / (double) results.size(), 2)).toString()) + newline());
|
||||||
|
//avgVeh
|
||||||
|
Double average_vehicles = round(sum_avg_veh / (double) results.size(), 2);
|
||||||
|
writer.write(date(Double.valueOf(average_vehicles).toString()) + newline());
|
||||||
|
//worstVeh
|
||||||
|
writer.write(date(Double.valueOf(round(sum_worst_veh / (double) results.size(), 2)).toString()) + newline());
|
||||||
|
//stdevVeh
|
||||||
|
writer.write(date(Double.valueOf(round(sum_dev_veh / (double) results.size(), 2)).toString()) + newline());
|
||||||
|
//bestKnownRes
|
||||||
|
Double delta_res = null;
|
||||||
|
if (sum_res_star != null) {
|
||||||
|
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;
|
||||||
|
} else writer.write(date("null") + newline());
|
||||||
|
//bestKnownVeh
|
||||||
|
Double delta_veh = null;
|
||||||
|
if (sum_veh_star != null) {
|
||||||
|
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();
|
||||||
|
} else writer.write(date("null") + newline());
|
||||||
|
writer.write(closeRow() + newline());
|
||||||
|
|
||||||
Double average_time = round(sum_avg_time/(double)results.size(),2);
|
writer.write(closeTable() + newline());
|
||||||
writer.write(date(Double.valueOf(average_time).toString()) + newline());
|
|
||||||
//bestRes
|
|
||||||
writer.write(date(Double.valueOf(round(sum_best_result/(double)results.size(),2)).toString()) + newline());
|
|
||||||
//avgRes
|
|
||||||
Double average_result = round(sum_avg_result/(double)results.size(),2);
|
|
||||||
writer.write(date(Double.valueOf(average_result).toString()) + newline());
|
|
||||||
//worstRes
|
|
||||||
writer.write(date(Double.valueOf(round(sum_worst_result/(double)results.size(),2)).toString()) + newline());
|
|
||||||
//stdevRes
|
|
||||||
writer.write(date(Double.valueOf(round(sum_dev_result/(double)results.size(),2)).toString()) + newline());
|
|
||||||
//bestVeh
|
|
||||||
writer.write(date(Double.valueOf(round(sum_best_veh/(double)results.size(),2)).toString()) + newline());
|
|
||||||
//avgVeh
|
|
||||||
Double average_vehicles = round(sum_avg_veh/(double)results.size(),2);
|
|
||||||
writer.write(date(Double.valueOf(average_vehicles).toString()) + newline());
|
|
||||||
//worstVeh
|
|
||||||
writer.write(date(Double.valueOf(round(sum_worst_veh/(double)results.size(),2)).toString()) + newline());
|
|
||||||
//stdevVeh
|
|
||||||
writer.write(date(Double.valueOf(round(sum_dev_veh/(double)results.size(),2)).toString()) + newline());
|
|
||||||
//bestKnownRes
|
|
||||||
Double delta_res = null;
|
|
||||||
if(sum_res_star != null){
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else writer.write(date("null") + newline());
|
|
||||||
//bestKnownVeh
|
|
||||||
Double delta_veh = null;
|
|
||||||
if(sum_veh_star != null){
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
else writer.write(date("null") + newline());
|
|
||||||
writer.write(closeRow() + newline());
|
|
||||||
|
|
||||||
writer.write(closeTable() + newline());
|
writer.write("avg. percentage deviation to best-known result: " + round(delta_res, 2) + newline() + newline());
|
||||||
|
writer.write("avg. absolute deviation to best-known vehicles: " + round(delta_veh, 2) + newline());
|
||||||
|
|
||||||
writer.write("avg. percentage deviation to best-known result: " + round(delta_res,2) + newline() + newline());
|
writer.write(openTable() + newline());
|
||||||
writer.write("avg. absolute deviation to best-known vehicles: " + round(delta_veh,2) + newline());
|
writer.write(openRow() + newline());
|
||||||
|
writer.write(date("") + newline());
|
||||||
writer.write(openTable() + newline());
|
writer.write(date("") + newline());
|
||||||
writer.write(openRow() + newline());
|
writer.write(date("") + newline());
|
||||||
writer.write(date("") + newline());
|
writer.write(date("") + newline());
|
||||||
writer.write(date("") + newline());
|
writer.write(date(Double.valueOf(average_time).toString(), "align=\"right\"") + newline());
|
||||||
writer.write(date("") + newline());
|
writer.write(date(Double.valueOf(average_result).toString(), "align=\"right\"") + newline());
|
||||||
writer.write(date("") + newline());
|
writer.write(date(Double.valueOf(average_vehicles).toString(), "align=\"right\"") + newline());
|
||||||
writer.write(date(Double.valueOf(average_time).toString(),"align=\"right\"") + newline());
|
if (delta_res != null) {
|
||||||
writer.write(date(Double.valueOf(average_result).toString(),"align=\"right\"") + newline());
|
writer.write(date(Double.valueOf(round(delta_res, 2)).toString(), "align=\"right\"") + newline());
|
||||||
writer.write(date(Double.valueOf(average_vehicles).toString(),"align=\"right\"") + newline());
|
} else writer.write(date("n.a.") + newline());
|
||||||
if(delta_res != null){
|
if (delta_veh != null) {
|
||||||
writer.write(date(Double.valueOf(round(delta_res,2)).toString(),"align=\"right\"") + newline());
|
writer.write(date(Double.valueOf(round(delta_veh, 2)).toString(), "align=\"right\"") + newline());
|
||||||
}else writer.write(date("n.a.") + newline());
|
} else writer.write(date("n.a.") + newline());
|
||||||
if(delta_veh != null){
|
writer.write(closeRow() + newline());
|
||||||
writer.write(date(Double.valueOf(round(delta_veh,2)).toString(),"align=\"right\"") + newline());
|
writer.write(closeTable() + newline());
|
||||||
}else writer.write(date("n.a.") + newline());
|
|
||||||
writer.write(closeRow() + newline());
|
|
||||||
writer.write(closeTable() + newline());
|
|
||||||
|
|
||||||
|
|
||||||
writer.close();
|
writer.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String head(String string, int i) {
|
private String head(String string, int i) {
|
||||||
return "<th colspan=\""+i+"\">"+string+"</th>";
|
return "<th colspan=\"" + i + "\">" + string + "</th>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private Double round(Double value, int i) {
|
private Double round(Double value, int i) {
|
||||||
if(value==null) return null;
|
if (value == null) return null;
|
||||||
long roundedVal = Math.round(value*Math.pow(10, i));
|
long roundedVal = Math.round(value * Math.pow(10, i));
|
||||||
return (double)roundedVal/(double)(Math.pow(10, i));
|
return (double) roundedVal / (double) (Math.pow(10, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String head(String head) {
|
private String head(String head) {
|
||||||
return "<th>"+head+"</th>";
|
return "<th>" + head + "</th>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String closeTable() {
|
private String closeTable() {
|
||||||
return "</table>";
|
return "</table>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String openTable() {
|
private String openTable() {
|
||||||
return "<table>";
|
return "<table>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String closeRow() {
|
private String closeRow() {
|
||||||
return "</tr>";
|
return "</tr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String date(String date) {
|
private String date(String date) {
|
||||||
return "<td>"+date+"</td>";
|
return "<td>" + date + "</td>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String date(String date, String metaData) {
|
private String date(String date, String metaData) {
|
||||||
return "<td " + metaData + ">"+date+"</td>";
|
return "<td " + metaData + ">" + date + "</td>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String newline() {
|
private String newline() {
|
||||||
return "\n";
|
return "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String openRow() {
|
|
||||||
return "<tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private String openRow() {
|
||||||
|
return "<tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
~ Copyright (C) 2014 Stefan Schroeder
|
~ Copyright (C) 2014 Stefan Schroeder
|
||||||
~
|
~
|
||||||
|
|
@ -16,79 +15,109 @@
|
||||||
~ 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"
|
||||||
<parent>
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<groupId>jsprit</groupId>
|
<parent>
|
||||||
<artifactId>jsprit</artifactId>
|
<groupId>jsprit</groupId>
|
||||||
<version>1.6.1-SNAPSHOT</version>
|
<artifactId>jsprit</artifactId>
|
||||||
</parent>
|
<version>1.6.2-SNAPSHOT</version>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
</parent>
|
||||||
<artifactId>jsprit-core</artifactId>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<name>jsprit-core</name>
|
<artifactId>jsprit-core</artifactId>
|
||||||
|
<name>jsprit-core</name>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<pluginManagement>
|
<pluginManagement>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.m2e</groupId>
|
<groupId>org.eclipse.m2e</groupId>
|
||||||
<artifactId>lifecycle-mapping</artifactId>
|
<artifactId>lifecycle-mapping</artifactId>
|
||||||
<version>1.0.0</version>
|
<version>1.0.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<lifecycleMappingMetadata>
|
<lifecycleMappingMetadata>
|
||||||
<pluginExecutions>
|
<pluginExecutions>
|
||||||
<pluginExecution>
|
<pluginExecution>
|
||||||
<pluginExecutionFilter>
|
<pluginExecutionFilter>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-enforcer-plugin</artifactId>
|
<artifactId>maven-enforcer-plugin</artifactId>
|
||||||
<versionRange>[1.0.0,)</versionRange>
|
<versionRange>[1.0.0,)</versionRange>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>enforce</goal>
|
<goal>enforce</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</pluginExecutionFilter>
|
</pluginExecutionFilter>
|
||||||
<action>
|
<action>
|
||||||
<ignore />
|
<ignore/>
|
||||||
</action>
|
</action>
|
||||||
</pluginExecution>
|
</pluginExecution>
|
||||||
</pluginExecutions>
|
</pluginExecutions>
|
||||||
</lifecycleMappingMetadata>
|
</lifecycleMappingMetadata>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</pluginManagement>
|
</pluginManagement>
|
||||||
</build>
|
<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>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-math</artifactId>
|
|
||||||
<version>2.2</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependencies>
|
||||||
<groupId>commons-configuration</groupId>
|
|
||||||
<artifactId>commons-configuration</artifactId>
|
|
||||||
<version>1.9</version>
|
|
||||||
<type>jar</type>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>xerces</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>xerces</artifactId>
|
<artifactId>commons-math</artifactId>
|
||||||
<version>2.4.0</version>
|
<version>2.2</version>
|
||||||
<scope>compile</scope>
|
<type>jar</type>
|
||||||
</dependency>
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>commons-configuration</groupId>
|
||||||
<artifactId>commons-math3</artifactId>
|
<artifactId>commons-configuration</artifactId>
|
||||||
<version>3.4</version>
|
<version>1.9</version>
|
||||||
</dependency>
|
<type>jar</type>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
<dependency>
|
||||||
|
<groupId>xerces</groupId>
|
||||||
|
<artifactId>xercesImpl</artifactId>
|
||||||
|
<version>2.11.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-math3</artifactId>
|
||||||
|
<version>3.4</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
@ -35,32 +36,36 @@ import java.util.List;
|
||||||
|
|
||||||
public final class InsertionInitialSolutionFactory implements InitialSolutionFactory {
|
public final class InsertionInitialSolutionFactory implements InitialSolutionFactory {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(InsertionInitialSolutionFactory.class);
|
private static final Logger logger = LogManager.getLogger(InsertionInitialSolutionFactory.class);
|
||||||
|
|
||||||
private final InsertionStrategy insertion;
|
private final InsertionStrategy insertion;
|
||||||
|
|
||||||
private SolutionCostCalculator solutionCostsCalculator;
|
private SolutionCostCalculator solutionCostsCalculator;
|
||||||
|
|
||||||
public InsertionInitialSolutionFactory(InsertionStrategy insertionStrategy, SolutionCostCalculator solutionCostCalculator) {
|
public InsertionInitialSolutionFactory(InsertionStrategy insertionStrategy, SolutionCostCalculator solutionCostCalculator) {
|
||||||
super();
|
super();
|
||||||
this.insertion = insertionStrategy;
|
this.insertion = insertionStrategy;
|
||||||
this.solutionCostsCalculator = solutionCostCalculator;
|
this.solutionCostsCalculator = solutionCostCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VehicleRoutingProblemSolution createSolution(final VehicleRoutingProblem vrp) {
|
public VehicleRoutingProblemSolution createSolution(final VehicleRoutingProblem vrp) {
|
||||||
logger.info("create initial solution");
|
logger.info("create initial solution");
|
||||||
List<VehicleRoute> vehicleRoutes = new ArrayList<VehicleRoute>();
|
List<VehicleRoute> vehicleRoutes = new ArrayList<VehicleRoute>();
|
||||||
vehicleRoutes.addAll(vrp.getInitialVehicleRoutes());
|
vehicleRoutes.addAll(vrp.getInitialVehicleRoutes());
|
||||||
Collection<Job> badJobs = insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp));
|
Collection<Job> badJobs = insertion.insertJobs(vehicleRoutes, getUnassignedJobs(vrp));
|
||||||
VehicleRoutingProblemSolution solution = new VehicleRoutingProblemSolution(vehicleRoutes, badJobs, Double.MAX_VALUE);
|
VehicleRoutingProblemSolution solution = new VehicleRoutingProblemSolution(vehicleRoutes, badJobs, Double.MAX_VALUE);
|
||||||
double costs = solutionCostsCalculator.getCosts(solution);
|
double costs = solutionCostsCalculator.getCosts(solution);
|
||||||
solution.setCost(costs);
|
solution.setCost(costs);
|
||||||
return solution;
|
return solution;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -36,8 +37,8 @@ import jsprit.core.util.ActivityTimeTracker;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by schroeder on 10.12.14.
|
* Created by schroeder on 10.12.14.
|
||||||
*/
|
*/
|
||||||
public class PrettyAlgorithmBuilder {
|
public class PrettyAlgorithmBuilder {
|
||||||
|
|
||||||
private final VehicleRoutingProblem vrp;
|
private final VehicleRoutingProblem vrp;
|
||||||
|
|
@ -56,11 +57,11 @@ public class PrettyAlgorithmBuilder {
|
||||||
|
|
||||||
private boolean coreStuff = false;
|
private boolean coreStuff = false;
|
||||||
|
|
||||||
public static PrettyAlgorithmBuilder newInstance(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager){
|
public static PrettyAlgorithmBuilder newInstance(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
||||||
return new PrettyAlgorithmBuilder(vrp,fleetManager,stateManager,constraintManager);
|
return new PrettyAlgorithmBuilder(vrp, fleetManager, stateManager, constraintManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
PrettyAlgorithmBuilder(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager){
|
PrettyAlgorithmBuilder(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
this.fleetManager = fleetManager;
|
this.fleetManager = fleetManager;
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
|
|
@ -68,40 +69,41 @@ public class PrettyAlgorithmBuilder {
|
||||||
this.searchStrategyManager = new SearchStrategyManager();
|
this.searchStrategyManager = new SearchStrategyManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrettyAlgorithmBuilder setRandom(Random random){
|
public PrettyAlgorithmBuilder setRandom(Random random) {
|
||||||
searchStrategyManager.setRandom(random);
|
searchStrategyManager.setRandom(random);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrettyAlgorithmBuilder withStrategy(SearchStrategy strategy, double weight){
|
public PrettyAlgorithmBuilder withStrategy(SearchStrategy strategy, double weight) {
|
||||||
searchStrategyManager.addStrategy(strategy,weight);
|
searchStrategyManager.addStrategy(strategy, weight);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrettyAlgorithmBuilder constructInitialSolutionWith(InsertionStrategy insertionStrategy, SolutionCostCalculator objFunction){
|
public PrettyAlgorithmBuilder constructInitialSolutionWith(InsertionStrategy insertionStrategy, SolutionCostCalculator objFunction) {
|
||||||
this.iniInsertionStrategy = insertionStrategy;
|
this.iniInsertionStrategy = insertionStrategy;
|
||||||
this.iniObjFunction = objFunction;
|
this.iniObjFunction = objFunction;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VehicleRoutingAlgorithm build(){
|
public VehicleRoutingAlgorithm build() {
|
||||||
if(coreStuff){
|
if (coreStuff) {
|
||||||
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>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
|
public Collection<Vehicle> get(VehicleRoute vehicleRoute) {
|
||||||
if(uniqueTypes.isEmpty()){
|
if (uniqueTypes.isEmpty()) {
|
||||||
for( Vehicle v : vrp.getVehicles()){
|
for (Vehicle v : vrp.getVehicles()) {
|
||||||
if(!uniqueTypes.containsKey(v.getVehicleTypeIdentifier())){
|
if (!uniqueTypes.containsKey(v.getVehicleTypeIdentifier())) {
|
||||||
uniqueTypes.put(v.getVehicleTypeIdentifier(),v);
|
uniqueTypes.put(v.getVehicleTypeIdentifier(), v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -109,14 +111,16 @@ 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);
|
||||||
RemoveEmptyVehicles removeEmptyVehicles = new RemoveEmptyVehicles(fleetManager);
|
RemoveEmptyVehicles removeEmptyVehicles = new RemoveEmptyVehicles(fleetManager);
|
||||||
ResetAndIniFleetManager resetAndIniFleetManager = new ResetAndIniFleetManager(fleetManager);
|
ResetAndIniFleetManager resetAndIniFleetManager = new ResetAndIniFleetManager(fleetManager);
|
||||||
|
|
@ -124,7 +128,7 @@ public class PrettyAlgorithmBuilder {
|
||||||
vra.addListener(removeEmptyVehicles);
|
vra.addListener(removeEmptyVehicles);
|
||||||
vra.addListener(resetAndIniFleetManager);
|
vra.addListener(resetAndIniFleetManager);
|
||||||
vra.addListener(vehicleSwitched);
|
vra.addListener(vehicleSwitched);
|
||||||
if(iniInsertionStrategy != null) {
|
if (iniInsertionStrategy != null) {
|
||||||
if (!iniInsertionStrategy.getListeners().contains(removeEmptyVehicles))
|
if (!iniInsertionStrategy.getListeners().contains(removeEmptyVehicles))
|
||||||
iniInsertionStrategy.addListener(removeEmptyVehicles);
|
iniInsertionStrategy.addListener(removeEmptyVehicles);
|
||||||
if (!iniInsertionStrategy.getListeners().contains(resetAndIniFleetManager))
|
if (!iniInsertionStrategy.getListeners().contains(resetAndIniFleetManager))
|
||||||
|
|
@ -136,7 +140,9 @@ 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) {
|
||||||
solutions.add(new InsertionInitialSolutionFactory(iniInsertionStrategy, iniObjFunction).createSolution(vrp));
|
if (solutions.isEmpty()) {
|
||||||
|
solutions.add(new InsertionInitialSolutionFactory(iniInsertionStrategy, iniObjFunction).createSolution(vrp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -150,10 +156,10 @@ public class PrettyAlgorithmBuilder {
|
||||||
|
|
||||||
private void searchSchrimpfAndRegister(VehicleRoutingAlgorithm vra) {
|
private void searchSchrimpfAndRegister(VehicleRoutingAlgorithm vra) {
|
||||||
boolean schrimpfAdded = false;
|
boolean schrimpfAdded = false;
|
||||||
for(SearchStrategy strategy : vra.getSearchStrategyManager().getStrategies()){
|
for (SearchStrategy strategy : vra.getSearchStrategyManager().getStrategies()) {
|
||||||
SolutionAcceptor acceptor = strategy.getSolutionAcceptor();
|
SolutionAcceptor acceptor = strategy.getSolutionAcceptor();
|
||||||
if(acceptor instanceof SchrimpfAcceptance){
|
if (acceptor instanceof SchrimpfAcceptance) {
|
||||||
if(!schrimpfAdded) {
|
if (!schrimpfAdded) {
|
||||||
vra.addListener((SchrimpfAcceptance) acceptor);
|
vra.addListener((SchrimpfAcceptance) acceptor);
|
||||||
schrimpfAdded = true;
|
schrimpfAdded = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,28 +25,28 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class RemoveEmptyVehicles implements InsertionEndsListener{
|
public class RemoveEmptyVehicles implements InsertionEndsListener {
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
public RemoveEmptyVehicles(VehicleFleetManager fleetManager) {
|
public RemoveEmptyVehicles(VehicleFleetManager fleetManager) {
|
||||||
super();
|
super();
|
||||||
this.fleetManager = fleetManager;
|
this.fleetManager = fleetManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=removeEmptyVehicles]";
|
return "[name=removeEmptyVehicles]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
|
List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
|
||||||
for(VehicleRoute route : routes){
|
for (VehicleRoute route : routes) {
|
||||||
if(route.isEmpty()) {
|
if (route.isEmpty()) {
|
||||||
fleetManager.unlock(route.getVehicle());
|
fleetManager.unlock(route.getVehicle());
|
||||||
vehicleRoutes.remove(route);
|
vehicleRoutes.remove(route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,26 +25,26 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
public class ResetAndIniFleetManager implements InsertionStartsListener{
|
public class ResetAndIniFleetManager implements InsertionStartsListener {
|
||||||
|
|
||||||
private VehicleFleetManager vehicleFleetManager;
|
private VehicleFleetManager vehicleFleetManager;
|
||||||
|
|
||||||
public ResetAndIniFleetManager(VehicleFleetManager vehicleFleetManager) {
|
public ResetAndIniFleetManager(VehicleFleetManager vehicleFleetManager) {
|
||||||
super();
|
super();
|
||||||
this.vehicleFleetManager = vehicleFleetManager;
|
this.vehicleFleetManager = vehicleFleetManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
vehicleFleetManager.unlockAll();
|
vehicleFleetManager.unlockAll();
|
||||||
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
|
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
|
||||||
for(VehicleRoute route : routes){
|
for (VehicleRoute route : routes) {
|
||||||
vehicleFleetManager.lock(route.getVehicle());
|
vehicleFleetManager.lock(route.getVehicle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=resetAndIniFleetManager]";
|
return "[name=resetAndIniFleetManager]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,63 +32,65 @@ import java.util.Collections;
|
||||||
|
|
||||||
public class SearchStrategy {
|
public class SearchStrategy {
|
||||||
|
|
||||||
public static class DiscoveredSolution {
|
public static class DiscoveredSolution {
|
||||||
|
|
||||||
private VehicleRoutingProblemSolution solution;
|
private VehicleRoutingProblemSolution solution;
|
||||||
|
|
||||||
private boolean accepted;
|
private boolean accepted;
|
||||||
|
|
||||||
private String strategyId;
|
private String strategyId;
|
||||||
|
|
||||||
public DiscoveredSolution(VehicleRoutingProblemSolution solution, boolean accepted, String strategyId) {
|
public DiscoveredSolution(VehicleRoutingProblemSolution solution, boolean accepted, String strategyId) {
|
||||||
super();
|
super();
|
||||||
this.solution = solution;
|
this.solution = solution;
|
||||||
this.accepted = accepted;
|
this.accepted = accepted;
|
||||||
this.strategyId = strategyId;
|
this.strategyId = strategyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VehicleRoutingProblemSolution getSolution() {
|
public VehicleRoutingProblemSolution getSolution() {
|
||||||
return solution;
|
return solution;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAccepted() {
|
public boolean isAccepted() {
|
||||||
return accepted;
|
return accepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public String getStrategyName() {
|
public String getStrategyName() {
|
||||||
return strategyId;
|
return strategyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStrategyId() { return strategyId; }
|
public String getStrategyId() {
|
||||||
|
return strategyId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[strategyId="+strategyId+"][solution="+solution+"][accepted="+accepted+"]";
|
return "[strategyId=" + strategyId + "][solution=" + solution + "][accepted=" + accepted + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(SearchStrategy.class);
|
private static Logger logger = LogManager.getLogger(SearchStrategy.class);
|
||||||
|
|
||||||
private final Collection<SearchStrategyModule> searchStrategyModules = new ArrayList<SearchStrategyModule>();
|
private final Collection<SearchStrategyModule> searchStrategyModules = new ArrayList<SearchStrategyModule>();
|
||||||
|
|
||||||
private final SolutionSelector solutionSelector;
|
private final SolutionSelector solutionSelector;
|
||||||
|
|
||||||
private final SolutionCostCalculator solutionCostCalculator;
|
private final SolutionCostCalculator solutionCostCalculator;
|
||||||
|
|
||||||
private final SolutionAcceptor solutionAcceptor;
|
private final SolutionAcceptor solutionAcceptor;
|
||||||
|
|
||||||
private final String id;
|
private final String id;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
public SearchStrategy(String id, SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor, SolutionCostCalculator solutionCostCalculator) {
|
public SearchStrategy(String id, SolutionSelector solutionSelector, SolutionAcceptor solutionAcceptor, SolutionCostCalculator solutionCostCalculator) {
|
||||||
if(id == null) throw new IllegalStateException("strategy id cannot be null");
|
if (id == null) throw new IllegalStateException("strategy id cannot be null");
|
||||||
this.solutionSelector = solutionSelector;
|
this.solutionSelector = solutionSelector;
|
||||||
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() {
|
||||||
|
|
@ -96,77 +98,77 @@ public class SearchStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<SearchStrategyModule> getSearchStrategyModules() {
|
public Collection<SearchStrategyModule> getSearchStrategyModules() {
|
||||||
return Collections.unmodifiableCollection(searchStrategyModules);
|
return Collections.unmodifiableCollection(searchStrategyModules);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
|
||||||
public SolutionSelector getSolutionSelector() {
|
|
||||||
return solutionSelector;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
public SolutionAcceptor getSolutionAcceptor() {
|
public SolutionSelector getSolutionSelector() {
|
||||||
return solutionAcceptor;
|
return solutionSelector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
public String toString() {
|
public SolutionAcceptor getSolutionAcceptor() {
|
||||||
return "searchStrategy [#modules="+searchStrategyModules.size()+"][selector="+solutionSelector+"][acceptor="+solutionAcceptor+"]";
|
return solutionAcceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Runs the search-strategy and its according modules, and returns DiscoveredSolution.
|
public String toString() {
|
||||||
*
|
return "searchStrategy [#modules=" + searchStrategyModules.size() + "][selector=" + solutionSelector + "][acceptor=" + solutionAcceptor + "]";
|
||||||
* <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}.
|
|
||||||
* <p> Note that after 1) the selected solution is copied, thus the original solution is not modified.
|
/**
|
||||||
* <p> Note also that 3) modifies the input parameter solutions by adding, removing, replacing the existing solutions or whatever is defined in the solutionAcceptor.
|
* Runs the search-strategy and its according modules, and returns DiscoveredSolution.
|
||||||
*
|
* <p/>
|
||||||
* @param vrp the underlying vehicle routing problem
|
* <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
|
||||||
* @param solutions which will be modified
|
* ({@link jsprit.core.algorithm.SearchStrategyModule}) on the selectedSolution and 3) accepting the new solution according to {@link jsprit.core.algorithm.acceptor.SolutionAcceptor}.
|
||||||
* @return discoveredSolution
|
* <p> Note that after 1) the selected solution is copied, thus the original solution is not modified.
|
||||||
|
* <p> Note also that 3) modifies the input parameter solutions by adding, removing, replacing the existing solutions or whatever is defined in the solutionAcceptor.
|
||||||
|
*
|
||||||
|
* @param vrp the underlying vehicle routing problem
|
||||||
|
* @param solutions which will be modified
|
||||||
|
* @return discoveredSolution
|
||||||
* @throws java.lang.IllegalStateException if selector cannot select any solution
|
* @throws java.lang.IllegalStateException if selector cannot select any solution
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedParameters")
|
@SuppressWarnings("UnusedParameters")
|
||||||
public DiscoveredSolution run(VehicleRoutingProblem vrp, Collection<VehicleRoutingProblemSolution> solutions){
|
public DiscoveredSolution run(VehicleRoutingProblem vrp, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
VehicleRoutingProblemSolution solution = solutionSelector.selectSolution(solutions);
|
VehicleRoutingProblemSolution solution = solutionSelector.selectSolution(solutions);
|
||||||
if(solution == null) throw new IllegalStateException(getErrMsg());
|
if (solution == null) throw new IllegalStateException(getErrMsg());
|
||||||
VehicleRoutingProblemSolution lastSolution = VehicleRoutingProblemSolution.copyOf(solution);
|
VehicleRoutingProblemSolution lastSolution = VehicleRoutingProblemSolution.copyOf(solution);
|
||||||
for(SearchStrategyModule module : searchStrategyModules){
|
for (SearchStrategyModule module : searchStrategyModules) {
|
||||||
lastSolution = module.runAndGetSolution(lastSolution);
|
lastSolution = module.runAndGetSolution(lastSolution);
|
||||||
}
|
}
|
||||||
double costs = solutionCostCalculator.getCosts(lastSolution);
|
double costs = solutionCostCalculator.getCosts(lastSolution);
|
||||||
lastSolution.setCost(costs);
|
lastSolution.setCost(costs);
|
||||||
boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution);
|
boolean solutionAccepted = solutionAcceptor.acceptSolution(solutions, lastSolution);
|
||||||
return new DiscoveredSolution(lastSolution, solutionAccepted, getId());
|
return new DiscoveredSolution(lastSolution, solutionAccepted, getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getErrMsg() {
|
private String getErrMsg() {
|
||||||
return "solution is null. check solutionSelector to return an appropriate solution. " +
|
return "solution is null. check solutionSelector to return an appropriate solution. " +
|
||||||
"\nfigure out whether you start with an initial solution. either you set it manually by algorithm.addInitialSolution(...)"
|
"\nfigure out whether you start with an initial solution. either you set it manually by algorithm.addInitialSolution(...)"
|
||||||
+ " or let the algorithm create an initial solution for you. then add the <construction>...</construction> xml-snippet to your algorithm's config file.";
|
+ " or let the algorithm create an initial solution for you. then add the <construction>...</construction> xml-snippet to your algorithm's config file.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
for(SearchStrategyModule module : searchStrategyModules){
|
for (SearchStrategyModule module : searchStrategyModules) {
|
||||||
module.addModuleListener(moduleListener);
|
module.addModuleListener(moduleListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,71 +27,75 @@ import java.util.*;
|
||||||
|
|
||||||
public class SearchStrategyManager {
|
public class SearchStrategyManager {
|
||||||
|
|
||||||
private final static Logger logger = LogManager.getLogger();
|
private final static Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
private List<SearchStrategyListener> searchStrategyListeners = new ArrayList<SearchStrategyListener>();
|
private List<SearchStrategyListener> searchStrategyListeners = new ArrayList<SearchStrategyListener>();
|
||||||
|
|
||||||
private List<SearchStrategy> strategies = new ArrayList<SearchStrategy>();
|
private List<SearchStrategy> strategies = new ArrayList<SearchStrategy>();
|
||||||
|
|
||||||
private List<Double> weights = new ArrayList<Double>();
|
private List<Double> weights = new ArrayList<Double>();
|
||||||
|
|
||||||
private Map<String, Integer> id2index = new HashMap<String,Integer>();
|
private Map<String, Integer> id2index = new HashMap<String, Integer>();
|
||||||
|
|
||||||
private Random random = RandomNumberGeneration.getRandom();
|
private Random random = RandomNumberGeneration.getRandom();
|
||||||
|
|
||||||
private double sumWeights = 0;
|
private double sumWeights = 0;
|
||||||
|
|
||||||
private int strategyIndex = 0;
|
private int strategyIndex = 0;
|
||||||
|
|
||||||
public void setRandom(Random random) {
|
public void setRandom(Random random) {
|
||||||
this.random = random;
|
this.random = random;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SearchStrategy> getStrategies() {
|
public List<SearchStrategy> getStrategies() {
|
||||||
return Collections.unmodifiableList(strategies);
|
return Collections.unmodifiableList(strategies);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
public List<Double> getProbabilities() {
|
public List<Double> getProbabilities() {
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 weight of corresponding strategy to be added
|
* @param strategy 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
|
||||||
*/
|
*/
|
||||||
public void addStrategy(SearchStrategy strategy, double weight){
|
public void addStrategy(SearchStrategy strategy, double weight) {
|
||||||
if(strategy == null){
|
if (strategy == null) {
|
||||||
throw new IllegalStateException("strategy is null. make sure adding a valid strategy.");
|
throw new IllegalStateException("strategy is null. make sure adding a valid strategy.");
|
||||||
}
|
}
|
||||||
if(id2index.keySet().contains(strategy.getId())){
|
if (id2index.keySet().contains(strategy.getId())) {
|
||||||
throw new IllegalStateException("strategyId " + strategy.getId() + " already in use. replace strateId in your config file or code with a unique strategy id");
|
throw new IllegalStateException("strategyId " + strategy.getId() + " already in use. replace strateId in your config file or code with a unique strategy id");
|
||||||
}
|
}
|
||||||
if(weight < 0.0){
|
if (weight < 0.0) {
|
||||||
throw new IllegalStateException("weight is lower than zero.");
|
throw new IllegalStateException("weight is lower than zero.");
|
||||||
}
|
}
|
||||||
id2index.put(strategy.getId(),strategyIndex);
|
id2index.put(strategy.getId(), strategyIndex);
|
||||||
strategyIndex++;
|
strategyIndex++;
|
||||||
strategies.add(strategy);
|
strategies.add(strategy);
|
||||||
weights.add(weight);
|
weights.add(weight);
|
||||||
sumWeights += weight;
|
sumWeights += weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void informStrategyWeightChanged(String strategyId, double weight){
|
public void informStrategyWeightChanged(String strategyId, double weight) {
|
||||||
int strategyIndex = id2index.get(strategyId);
|
int strategyIndex = id2index.get(strategyId);
|
||||||
weights.set(strategyIndex, weight);
|
weights.set(strategyIndex, weight);
|
||||||
updateSumWeights();
|
updateSumWeights();
|
||||||
|
|
@ -99,7 +103,7 @@ public class SearchStrategyManager {
|
||||||
|
|
||||||
private void updateSumWeights() {
|
private void updateSumWeights() {
|
||||||
double sum = 0.;
|
double sum = 0.;
|
||||||
for(double w : weights){
|
for (double w : weights) {
|
||||||
sum += w;
|
sum += w;
|
||||||
}
|
}
|
||||||
sumWeights = sum;
|
sumWeights = sum;
|
||||||
|
|
@ -111,26 +115,27 @@ public class SearchStrategyManager {
|
||||||
* @return selected search strategy
|
* @return selected search strategy
|
||||||
* @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)
|
||||||
double randomFig = random.nextDouble();
|
throw new IllegalStateException("randomizer is null. make sure you set random object correctly");
|
||||||
double sumProbabilities = 0.0;
|
double randomFig = random.nextDouble();
|
||||||
for (int i = 0; i < weights.size(); i++) {
|
double sumProbabilities = 0.0;
|
||||||
sumProbabilities += weights.get(i) / sumWeights;
|
for (int i = 0; i < weights.size(); i++) {
|
||||||
if (randomFig < sumProbabilities) {
|
sumProbabilities += weights.get(i) / sumWeights;
|
||||||
return strategies.get(i);
|
if (randomFig < sumProbabilities) {
|
||||||
}
|
return strategies.get(i);
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("no search-strategy found");
|
}
|
||||||
}
|
throw new IllegalStateException("no search-strategy found");
|
||||||
|
}
|
||||||
|
|
||||||
public void addSearchStrategyListener(SearchStrategyListener strategyListener){
|
public void addSearchStrategyListener(SearchStrategyListener strategyListener) {
|
||||||
searchStrategyListeners.add(strategyListener);
|
searchStrategyListeners.add(strategyListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSearchStrategyModuleListener(SearchStrategyModuleListener moduleListener){
|
public void addSearchStrategyModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
for(SearchStrategy s : strategies){
|
for (SearchStrategy s : strategies) {
|
||||||
s.addModuleListener(moduleListener);
|
s.addModuleListener(moduleListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,10 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
|
|
||||||
public interface SearchStrategyModule {
|
public interface SearchStrategyModule {
|
||||||
|
|
||||||
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution);
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution);
|
||||||
|
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
public void addModuleListener(SearchStrategyModuleListener moduleListener);
|
public void addModuleListener(SearchStrategyModuleListener moduleListener);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,37 +31,36 @@ import jsprit.core.problem.vehicle.Vehicle;
|
||||||
* this objective function.
|
* this objective function.
|
||||||
*
|
*
|
||||||
* @author schroeder
|
* @author schroeder
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class VariablePlusFixedSolutionCostCalculatorFactory {
|
public class VariablePlusFixedSolutionCostCalculatorFactory {
|
||||||
|
|
||||||
private RouteAndActivityStateGetter stateManager;
|
private RouteAndActivityStateGetter stateManager;
|
||||||
|
|
||||||
public VariablePlusFixedSolutionCostCalculatorFactory(RouteAndActivityStateGetter stateManager) {
|
public VariablePlusFixedSolutionCostCalculatorFactory(RouteAndActivityStateGetter stateManager) {
|
||||||
super();
|
super();
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SolutionCostCalculator createCalculator(){
|
public SolutionCostCalculator createCalculator() {
|
||||||
return new SolutionCostCalculator() {
|
return new SolutionCostCalculator() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCosts(VehicleRoutingProblemSolution solution) {
|
public double getCosts(VehicleRoutingProblemSolution solution) {
|
||||||
double c = 0.0;
|
double c = 0.0;
|
||||||
for(VehicleRoute r : solution.getRoutes()){
|
for (VehicleRoute r : solution.getRoutes()) {
|
||||||
c += stateManager.getRouteState(r, InternalStates.COSTS, Double.class);
|
c += stateManager.getRouteState(r, InternalStates.COSTS, Double.class);
|
||||||
c += getFixedCosts(r.getVehicle());
|
c += getFixedCosts(r.getVehicle());
|
||||||
}
|
}
|
||||||
c += solution.getUnassignedJobs().size() * c * .1;
|
c += solution.getUnassignedJobs().size() * c * .1;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getFixedCosts(Vehicle vehicle) {
|
private double getFixedCosts(Vehicle vehicle) {
|
||||||
if(vehicle == null) return 0.0;
|
if (vehicle == null) return 0.0;
|
||||||
if(vehicle.getType() == null) return 0.0;
|
if (vehicle.getType() == null) return 0.0;
|
||||||
return vehicle.getType().getVehicleCostParams().fix;
|
return vehicle.getType().getVehicleCostParams().fix;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
|
@ -43,14 +43,14 @@ public class VehicleRoutingAlgorithm {
|
||||||
|
|
||||||
private Collection<PrematureAlgorithmTermination> terminationCriteria = new ArrayList<PrematureAlgorithmTermination>();
|
private Collection<PrematureAlgorithmTermination> terminationCriteria = new ArrayList<PrematureAlgorithmTermination>();
|
||||||
|
|
||||||
void addTermination(PrematureAlgorithmTermination termination){
|
void addTermination(PrematureAlgorithmTermination termination) {
|
||||||
terminationCriteria.add(termination);
|
terminationCriteria.add(termination);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) {
|
public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) {
|
||||||
for(PrematureAlgorithmTermination termination : terminationCriteria){
|
for (PrematureAlgorithmTermination termination : terminationCriteria) {
|
||||||
if(termination.isPrematureBreak(discoveredSolution)){
|
if (termination.isPrematureBreak(discoveredSolution)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -59,31 +59,31 @@ public class VehicleRoutingAlgorithm {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Counter {
|
private static class Counter {
|
||||||
private final String name;
|
private final String name;
|
||||||
private long counter = 0;
|
private long counter = 0;
|
||||||
private long nextCounter = 1;
|
private long nextCounter = 1;
|
||||||
private static final Logger log = LogManager.getLogger(Counter.class);
|
private static final Logger log = LogManager.getLogger(Counter.class);
|
||||||
|
|
||||||
public Counter(final String name) {
|
public Counter(final String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incCounter() {
|
public void incCounter() {
|
||||||
long i = counter++;
|
long i = counter++;
|
||||||
long n = nextCounter;
|
long n = nextCounter;
|
||||||
if (i >= n) {
|
if (i >= n) {
|
||||||
nextCounter=n*2;
|
nextCounter = n * 2;
|
||||||
log.info(this.name + n);
|
log.info(this.name + n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
counter=0;
|
counter = 0;
|
||||||
nextCounter=1;
|
nextCounter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static Logger logger = LogManager.getLogger();
|
private final static Logger logger = LogManager.getLogger();
|
||||||
|
|
||||||
private final Counter counter = new Counter("iterations ");
|
private final Counter counter = new Counter("iterations ");
|
||||||
|
|
||||||
|
|
@ -101,62 +101,62 @@ public class VehicleRoutingAlgorithm {
|
||||||
|
|
||||||
private VehicleRoutingProblemSolution bestEver = null;
|
private VehicleRoutingProblemSolution bestEver = null;
|
||||||
|
|
||||||
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, SearchStrategyManager searchStrategyManager) {
|
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, SearchStrategyManager searchStrategyManager) {
|
||||||
super();
|
super();
|
||||||
this.problem = problem;
|
this.problem = problem;
|
||||||
this.searchStrategyManager = searchStrategyManager;
|
this.searchStrategyManager = searchStrategyManager;
|
||||||
initialSolutions = new ArrayList<VehicleRoutingProblemSolution>();
|
initialSolutions = new ArrayList<VehicleRoutingProblemSolution>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> initialSolutions, SearchStrategyManager searchStrategyManager) {
|
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> initialSolutions, SearchStrategyManager searchStrategyManager) {
|
||||||
super();
|
super();
|
||||||
this.problem = problem;
|
this.problem = problem;
|
||||||
this.searchStrategyManager = searchStrategyManager;
|
this.searchStrategyManager = searchStrategyManager;
|
||||||
this.initialSolutions = initialSolutions;
|
this.initialSolutions = initialSolutions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds solution to the collection of initial solutions.
|
* Adds solution to the collection of initial solutions.
|
||||||
*
|
*
|
||||||
* @param solution the solution to be added
|
* @param solution the solution to be added
|
||||||
*/
|
*/
|
||||||
public void addInitialSolution(VehicleRoutingProblemSolution solution){
|
public void addInitialSolution(VehicleRoutingProblemSolution solution) {
|
||||||
verify(solution);
|
verify(solution);
|
||||||
initialSolutions.add(solution);
|
initialSolutions.add(solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verify(VehicleRoutingProblemSolution solution) {
|
private void verify(VehicleRoutingProblemSolution solution) {
|
||||||
int nuJobs = 0;
|
int nuJobs = 0;
|
||||||
for(VehicleRoute route : solution.getRoutes()){
|
for (VehicleRoute route : solution.getRoutes()) {
|
||||||
nuJobs += route.getTourActivities().getJobs().size();
|
nuJobs += route.getTourActivities().getJobs().size();
|
||||||
if(route.getVehicle().getIndex() == 0)
|
if (route.getVehicle().getIndex() == 0)
|
||||||
throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " +
|
throw new IllegalStateException("vehicle used in initial solution has no index. probably a vehicle is used that has not been added to the " +
|
||||||
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
|
" the VehicleRoutingProblem. only use vehicles that have already been added to the problem.");
|
||||||
for(TourActivity act : route.getActivities()) {
|
for (TourActivity act : route.getActivities()) {
|
||||||
if (act.getIndex() == 0) {
|
if (act.getIndex() == 0) {
|
||||||
throw new IllegalStateException("act in initial solution has no index. activities are created and associated to their job in VehicleRoutingProblem\n." +
|
throw new IllegalStateException("act in initial solution has no index. activities are created and associated to their job in VehicleRoutingProblem\n." +
|
||||||
" thus if you build vehicle-routes use the jobActivityFactory from vehicle routing problem like that \n" +
|
" thus if you build vehicle-routes use the jobActivityFactory from vehicle routing problem like that \n" +
|
||||||
" VehicleRoute.Builder.newInstance(knownVehicle).setJobActivityFactory(vrp.getJobActivityFactory).addService(..)....build() \n" +
|
" VehicleRoute.Builder.newInstance(knownVehicle).setJobActivityFactory(vrp.getJobActivityFactory).addService(..)....build() \n" +
|
||||||
" then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem");
|
" then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets premature termination and overrides existing termination criteria. If existing ones should not be
|
* Sets premature termination and overrides existing termination criteria. If existing ones should not be
|
||||||
* overridden use <code>.addTerminationCriterion(...)</code>.
|
* overridden use <code>.addTerminationCriterion(...)</code>.
|
||||||
*
|
*
|
||||||
* @param prematureAlgorithmTermination the termination criterion
|
* @param prematureAlgorithmTermination the termination criterion
|
||||||
*/
|
*/
|
||||||
public void setPrematureAlgorithmTermination(PrematureAlgorithmTermination prematureAlgorithmTermination){
|
public void setPrematureAlgorithmTermination(PrematureAlgorithmTermination prematureAlgorithmTermination) {
|
||||||
terminationManager = new TerminationManager();
|
terminationManager = new TerminationManager();
|
||||||
terminationManager.addTermination(prematureAlgorithmTermination);
|
terminationManager.addTermination(prematureAlgorithmTermination);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a termination criterion to the collection of already specified termination criteria. If one
|
* Adds a termination criterion to the collection of already specified termination criteria. If one
|
||||||
|
|
@ -164,101 +164,137 @@ public class VehicleRoutingAlgorithm {
|
||||||
*
|
*
|
||||||
* @param terminationCriterion the termination criterion
|
* @param terminationCriterion the termination criterion
|
||||||
*/
|
*/
|
||||||
public void addTerminationCriterion(PrematureAlgorithmTermination terminationCriterion){
|
public void addTerminationCriterion(PrematureAlgorithmTermination terminationCriterion) {
|
||||||
terminationManager.addTermination(terminationCriterion);
|
terminationManager.addTermination(terminationCriterion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link SearchStrategyManager}.
|
* Gets the {@link SearchStrategyManager}.
|
||||||
*
|
*
|
||||||
* @return SearchStrategyManager
|
* @return SearchStrategyManager
|
||||||
*/
|
*/
|
||||||
public SearchStrategyManager getSearchStrategyManager() {
|
public SearchStrategyManager getSearchStrategyManager() {
|
||||||
return searchStrategyManager;
|
return searchStrategyManager;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs the vehicle routing algorithm and returns a number of generated solutions.
|
|
||||||
*
|
|
||||||
* <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.
|
|
||||||
* <p>Note that clients are allowed to observe/listen the algorithm. See {@link VehicleRoutingAlgorithmListener} and its according listeners.
|
|
||||||
*
|
|
||||||
* @return Collection<VehicleRoutingProblemSolution> the solutions
|
|
||||||
* @see {@link SearchStrategyManager}, {@link VehicleRoutingAlgorithmListener}, {@link AlgorithmStartsListener}, {@link AlgorithmEndsListener}, {@link IterationStartsListener}, {@link IterationEndsListener}
|
|
||||||
*/
|
|
||||||
public Collection<VehicleRoutingProblemSolution> searchSolutions(){
|
|
||||||
logger.info("algorithm starts: " + "[maxIterations=" + maxIterations + "]");
|
|
||||||
double now = System.currentTimeMillis();
|
|
||||||
int noIterationsThisAlgoIsRunning = maxIterations;
|
|
||||||
counter.reset();
|
|
||||||
Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions);
|
|
||||||
algorithmStarts(problem,solutions);
|
|
||||||
bestEver = Solutions.bestOf(solutions);
|
|
||||||
logger.info("iterations start");
|
|
||||||
for(int i=0;i< maxIterations;i++){
|
|
||||||
iterationStarts(i+1,problem,solutions);
|
|
||||||
logger.debug("start iteration: " + i);
|
|
||||||
counter.incCounter();
|
|
||||||
SearchStrategy strategy = searchStrategyManager.getRandomStrategy();
|
|
||||||
DiscoveredSolution discoveredSolution = strategy.run(problem, solutions);
|
|
||||||
logger.trace("discovered solution: " + discoveredSolution);
|
|
||||||
memorizeIfBestEver(discoveredSolution);
|
|
||||||
selectedStrategy(discoveredSolution,problem,solutions);
|
|
||||||
if(terminationManager.isPrematureBreak(discoveredSolution)){
|
|
||||||
logger.info("premature algorithm termination at iteration "+ (i+1));
|
|
||||||
noIterationsThisAlgoIsRunning = (i+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
iterationEnds(i+1,problem,solutions);
|
|
||||||
}
|
|
||||||
logger.info("iterations end at " + noIterationsThisAlgoIsRunning + " iterations");
|
|
||||||
addBestEver(solutions);
|
|
||||||
algorithmEnds(problem, solutions);
|
|
||||||
logger.info("took " + ((System.currentTimeMillis()-now)/1000.0) + " seconds");
|
|
||||||
return solutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addBestEver(Collection<VehicleRoutingProblemSolution> solutions) {
|
|
||||||
if(bestEver != null) solutions.add(bestEver);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @return Collection<VehicleRoutingProblemSolution> the solutions
|
||||||
|
* @see {@link SearchStrategyManager}, {@link VehicleRoutingAlgorithmListener}, {@link AlgorithmStartsListener}, {@link AlgorithmEndsListener}, {@link IterationStartsListener}, {@link IterationEndsListener}
|
||||||
|
*/
|
||||||
|
public Collection<VehicleRoutingProblemSolution> searchSolutions() {
|
||||||
|
logger.info("algorithm starts: [maxIterations={}]", maxIterations);
|
||||||
|
double now = System.currentTimeMillis();
|
||||||
|
int noIterationsThisAlgoIsRunning = maxIterations;
|
||||||
|
counter.reset();
|
||||||
|
Collection<VehicleRoutingProblemSolution> solutions = new ArrayList<VehicleRoutingProblemSolution>(initialSolutions);
|
||||||
|
algorithmStarts(problem, solutions);
|
||||||
|
bestEver = Solutions.bestOf(solutions);
|
||||||
|
if (logger.isTraceEnabled()) log(solutions);
|
||||||
|
logger.info("iterations start");
|
||||||
|
for (int i = 0; i < maxIterations; i++) {
|
||||||
|
iterationStarts(i + 1, problem, solutions);
|
||||||
|
logger.debug("start iteration: {}", i);
|
||||||
|
counter.incCounter();
|
||||||
|
SearchStrategy strategy = searchStrategyManager.getRandomStrategy();
|
||||||
|
DiscoveredSolution discoveredSolution = strategy.run(problem, solutions);
|
||||||
|
if (logger.isTraceEnabled()) log(discoveredSolution);
|
||||||
|
memorizeIfBestEver(discoveredSolution);
|
||||||
|
selectedStrategy(discoveredSolution, problem, solutions);
|
||||||
|
if (terminationManager.isPrematureBreak(discoveredSolution)) {
|
||||||
|
logger.info("premature algorithm termination at iteration {}", (i + 1));
|
||||||
|
noIterationsThisAlgoIsRunning = (i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
iterationEnds(i + 1, problem, solutions);
|
||||||
|
}
|
||||||
|
logger.info("iterations end at {} iterations", noIterationsThisAlgoIsRunning);
|
||||||
|
addBestEver(solutions);
|
||||||
|
algorithmEnds(problem, solutions);
|
||||||
|
logger.info("took {} seconds", ((System.currentTimeMillis() - now) / 1000.0));
|
||||||
|
return solutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBestEver(Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void selectedStrategy(DiscoveredSolution discoveredSolution, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
private void selectedStrategy(DiscoveredSolution discoveredSolution, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
algoListeners.selectedStrategy(discoveredSolution,problem,solutions);
|
algoListeners.selectedStrategy(discoveredSolution, problem, solutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
private void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
algoListeners.algorithmEnds(problem, solutions);
|
algoListeners.algorithmEnds(problem, solutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VehicleRoutingAlgorithmListeners getAlgorithmListeners() {
|
public VehicleRoutingAlgorithmListeners getAlgorithmListeners() {
|
||||||
return algoListeners;
|
return algoListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
algoListeners.iterationEnds(i,problem, solutions);
|
algoListeners.iterationEnds(i, problem, solutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
private void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
algoListeners.iterationStarts(i, problem, solutions);
|
algoListeners.iterationStarts(i, problem, solutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void algorithmStarts(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
private void algorithmStarts(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
algoListeners.algorithmStarts(problem, this, solutions);
|
algoListeners.algorithmStarts(problem, this, solutions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets max number of iterations.
|
* Sets max number of iterations.
|
||||||
|
|
@ -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,151 +29,149 @@ 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 {
|
||||||
|
|
||||||
private String algorithmConfigFile;
|
private String algorithmConfigFile;
|
||||||
|
|
||||||
private AlgorithmConfig algorithmConfig;
|
private AlgorithmConfig algorithmConfig;
|
||||||
|
|
||||||
private final VehicleRoutingProblem vrp;
|
private final VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private SolutionCostCalculator solutionCostCalculator;
|
private SolutionCostCalculator solutionCostCalculator;
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateManager stateManager;
|
||||||
|
|
||||||
private boolean addCoreConstraints = false;
|
private boolean addCoreConstraints = false;
|
||||||
|
|
||||||
private boolean addDefaultCostCalculators = false;
|
private boolean addDefaultCostCalculators = false;
|
||||||
|
|
||||||
private ConstraintManager constraintManager;
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
private int nuOfThreads=0;
|
private int nuOfThreads = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the builder with the problem and an algorithmConfigFile. Latter is to configure and specify the ruin-and-recreate meta-heuristic.
|
* Constructs the builder with the problem and an algorithmConfigFile. Latter is to configure and specify the ruin-and-recreate meta-heuristic.
|
||||||
*
|
*
|
||||||
* @param problem to solve
|
* @param problem to solve
|
||||||
* @param algorithmConfig config file of VehicleRoutingAlgorithm
|
|
||||||
*/
|
|
||||||
public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, String algorithmConfig) {
|
|
||||||
this.vrp=problem;
|
|
||||||
this.algorithmConfigFile=algorithmConfig;
|
|
||||||
this.algorithmConfig=null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs the builder with the problem and an algorithmConfig. Latter is to configure and specify the ruin-and-recreate meta-heuristic.
|
|
||||||
*
|
|
||||||
* @param problem to solve
|
|
||||||
* @param algorithmConfig config file of VehicleRoutingAlgorithm
|
* @param algorithmConfig config file of VehicleRoutingAlgorithm
|
||||||
*/
|
*/
|
||||||
public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, AlgorithmConfig algorithmConfig) {
|
public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, String algorithmConfig) {
|
||||||
this.vrp=problem;
|
this.vrp = problem;
|
||||||
this.algorithmConfigFile=null;
|
this.algorithmConfigFile = algorithmConfig;
|
||||||
this.algorithmConfig=algorithmConfig;
|
this.algorithmConfig = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets custom objective function.
|
* Constructs the builder with the problem and an algorithmConfig. Latter is to configure and specify the ruin-and-recreate meta-heuristic.
|
||||||
*
|
*
|
||||||
* <p>If objective function is not set, a default function is applied (which basically minimizes
|
* @param problem to solve
|
||||||
* fixed and variable transportation costs ({@link VariablePlusFixedSolutionCostCalculatorFactory}).
|
* @param algorithmConfig config file of VehicleRoutingAlgorithm
|
||||||
*
|
*/
|
||||||
* @param objectiveFunction to be minimized
|
public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, AlgorithmConfig algorithmConfig) {
|
||||||
* @see VariablePlusFixedSolutionCostCalculatorFactory
|
this.vrp = problem;
|
||||||
*/
|
this.algorithmConfigFile = null;
|
||||||
public void setObjectiveFunction(SolutionCostCalculator objectiveFunction) {
|
this.algorithmConfig = algorithmConfig;
|
||||||
this.solutionCostCalculator = objectiveFunction;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets stateManager to memorize states.
|
* Sets custom objective function.
|
||||||
*
|
* <p/>
|
||||||
* @param stateManager that memorizes your states
|
* <p>If objective function is not set, a default function is applied (which basically minimizes
|
||||||
* @see StateManager
|
* fixed and variable transportation costs ({@link VariablePlusFixedSolutionCostCalculatorFactory}).
|
||||||
*/
|
*
|
||||||
public void setStateManager(StateManager stateManager) {
|
* @param objectiveFunction to be minimized
|
||||||
this.stateManager=stateManager;
|
* @see VariablePlusFixedSolutionCostCalculatorFactory
|
||||||
}
|
*/
|
||||||
|
public void setObjectiveFunction(SolutionCostCalculator objectiveFunction) {
|
||||||
|
this.solutionCostCalculator = objectiveFunction;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds core constraints.
|
* Sets stateManager to memorize states.
|
||||||
*
|
*
|
||||||
* <p>Thus, it adds vehicle-capacity, time-window and skills constraints and their
|
* @param stateManager that memorizes your states
|
||||||
* required stateUpdater.
|
* @see StateManager
|
||||||
*
|
*/
|
||||||
*/
|
public void setStateManager(StateManager stateManager) {
|
||||||
public void addCoreConstraints() {
|
this.stateManager = stateManager;
|
||||||
addCoreConstraints=true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds default cost calculators used by the insertion heuristic,
|
* Adds core constraints.
|
||||||
* to calculate activity insertion costs.
|
* <p/>
|
||||||
* By default, marginal transportation costs are calculated. Thus when inserting
|
* <p>Thus, it adds vehicle-capacity, time-window and skills constraints and their
|
||||||
* act_k between act_i and act_j, marginal (additional) transportation costs
|
* required stateUpdater.
|
||||||
* are basically c(act_i,act_k)+c(act_k,act_j)-c(act_i,act_j).
|
*/
|
||||||
*
|
public void addCoreConstraints() {
|
||||||
* <p>Do not use this method, if you plan to control the insertion heuristic
|
addCoreConstraints = true;
|
||||||
* entirely via hard- and soft-constraints.
|
}
|
||||||
*/
|
|
||||||
public void addDefaultCostCalculators() {
|
|
||||||
addDefaultCostCalculators=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets state- and constraintManager.
|
* Adds default cost calculators used by the insertion heuristic,
|
||||||
*
|
* to calculate activity insertion costs.
|
||||||
* @param stateManager that memorizes your states
|
* By default, marginal transportation costs are calculated. Thus when inserting
|
||||||
* @param constraintManager that manages your constraints
|
* act_k between act_i and act_j, marginal (additional) transportation costs
|
||||||
* @see StateManager
|
* are basically c(act_i,act_k)+c(act_k,act_j)-c(act_i,act_j).
|
||||||
* @see ConstraintManager
|
* <p/>
|
||||||
*/
|
* <p>Do not use this method, if you plan to control the insertion heuristic
|
||||||
public void setStateAndConstraintManager(StateManager stateManager, ConstraintManager constraintManager) {
|
* entirely via hard- and soft-constraints.
|
||||||
this.stateManager=stateManager;
|
*/
|
||||||
this.constraintManager=constraintManager;
|
public void addDefaultCostCalculators() {
|
||||||
}
|
addDefaultCostCalculators = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets nuOfThreads.
|
* Sets state- and constraintManager.
|
||||||
*
|
*
|
||||||
* @param nuOfThreads to be operated
|
* @param stateManager that memorizes your states
|
||||||
*/
|
* @param constraintManager that manages your constraints
|
||||||
public void setNuOfThreads(int nuOfThreads){
|
* @see StateManager
|
||||||
this.nuOfThreads=nuOfThreads;
|
* @see ConstraintManager
|
||||||
}
|
*/
|
||||||
|
public void setStateAndConstraintManager(StateManager stateManager, ConstraintManager constraintManager) {
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.constraintManager = constraintManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and returns the algorithm.
|
* Sets nuOfThreads.
|
||||||
*
|
*
|
||||||
* <p>If algorithmConfigFile is set, it reads the configuration.
|
* @param nuOfThreads to be operated
|
||||||
*
|
*/
|
||||||
* @return the algorithm
|
public void setNuOfThreads(int nuOfThreads) {
|
||||||
*/
|
this.nuOfThreads = nuOfThreads;
|
||||||
public VehicleRoutingAlgorithm build() {
|
}
|
||||||
if(stateManager == null) stateManager = new StateManager(vrp);
|
|
||||||
if(constraintManager == null) constraintManager = new ConstraintManager(vrp,stateManager);
|
/**
|
||||||
//add core updater
|
* Builds and returns the algorithm.
|
||||||
stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen());
|
* <p/>
|
||||||
|
* <p>If algorithmConfigFile is set, it reads the configuration.
|
||||||
|
*
|
||||||
|
* @return the algorithm
|
||||||
|
*/
|
||||||
|
public VehicleRoutingAlgorithm build() {
|
||||||
|
if (stateManager == null) stateManager = new StateManager(vrp);
|
||||||
|
if (constraintManager == null) constraintManager = new ConstraintManager(vrp, stateManager);
|
||||||
|
//add core updater
|
||||||
|
stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen());
|
||||||
// stateManager.addStateUpdater(new OpenRouteStateVerifier());
|
// stateManager.addStateUpdater(new OpenRouteStateVerifier());
|
||||||
|
|
||||||
if(addCoreConstraints){
|
if (addCoreConstraints) {
|
||||||
constraintManager.addLoadConstraint();
|
constraintManager.addLoadConstraint();
|
||||||
constraintManager.addTimeWindowConstraint();
|
constraintManager.addTimeWindowConstraint();
|
||||||
constraintManager.addSkillsConstraint();
|
constraintManager.addSkillsConstraint();
|
||||||
stateManager.updateLoadStates();
|
stateManager.updateLoadStates();
|
||||||
stateManager.updateTimeWindowStates();
|
stateManager.updateTimeWindowStates();
|
||||||
stateManager.updateSkillStates();
|
stateManager.updateSkillStates();
|
||||||
}
|
}
|
||||||
if(algorithmConfig==null){
|
if (algorithmConfig == null) {
|
||||||
algorithmConfig = new AlgorithmConfig();
|
algorithmConfig = new AlgorithmConfig();
|
||||||
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
|
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
|
||||||
xmlReader.read(algorithmConfigFile);
|
xmlReader.read(algorithmConfigFile);
|
||||||
}
|
}
|
||||||
return VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, algorithmConfig, nuOfThreads, solutionCostCalculator, stateManager, constraintManager, addDefaultCostCalculators);
|
return VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, algorithmConfig, nuOfThreads, solutionCostCalculator, stateManager, constraintManager, addDefaultCostCalculators);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,6 @@ import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
|
|
||||||
public interface VehicleRoutingAlgorithmFactory {
|
public interface VehicleRoutingAlgorithmFactory {
|
||||||
|
|
||||||
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp);
|
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,35 +24,33 @@ import java.util.Collection;
|
||||||
* @deprecated use GreedyAcceptance instead
|
* @deprecated use GreedyAcceptance instead
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class AcceptNewRemoveFirst implements SolutionAcceptor{
|
public class AcceptNewRemoveFirst implements SolutionAcceptor {
|
||||||
|
|
||||||
private final int solutionMemory;
|
private final int solutionMemory;
|
||||||
|
|
||||||
public AcceptNewRemoveFirst(int solutionMemory){
|
public AcceptNewRemoveFirst(int solutionMemory) {
|
||||||
this.solutionMemory = solutionMemory;
|
this.solutionMemory = solutionMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
|
||||||
if (solutions.size() >= solutionMemory) {
|
|
||||||
solutions.remove(solutions.iterator().next());
|
|
||||||
}
|
|
||||||
solutions.add(newSolution);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[name=acceptNewRemoveFirst]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* <p/>
|
||||||
|
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
if (solutions.size() >= solutionMemory) {
|
||||||
|
solutions.remove(solutions.iterator().next());
|
||||||
|
}
|
||||||
|
solutions.add(newSolution);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=acceptNewRemoveFirst]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,122 +35,120 @@ import java.net.URL;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, IterationStartsListener, AlgorithmStartsListener{
|
public class ExperimentalSchrimpfAcceptance implements SolutionAcceptor, IterationStartsListener, AlgorithmStartsListener {
|
||||||
|
|
||||||
final static Logger logger = LogManager.getLogger(ExperimentalSchrimpfAcceptance.class.getName());
|
final static Logger logger = LogManager.getLogger(ExperimentalSchrimpfAcceptance.class.getName());
|
||||||
|
|
||||||
private final double alpha;
|
private final double alpha;
|
||||||
|
|
||||||
private int nOfTotalIterations = 1000;
|
private int nOfTotalIterations = 1000;
|
||||||
|
|
||||||
private int currentIteration = 0;
|
private int currentIteration = 0;
|
||||||
|
|
||||||
private double initialThreshold = 0.0;
|
private double initialThreshold = 0.0;
|
||||||
|
|
||||||
private final int nOfRandomWalks;
|
private final int nOfRandomWalks;
|
||||||
|
|
||||||
private final int solutionMemory;
|
private final int solutionMemory;
|
||||||
|
|
||||||
|
|
||||||
public ExperimentalSchrimpfAcceptance(int solutionMemory, double alpha, int nOfWarmupIterations) {
|
public ExperimentalSchrimpfAcceptance(int solutionMemory, double alpha, int nOfWarmupIterations) {
|
||||||
super();
|
super();
|
||||||
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
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
boolean solutionAccepted = false;
|
||||||
|
if (solutions.size() < solutionMemory) {
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else {
|
||||||
|
VehicleRoutingProblemSolution worst = null;
|
||||||
|
double threshold = getThreshold(currentIteration);
|
||||||
|
for (VehicleRoutingProblemSolution solutionInMemory : solutions) {
|
||||||
|
if (worst == null) worst = solutionInMemory;
|
||||||
|
else if (solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory;
|
||||||
|
}
|
||||||
|
if (newSolution.getRoutes().size() < worst.getRoutes().size()) {
|
||||||
|
solutions.remove(worst);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else if (newSolution.getRoutes().size() == worst.getRoutes().size() && newSolution.getCost() < worst.getCost() + threshold) {
|
||||||
|
solutions.remove(worst);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return solutionAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
public String toString() {
|
||||||
boolean solutionAccepted = false;
|
return "[name=schrimpfAcceptanceFunction][alpha=" + alpha + "][warmup=" + nOfRandomWalks + "]";
|
||||||
if (solutions.size() < solutionMemory) {
|
}
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
} else {
|
|
||||||
VehicleRoutingProblemSolution worst = null;
|
|
||||||
double threshold = getThreshold(currentIteration);
|
|
||||||
for(VehicleRoutingProblemSolution solutionInMemory : solutions){
|
|
||||||
if(worst == null) worst = solutionInMemory;
|
|
||||||
else if(solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory;
|
|
||||||
}
|
|
||||||
if(newSolution.getRoutes().size() < worst.getRoutes().size()){
|
|
||||||
solutions.remove(worst);
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
}
|
|
||||||
else if(newSolution.getRoutes().size() == worst.getRoutes().size() && newSolution.getCost() < worst.getCost() + threshold){
|
|
||||||
solutions.remove(worst);
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return solutionAccepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private double getThreshold(int iteration) {
|
||||||
public String toString() {
|
double scheduleVariable = (double) iteration / (double) nOfTotalIterations;
|
||||||
return "[name=schrimpfAcceptanceFunction][alpha="+alpha+"][warmup=" + nOfRandomWalks + "]";
|
// logger.debug("iter={} totalIter={} scheduling={}", iteration, nOfTotalIterations, scheduleVariable);
|
||||||
}
|
double currentThreshold = initialThreshold * Math.exp(-Math.log(2) * scheduleVariable / alpha);
|
||||||
|
return currentThreshold;
|
||||||
private double getThreshold(int iteration) {
|
}
|
||||||
double scheduleVariable = (double) iteration / (double) nOfTotalIterations;
|
|
||||||
// logger.debug("iter="+iteration+" totalIter="+nOfTotalIterations+" scheduling="+scheduleVariable);
|
|
||||||
double currentThreshold = initialThreshold * Math.exp(-Math.log(2) * scheduleVariable / alpha);
|
|
||||||
return currentThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
reset();
|
reset();
|
||||||
logger.info("---------------------------------------------------------------------");
|
logger.info("---------------------------------------------------------------------");
|
||||||
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
|
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
|
||||||
logger.info("start random-walk (see randomWalk.xml)");
|
logger.info("start random-walk (see randomWalk.xml)");
|
||||||
double now = System.currentTimeMillis();
|
double now = System.currentTimeMillis();
|
||||||
this.nOfTotalIterations = algorithm.getMaxIterations();
|
this.nOfTotalIterations = algorithm.getMaxIterations();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* randomWalk to determine standardDev
|
* randomWalk to determine standardDev
|
||||||
*/
|
*/
|
||||||
final double[] results = new double[nOfRandomWalks];
|
final double[] results = new double[nOfRandomWalks];
|
||||||
|
|
||||||
URL resource = Resource.getAsURL("randomWalk.xml");
|
URL resource = Resource.getAsURL("randomWalk.xml");
|
||||||
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
||||||
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
|
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
|
||||||
vra.setMaxIterations(nOfRandomWalks);
|
vra.setMaxIterations(nOfRandomWalks);
|
||||||
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
|
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
|
||||||
|
|
||||||
@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;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
vra.searchSolutions();
|
vra.searchSolutions();
|
||||||
|
|
||||||
StandardDeviation dev = new StandardDeviation();
|
StandardDeviation dev = new StandardDeviation();
|
||||||
double standardDeviation = dev.evaluate(results);
|
double standardDeviation = dev.evaluate(results);
|
||||||
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("---------------------------------------------------------------------");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset() {
|
private void reset() {
|
||||||
currentIteration = 0;
|
currentIteration = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
currentIteration = i;
|
currentIteration = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,51 +23,49 @@ 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>
|
||||||
*/
|
*/
|
||||||
public class GreedyAcceptance implements SolutionAcceptor{
|
public class GreedyAcceptance implements SolutionAcceptor {
|
||||||
|
|
||||||
private final int solutionMemory;
|
private final int solutionMemory;
|
||||||
|
|
||||||
public GreedyAcceptance(int solutionMemory){
|
public GreedyAcceptance(int solutionMemory) {
|
||||||
this.solutionMemory = solutionMemory;
|
this.solutionMemory = solutionMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
|
||||||
boolean solutionAccepted = false;
|
|
||||||
if (solutions.size() < solutionMemory) {
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
} else {
|
|
||||||
VehicleRoutingProblemSolution worstSolution = null;
|
|
||||||
for (VehicleRoutingProblemSolution s : solutions) {
|
|
||||||
if (worstSolution == null) worstSolution = s;
|
|
||||||
else if (s.getCost() > worstSolution.getCost()) worstSolution = s;
|
|
||||||
}
|
|
||||||
if(newSolution.getCost() < worstSolution.getCost()){
|
|
||||||
solutions.remove(worstSolution);
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return solutionAccepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[name=GreedyAcceptance]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* <p/>
|
||||||
|
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
boolean solutionAccepted = false;
|
||||||
|
if (solutions.size() < solutionMemory) {
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else {
|
||||||
|
VehicleRoutingProblemSolution worstSolution = null;
|
||||||
|
for (VehicleRoutingProblemSolution s : solutions) {
|
||||||
|
if (worstSolution == null) worstSolution = s;
|
||||||
|
else if (s.getCost() > worstSolution.getCost()) worstSolution = s;
|
||||||
|
}
|
||||||
|
if (newSolution.getCost() < worstSolution.getCost()) {
|
||||||
|
solutions.remove(worstSolution);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return solutionAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=GreedyAcceptance]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,52 +22,49 @@ import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public class GreedyAcceptance_minVehFirst implements SolutionAcceptor{
|
public class GreedyAcceptance_minVehFirst implements SolutionAcceptor {
|
||||||
|
|
||||||
private final int solutionMemory;
|
private final int solutionMemory;
|
||||||
|
|
||||||
public GreedyAcceptance_minVehFirst(int solutionMemory){
|
public GreedyAcceptance_minVehFirst(int solutionMemory) {
|
||||||
this.solutionMemory = solutionMemory;
|
this.solutionMemory = solutionMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
|
||||||
boolean solutionAccepted = false;
|
|
||||||
if (solutions.size() < solutionMemory) {
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
} else {
|
|
||||||
VehicleRoutingProblemSolution worstSolution = null;
|
|
||||||
for (VehicleRoutingProblemSolution s : solutions) {
|
|
||||||
if (worstSolution == null) worstSolution = s;
|
|
||||||
else if (s.getRoutes().size() > worstSolution.getRoutes().size()) worstSolution = s;
|
|
||||||
}
|
|
||||||
if(newSolution.getRoutes().size() < worstSolution.getRoutes().size()){
|
|
||||||
solutions.remove(worstSolution);
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
}
|
|
||||||
else if(newSolution.getRoutes().size() == worstSolution.getRoutes().size() && newSolution.getCost() < worstSolution.getCost()){
|
|
||||||
solutions.remove(worstSolution);
|
|
||||||
solutions.add(newSolution);
|
|
||||||
solutionAccepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return solutionAccepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[name=greedyAcceptance_minVehFirst]";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* <p/>
|
||||||
|
* <p>Note that this modifies Collection<VehicleRoutingProblemSolution> solutions.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
|
boolean solutionAccepted = false;
|
||||||
|
if (solutions.size() < solutionMemory) {
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else {
|
||||||
|
VehicleRoutingProblemSolution worstSolution = null;
|
||||||
|
for (VehicleRoutingProblemSolution s : solutions) {
|
||||||
|
if (worstSolution == null) worstSolution = s;
|
||||||
|
else if (s.getRoutes().size() > worstSolution.getRoutes().size()) worstSolution = s;
|
||||||
|
}
|
||||||
|
if (newSolution.getRoutes().size() < worstSolution.getRoutes().size()) {
|
||||||
|
solutions.remove(worstSolution);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else if (newSolution.getRoutes().size() == worstSolution.getRoutes().size() && newSolution.getCost() < worstSolution.getCost()) {
|
||||||
|
solutions.remove(worstSolution);
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return solutionAccepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=greedyAcceptance_minVehFirst]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,102 +55,99 @@ 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 {
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(SchrimpfAcceptance.class.getName());
|
private static Logger logger = LogManager.getLogger(SchrimpfAcceptance.class.getName());
|
||||||
|
|
||||||
private final double alpha;
|
private final double alpha;
|
||||||
|
|
||||||
private int maxIterations = 1000;
|
private int maxIterations = 1000;
|
||||||
|
|
||||||
private int currentIteration = 0;
|
private int currentIteration = 0;
|
||||||
|
|
||||||
private double initialThreshold = 0.0;
|
private double initialThreshold = 0.0;
|
||||||
|
|
||||||
private final int solutionMemory;
|
private final int solutionMemory;
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
|
||||||
boolean solutionAccepted = false;
|
boolean solutionAccepted = false;
|
||||||
if (solutions.size() < solutionMemory) {
|
if (solutions.size() < solutionMemory) {
|
||||||
solutions.add(newSolution);
|
solutions.add(newSolution);
|
||||||
solutionAccepted = true;
|
solutionAccepted = true;
|
||||||
} else {
|
} else {
|
||||||
VehicleRoutingProblemSolution worst = null;
|
VehicleRoutingProblemSolution worst = null;
|
||||||
double threshold = getThreshold(currentIteration);
|
double threshold = getThreshold(currentIteration);
|
||||||
for(VehicleRoutingProblemSolution solutionInMemory : solutions){
|
for (VehicleRoutingProblemSolution solutionInMemory : solutions) {
|
||||||
if(worst == null) worst = solutionInMemory;
|
if (worst == null) worst = solutionInMemory;
|
||||||
else if(solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory;
|
else if (solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory;
|
||||||
}
|
}
|
||||||
if(worst == null){
|
if (worst == null) {
|
||||||
|
solutions.add(newSolution);
|
||||||
|
solutionAccepted = true;
|
||||||
|
} else if (newSolution.getCost() < worst.getCost() + threshold) {
|
||||||
|
solutions.remove(worst);
|
||||||
solutions.add(newSolution);
|
solutions.add(newSolution);
|
||||||
solutionAccepted = true;
|
solutionAccepted = true;
|
||||||
}
|
}
|
||||||
else if(newSolution.getCost() < worst.getCost() + threshold){
|
}
|
||||||
solutions.remove(worst);
|
return solutionAccepted;
|
||||||
solutions.add(newSolution);
|
}
|
||||||
solutionAccepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return solutionAccepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=SchrimpfAcceptance][alpha="+alpha+"]";
|
return "[name=SchrimpfAcceptance][alpha=" + alpha + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getThreshold(int iteration) {
|
private double getThreshold(int iteration) {
|
||||||
double scheduleVariable = (double) iteration / (double) maxIterations;
|
double scheduleVariable = (double) iteration / (double) maxIterations;
|
||||||
return initialThreshold * Math.exp(-1. * Math.log(2) * scheduleVariable / alpha);
|
return initialThreshold * Math.exp(-1. * Math.log(2) * scheduleVariable / alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
public double getInitialThreshold(){
|
public double getInitialThreshold() {
|
||||||
return initialThreshold;
|
return initialThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets initial threshold.
|
* Sets initial threshold.
|
||||||
* <p>Note that if initial threshold has been set, automatic generation of initial threshold is disabled.
|
* <p>Note that if initial threshold has been set, automatic generation of initial threshold is disabled.
|
||||||
*
|
*
|
||||||
* @param initialThreshold the initialThreshold to set
|
* @param initialThreshold the initialThreshold to set
|
||||||
*/
|
*/
|
||||||
public void setInitialThreshold(double initialThreshold) {
|
public void setInitialThreshold(double initialThreshold) {
|
||||||
this.initialThreshold = initialThreshold;
|
this.initialThreshold = initialThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
reset();
|
reset();
|
||||||
this.maxIterations = algorithm.getMaxIterations();
|
this.maxIterations = algorithm.getMaxIterations();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset() {
|
private void reset() {
|
||||||
currentIteration = 0;
|
currentIteration = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
currentIteration = i;
|
currentIteration = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,54 +35,54 @@ import java.util.Collection;
|
||||||
|
|
||||||
public class SchrimpfInitialThresholdGenerator implements AlgorithmStartsListener {
|
public class SchrimpfInitialThresholdGenerator implements AlgorithmStartsListener {
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(SchrimpfInitialThresholdGenerator.class.getName());
|
private static Logger logger = LogManager.getLogger(SchrimpfInitialThresholdGenerator.class.getName());
|
||||||
|
|
||||||
private SchrimpfAcceptance schrimpfAcceptance;
|
private SchrimpfAcceptance schrimpfAcceptance;
|
||||||
|
|
||||||
private int nOfRandomWalks;
|
private int nOfRandomWalks;
|
||||||
|
|
||||||
public SchrimpfInitialThresholdGenerator(SchrimpfAcceptance schrimpfAcceptance, int nOfRandomWalks) {
|
public SchrimpfInitialThresholdGenerator(SchrimpfAcceptance schrimpfAcceptance, int nOfRandomWalks) {
|
||||||
super();
|
super();
|
||||||
this.schrimpfAcceptance = schrimpfAcceptance;
|
this.schrimpfAcceptance = schrimpfAcceptance;
|
||||||
this.nOfRandomWalks = nOfRandomWalks;
|
this.nOfRandomWalks = nOfRandomWalks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informAlgorithmStarts(VehicleRoutingProblem problem,VehicleRoutingAlgorithm algorithm,Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
|
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
|
||||||
double now = System.currentTimeMillis();
|
double now = System.currentTimeMillis();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* randomWalk to determine standardDev
|
* randomWalk to determine standardDev
|
||||||
*/
|
*/
|
||||||
final double[] results = new double[nOfRandomWalks];
|
final double[] results = new double[nOfRandomWalks];
|
||||||
|
|
||||||
URL resource = Resource.getAsURL("randomWalk.xml");
|
URL resource = Resource.getAsURL("randomWalk.xml");
|
||||||
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
||||||
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
|
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
|
||||||
vra.setMaxIterations(nOfRandomWalks);
|
vra.setMaxIterations(nOfRandomWalks);
|
||||||
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
|
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
|
||||||
|
|
||||||
@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;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
vra.searchSolutions();
|
vra.searchSolutions();
|
||||||
|
|
||||||
StandardDeviation dev = new StandardDeviation();
|
StandardDeviation dev = new StandardDeviation();
|
||||||
double standardDeviation = dev.evaluate(results);
|
double standardDeviation = dev.evaluate(results);
|
||||||
double initialThreshold = standardDeviation / 2;
|
double initialThreshold = standardDeviation / 2;
|
||||||
|
|
||||||
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,21 +25,19 @@ 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
|
||||||
* @param newSolution new solution to be evaluated
|
* @param newSolution new solution to be evaluated
|
||||||
* @return true if solution accepted
|
* @return true if solution accepted
|
||||||
*/
|
*/
|
||||||
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution);
|
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,41 +26,38 @@ 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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the {@link VehicleRoutingAlgorithm}.
|
* Creates the {@link VehicleRoutingAlgorithm}.
|
||||||
*
|
*
|
||||||
* @param vrp
|
* @param vrp
|
||||||
* @return algorithm
|
* @return algorithm
|
||||||
*/
|
*/
|
||||||
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp){
|
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp) {
|
||||||
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
URL resource = Resource.getAsURL("greedySchrimpf.xml");
|
URL resource = Resource.getAsURL("greedySchrimpf.xml");
|
||||||
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
||||||
return VehicleRoutingAlgorithms.createAlgorithm(vrp, algorithmConfig);
|
return VehicleRoutingAlgorithms.createAlgorithm(vrp, algorithmConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,92 +1,60 @@
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by schroeder on 16/01/15.
|
* Created by schroeder on 16/01/15.
|
||||||
*/
|
*/
|
||||||
class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsListener {
|
class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsListener {
|
||||||
|
|
||||||
private final double noiseProbability;
|
private final double noiseProbability;
|
||||||
|
|
||||||
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
|
||||||
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) {
|
||||||
if(makeNoise) {
|
if (makeNoise) {
|
||||||
return noiseLevel * maxCosts * random.nextDouble();
|
return noiseLevel * maxCosts * random.nextDouble();
|
||||||
}
|
}
|
||||||
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,17 +35,19 @@ 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");
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
Construction(String name){
|
Construction(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(){
|
public String toString() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -63,11 +66,11 @@ public class Jsprit {
|
||||||
|
|
||||||
String strategyName;
|
String strategyName;
|
||||||
|
|
||||||
Strategy(String strategyName){
|
Strategy(String strategyName) {
|
||||||
this.strategyName = strategyName;
|
this.strategyName = strategyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(){
|
public String toString() {
|
||||||
return strategyName;
|
return strategyName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +78,7 @@ public class Jsprit {
|
||||||
public enum Parameter {
|
public enum Parameter {
|
||||||
|
|
||||||
FIXED_COST_PARAM("fixed_cost_param"), VEHICLE_SWITCH("vehicle_switch"), REGRET_TIME_WINDOW_SCORER("regret.tw_scorer"),
|
FIXED_COST_PARAM("fixed_cost_param"), VEHICLE_SWITCH("vehicle_switch"), REGRET_TIME_WINDOW_SCORER("regret.tw_scorer"),
|
||||||
REGRET_DISTANCE_SCORER("regret.distance_scorer"), INITIAL_THRESHOLD("initial_threshold"), ITERATIONS("iterations"),
|
REGRET_DISTANCE_SCORER("regret.distance_scorer"), INITIAL_THRESHOLD("initial_threshold"), ITERATIONS("iterations"),
|
||||||
THREADS("threads"),
|
THREADS("threads"),
|
||||||
RANDOM_REGRET_MIN_SHARE("random_regret.min_share"),
|
RANDOM_REGRET_MIN_SHARE("random_regret.min_share"),
|
||||||
RANDOM_REGRET_MAX_SHARE("random_regret.max_share"),
|
RANDOM_REGRET_MAX_SHARE("random_regret.max_share"),
|
||||||
|
|
@ -93,21 +96,23 @@ 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;
|
||||||
|
|
||||||
Parameter(String name){
|
Parameter(String name) {
|
||||||
this.paraName = name;
|
this.paraName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(){
|
public String toString() {
|
||||||
return paraName;
|
return paraName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vehicleRoutingProblem){
|
public static VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
return Jsprit.Builder.newInstance(vehicleRoutingProblem).buildAlgorithm();
|
return Jsprit.Builder.newInstance(vehicleRoutingProblem).buildAlgorithm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,53 +136,56 @@ public class Jsprit {
|
||||||
|
|
||||||
private Random random = RandomNumberGeneration.newInstance();
|
private Random random = RandomNumberGeneration.newInstance();
|
||||||
|
|
||||||
public static Builder newInstance(VehicleRoutingProblem vrp){
|
private ActivityInsertionCostsCalculator activityInsertionCalculator;
|
||||||
|
|
||||||
|
public static Builder newInstance(VehicleRoutingProblem vrp) {
|
||||||
return new Builder(vrp);
|
return new Builder(vrp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Builder(VehicleRoutingProblem vrp){
|
private Builder(VehicleRoutingProblem vrp) {
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
properties = new Properties(createDefaultProperties());
|
properties = new Properties(createDefaultProperties());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties createDefaultProperties() {
|
private Properties createDefaultProperties() {
|
||||||
Properties defaults = new Properties();
|
Properties defaults = new Properties();
|
||||||
defaults.put(Strategy.RADIAL_BEST.toString(),"0.");
|
defaults.put(Strategy.RADIAL_BEST.toString(), "0.");
|
||||||
defaults.put(Strategy.RADIAL_REGRET.toString(),".5");
|
defaults.put(Strategy.RADIAL_REGRET.toString(), ".5");
|
||||||
defaults.put(Strategy.RANDOM_BEST.toString(),".5");
|
defaults.put(Strategy.RANDOM_BEST.toString(), ".5");
|
||||||
defaults.put(Strategy.RANDOM_REGRET.toString(),".5");
|
defaults.put(Strategy.RANDOM_REGRET.toString(), ".5");
|
||||||
defaults.put(Strategy.WORST_BEST.toString(),"0.");
|
defaults.put(Strategy.WORST_BEST.toString(), "0.");
|
||||||
defaults.put(Strategy.WORST_REGRET.toString(),"1.");
|
defaults.put(Strategy.WORST_REGRET.toString(), "1.");
|
||||||
defaults.put(Strategy.CLUSTER_BEST.toString(),"0.");
|
defaults.put(Strategy.CLUSTER_BEST.toString(), "0.");
|
||||||
defaults.put(Strategy.CLUSTER_REGRET.toString(),"1.");
|
defaults.put(Strategy.CLUSTER_REGRET.toString(), "1.");
|
||||||
defaults.put(Parameter.FIXED_COST_PARAM.toString(),"0.");
|
defaults.put(Parameter.FIXED_COST_PARAM.toString(), "0.");
|
||||||
defaults.put(Parameter.VEHICLE_SWITCH.toString(),"true");
|
defaults.put(Parameter.VEHICLE_SWITCH.toString(), "true");
|
||||||
defaults.put(Parameter.ITERATIONS.toString(),"2000");
|
defaults.put(Parameter.ITERATIONS.toString(), "2000");
|
||||||
defaults.put(Parameter.REGRET_DISTANCE_SCORER.toString(),".05");
|
defaults.put(Parameter.REGRET_DISTANCE_SCORER.toString(), ".05");
|
||||||
defaults.put(Parameter.REGRET_TIME_WINDOW_SCORER.toString(),"-.1");
|
defaults.put(Parameter.REGRET_TIME_WINDOW_SCORER.toString(), "-.1");
|
||||||
defaults.put(Parameter.THREADS.toString(),"1");
|
defaults.put(Parameter.THREADS.toString(), "1");
|
||||||
int minShare = (int)Math.min(20, Math.max(3,vrp.getJobs().size() * 0.05));
|
int minShare = (int) Math.min(20, Math.max(3, vrp.getJobs().size() * 0.05));
|
||||||
int maxShare = (int)Math.min(50, Math.max(5,vrp.getJobs().size() * 0.3));
|
int maxShare = (int) Math.min(50, Math.max(5, vrp.getJobs().size() * 0.3));
|
||||||
defaults.put(Parameter.RADIAL_MIN_SHARE.toString(),String.valueOf(minShare));
|
defaults.put(Parameter.RADIAL_MIN_SHARE.toString(), String.valueOf(minShare));
|
||||||
defaults.put(Parameter.RADIAL_MAX_SHARE.toString(),String.valueOf(maxShare));
|
defaults.put(Parameter.RADIAL_MAX_SHARE.toString(), String.valueOf(maxShare));
|
||||||
defaults.put(Parameter.WORST_MIN_SHARE.toString(),String.valueOf(minShare));
|
defaults.put(Parameter.WORST_MIN_SHARE.toString(), String.valueOf(minShare));
|
||||||
defaults.put(Parameter.WORST_MAX_SHARE.toString(),String.valueOf(maxShare));
|
defaults.put(Parameter.WORST_MAX_SHARE.toString(), String.valueOf(maxShare));
|
||||||
defaults.put(Parameter.CLUSTER_MIN_SHARE.toString(),String.valueOf(minShare));
|
defaults.put(Parameter.CLUSTER_MIN_SHARE.toString(), String.valueOf(minShare));
|
||||||
defaults.put(Parameter.CLUSTER_MAX_SHARE.toString(),String.valueOf(maxShare));
|
defaults.put(Parameter.CLUSTER_MAX_SHARE.toString(), String.valueOf(maxShare));
|
||||||
int minShare_ = (int)Math.min(70, Math.max(5,vrp.getJobs().size() * 0.5));
|
int minShare_ = (int) Math.min(70, Math.max(5, vrp.getJobs().size() * 0.5));
|
||||||
int maxShare_ = (int)Math.min(70, Math.max(5,vrp.getJobs().size() * 0.5));
|
int maxShare_ = (int) Math.min(70, Math.max(5, vrp.getJobs().size() * 0.5));
|
||||||
defaults.put(Parameter.RANDOM_REGRET_MIN_SHARE.toString(),String.valueOf(minShare_));
|
defaults.put(Parameter.RANDOM_REGRET_MIN_SHARE.toString(), String.valueOf(minShare_));
|
||||||
defaults.put(Parameter.RANDOM_REGRET_MAX_SHARE.toString(),String.valueOf(maxShare_));
|
defaults.put(Parameter.RANDOM_REGRET_MAX_SHARE.toString(), String.valueOf(maxShare_));
|
||||||
defaults.put(Parameter.RANDOM_BEST_MIN_SHARE.toString(),String.valueOf(minShare_));
|
defaults.put(Parameter.RANDOM_BEST_MIN_SHARE.toString(), String.valueOf(minShare_));
|
||||||
defaults.put(Parameter.RANDOM_BEST_MAX_SHARE.toString(),String.valueOf(maxShare_));
|
defaults.put(Parameter.RANDOM_BEST_MAX_SHARE.toString(), String.valueOf(maxShare_));
|
||||||
defaults.put(Parameter.THRESHOLD_ALPHA.toString(),String.valueOf(0.15));
|
defaults.put(Parameter.THRESHOLD_ALPHA.toString(), String.valueOf(0.15));
|
||||||
defaults.put(Parameter.THRESHOLD_INI.toString(),String.valueOf(0.03));
|
defaults.put(Parameter.THRESHOLD_INI.toString(), String.valueOf(0.03));
|
||||||
defaults.put(Parameter.INSERTION_NOISE_LEVEL.toString(),String.valueOf(0.15));
|
defaults.put(Parameter.INSERTION_NOISE_LEVEL.toString(), String.valueOf(0.15));
|
||||||
defaults.put(Parameter.INSERTION_NOISE_PROB.toString(),String.valueOf(0.2));
|
defaults.put(Parameter.INSERTION_NOISE_PROB.toString(), String.valueOf(0.2));
|
||||||
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.CONSTRUCTION.toString(),Construction.REGRET_INSERTION.toString());
|
defaults.put(Parameter.FAST_REGRET, String.valueOf(false));
|
||||||
|
defaults.put(Parameter.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString());
|
||||||
return defaults;
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,23 +196,23 @@ public class Jsprit {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setRandom(Random random){
|
public Builder setRandom(Random random) {
|
||||||
this.random = random;
|
this.random = random;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setProperty(String key, String value){
|
public Builder setProperty(String key, String value) {
|
||||||
properties.put(key,value);
|
properties.put(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setProperty(Parameter parameter, String value){
|
public Builder setProperty(Parameter parameter, String value) {
|
||||||
setProperty(parameter.toString(),value);
|
setProperty(parameter.toString(), value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setProperty(Strategy strategy, String value){
|
public Builder setProperty(Strategy strategy, String value) {
|
||||||
setProperty(strategy.toString(),value);
|
setProperty(strategy.toString(), value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,7 +232,12 @@ public class Jsprit {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VehicleRoutingAlgorithm buildAlgorithm(){
|
public Builder setActivityInsertionCalculator(ActivityInsertionCostsCalculator activityInsertionCalculator) {
|
||||||
|
this.activityInsertionCalculator = activityInsertionCalculator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,61 +306,93 @@ 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);
|
||||||
}
|
}
|
||||||
if(constraintManager == null){
|
if (constraintManager == null) {
|
||||||
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();
|
||||||
|
|
||||||
RuinRadial radial = new RuinRadial(vrp,vrp.getJobs().size(),jobNeighborhoods);
|
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);
|
||||||
radial.setRandom(random);
|
radial.setRandom(random);
|
||||||
radial.setRuinShareFactory(new RuinShareFactoryImpl(
|
radial.setRuinShareFactory(new RuinShareFactoryImpl(
|
||||||
toInteger(properties.getProperty(Parameter.RADIAL_MIN_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.RADIAL_MIN_SHARE.toString())),
|
||||||
toInteger(properties.getProperty(Parameter.RADIAL_MAX_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.RADIAL_MAX_SHARE.toString())),
|
||||||
random)
|
random)
|
||||||
);
|
);
|
||||||
|
|
||||||
final RuinRandom random_for_regret = new RuinRandom(vrp,0.5);
|
final RuinRandom random_for_regret = new RuinRandom(vrp, 0.5);
|
||||||
random_for_regret.setRandom(random);
|
random_for_regret.setRandom(random);
|
||||||
random_for_regret.setRuinShareFactory(new RuinShareFactoryImpl(
|
random_for_regret.setRuinShareFactory(new RuinShareFactoryImpl(
|
||||||
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MIN_SHARE.toString())),
|
||||||
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.RANDOM_REGRET_MAX_SHARE.toString())),
|
||||||
random)
|
random)
|
||||||
);
|
);
|
||||||
|
|
||||||
final RuinRandom random_for_best = new RuinRandom(vrp,0.5);
|
final RuinRandom random_for_best = new RuinRandom(vrp, 0.5);
|
||||||
random_for_best.setRandom(random);
|
random_for_best.setRandom(random);
|
||||||
random_for_best.setRuinShareFactory(new RuinShareFactoryImpl(
|
random_for_best.setRuinShareFactory(new RuinShareFactoryImpl(
|
||||||
toInteger(properties.getProperty(Parameter.RANDOM_BEST_MIN_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.RANDOM_BEST_MIN_SHARE.toString())),
|
||||||
toInteger(properties.getProperty(Parameter.RANDOM_BEST_MAX_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.RANDOM_BEST_MAX_SHARE.toString())),
|
||||||
random)
|
random)
|
||||||
);
|
);
|
||||||
|
|
||||||
final RuinWorst worst = new RuinWorst(vrp, (int) (vrp.getJobs().values().size()*0.5));
|
final RuinWorst worst = new RuinWorst(vrp, (int) (vrp.getJobs().values().size() * 0.5));
|
||||||
worst.setRandom(random);
|
worst.setRandom(random);
|
||||||
worst.setRuinShareFactory(new RuinShareFactoryImpl(
|
worst.setRuinShareFactory(new RuinShareFactoryImpl(
|
||||||
toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())),
|
||||||
toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())),
|
||||||
random)
|
random)
|
||||||
);
|
);
|
||||||
IterationStartsListener noise = new IterationStartsListener() {
|
IterationStartsListener noise = new IterationStartsListener() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -353,158 +400,182 @@ public class Jsprit {
|
||||||
worst.setNoiseMaker(new NoiseMaker() {
|
worst.setNoiseMaker(new NoiseMaker() {
|
||||||
|
|
||||||
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.;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final RuinClusters clusters = new RuinClusters(vrp,(int) (vrp.getJobs().values().size()*0.5),jobNeighborhoods);
|
final RuinClusters clusters = new RuinClusters(vrp, (int) (vrp.getJobs().values().size() * 0.5), jobNeighborhoods);
|
||||||
clusters.setRandom(random);
|
clusters.setRandom(random);
|
||||||
clusters.setRuinShareFactory(new RuinShareFactoryImpl(
|
clusters.setRuinShareFactory(new RuinShareFactoryImpl(
|
||||||
toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.WORST_MIN_SHARE.toString())),
|
||||||
toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())),
|
toInteger(properties.getProperty(Parameter.WORST_MAX_SHARE.toString())),
|
||||||
random)
|
random)
|
||||||
);
|
);
|
||||||
|
|
||||||
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 (es != null) {
|
||||||
if(noThreads > 1){
|
if(fastRegret){
|
||||||
if(es == null){
|
RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||||
setupExecutorInternally = true;
|
.setInsertionStrategy(InsertionBuilder.Strategy.REGRET)
|
||||||
es = Executors.newFixedThreadPool(noThreads);
|
.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 {
|
||||||
if(es != null) {
|
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();
|
.build();
|
||||||
scorer = getRegretScorer(vrp);
|
scorer = getRegretScorer(vrp);
|
||||||
regretInsertion.setScoringFunction(scorer);
|
regretInsertion.setScoringFunction(scorer);
|
||||||
regret = regretInsertion;
|
regret = regretInsertion;
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
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();
|
||||||
|
scorer = getRegretScorer(vrp);
|
||||||
|
regretInsertion.setScoringFunction(scorer);
|
||||||
|
regret = regretInsertion;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
||||||
.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;
|
||||||
if(vrp.getJobs().size() < 250 || es == null) {
|
if (vrp.getJobs().size() < 250 || es == null) {
|
||||||
BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager)
|
BestInsertion bestInsertion = (BestInsertion) 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())))
|
||||||
.build();
|
.setActivityInsertionCostCalculator(activityInsertion)
|
||||||
|
.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)
|
||||||
.build();
|
.setActivityInsertionCostCalculator(activityInsertion)
|
||||||
|
.build();
|
||||||
best = bestInsertion;
|
best = bestInsertion;
|
||||||
}
|
}
|
||||||
best.setRandom(random);
|
best.setRandom(random);
|
||||||
|
|
||||||
final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1,toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString())));
|
final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString())));
|
||||||
IterationStartsListener schrimpfThreshold = new IterationStartsListener() {
|
IterationStartsListener schrimpfThreshold = new IterationStartsListener() {
|
||||||
@Override
|
@Override
|
||||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
if(i == 1){
|
if (i == 1) {
|
||||||
double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString()));
|
double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString()));
|
||||||
schrimpfAcceptance.setInitialThreshold(initialThreshold);
|
schrimpfAcceptance.setInitialThreshold(initialThreshold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
SearchStrategy radial_best = new SearchStrategy(Strategy.RADIAL_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
SearchStrategy radial_best = new SearchStrategy(Strategy.RADIAL_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
radial_best.addModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(),best,radial));
|
radial_best.addModule(new RuinAndRecreateModule(Strategy.RADIAL_BEST.toString(), best, radial));
|
||||||
|
|
||||||
SearchStrategy random_best = new SearchStrategy(Strategy.RANDOM_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
SearchStrategy random_best = new SearchStrategy(Strategy.RANDOM_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
random_best.addModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(),best,random_for_best));
|
random_best.addModule(new RuinAndRecreateModule(Strategy.RANDOM_BEST.toString(), best, random_for_best));
|
||||||
|
|
||||||
SearchStrategy random_regret = new SearchStrategy(Strategy.RANDOM_REGRET.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
SearchStrategy random_regret = new SearchStrategy(Strategy.RANDOM_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
random_regret.addModule(new RuinAndRecreateModule(Strategy.RANDOM_REGRET.toString(),regret,random_for_regret));
|
random_regret.addModule(new RuinAndRecreateModule(Strategy.RANDOM_REGRET.toString(), regret, random_for_regret));
|
||||||
|
|
||||||
SearchStrategy worst_regret = new SearchStrategy(Strategy.WORST_REGRET.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
SearchStrategy worst_regret = new SearchStrategy(Strategy.WORST_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
worst_regret.addModule(new RuinAndRecreateModule(Strategy.WORST_REGRET.toString(),regret,worst));
|
worst_regret.addModule(new RuinAndRecreateModule(Strategy.WORST_REGRET.toString(), regret, worst));
|
||||||
|
|
||||||
SearchStrategy worst_best = new SearchStrategy(Strategy.WORST_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
SearchStrategy worst_best = new SearchStrategy(Strategy.WORST_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
worst_best.addModule(new RuinAndRecreateModule(Strategy.WORST_BEST.toString(),best,worst));
|
worst_best.addModule(new RuinAndRecreateModule(Strategy.WORST_BEST.toString(), best, worst));
|
||||||
|
|
||||||
final SearchStrategy clusters_regret = new SearchStrategy(Strategy.CLUSTER_REGRET.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
final SearchStrategy clusters_regret = new SearchStrategy(Strategy.CLUSTER_REGRET.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
clusters_regret.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_REGRET.toString(),regret,clusters));
|
clusters_regret.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_REGRET.toString(), regret, clusters));
|
||||||
|
|
||||||
final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(),new SelectBest(),schrimpfAcceptance,objectiveFunction);
|
final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), schrimpfAcceptance, objectiveFunction);
|
||||||
clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(),best,clusters));
|
clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters));
|
||||||
|
|
||||||
|
|
||||||
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager);
|
PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager);
|
||||||
prettyBuilder.setRandom(random);
|
prettyBuilder.setRandom(random);
|
||||||
if(addCoreConstraints){
|
if (addCoreConstraints) {
|
||||||
prettyBuilder.addCoreStateAndConstraintStuff();
|
prettyBuilder.addCoreStateAndConstraintStuff();
|
||||||
}
|
}
|
||||||
prettyBuilder.withStrategy(radial_regret, toDouble(getProperty(Strategy.RADIAL_REGRET.toString())))
|
prettyBuilder.withStrategy(radial_regret, toDouble(getProperty(Strategy.RADIAL_REGRET.toString())))
|
||||||
.withStrategy(radial_best, toDouble(getProperty(Strategy.RADIAL_BEST.toString())))
|
.withStrategy(radial_best, toDouble(getProperty(Strategy.RADIAL_BEST.toString())))
|
||||||
.withStrategy(random_best, toDouble(getProperty(Strategy.RANDOM_BEST.toString())))
|
.withStrategy(random_best, toDouble(getProperty(Strategy.RANDOM_BEST.toString())))
|
||||||
.withStrategy(random_regret, toDouble(getProperty(Strategy.RANDOM_REGRET.toString())))
|
.withStrategy(random_regret, toDouble(getProperty(Strategy.RANDOM_REGRET.toString())))
|
||||||
.withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString())))
|
.withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString())))
|
||||||
.withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_REGRET.toString())))
|
.withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_REGRET.toString())))
|
||||||
.withStrategy(clusters_regret,toDouble(getProperty(Strategy.CLUSTER_REGRET.toString())))
|
.withStrategy(clusters_regret, toDouble(getProperty(Strategy.CLUSTER_REGRET.toString())))
|
||||||
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void handleExecutorShutdown(VehicleRoutingAlgorithm vra) {
|
private void handleExecutorShutdown(VehicleRoutingAlgorithm vra) {
|
||||||
if(setupExecutorInternally){
|
if (setupExecutorInternally) {
|
||||||
vra.addListener(new AlgorithmEndsListener() {
|
vra.addListener(new AlgorithmEndsListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -514,7 +585,7 @@ public class Jsprit {
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if(es != null) {
|
if (es != null) {
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!es.isShutdown()) {
|
if (!es.isShutdown()) {
|
||||||
|
|
@ -526,7 +597,7 @@ public class Jsprit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getProperty(String key){
|
String getProperty(String key) {
|
||||||
return properties.getProperty(key);
|
return properties.getProperty(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -543,20 +614,34 @@ public class Jsprit {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp, final double maxCosts) {
|
private SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp, final double maxCosts) {
|
||||||
if(objectiveFunction != null) return objectiveFunction;
|
if (objectiveFunction != null) return objectiveFunction;
|
||||||
|
|
||||||
SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() {
|
SolutionCostCalculator solutionCostCalculator = new SolutionCostCalculator() {
|
||||||
@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()) {
|
||||||
costs += vrp.getTransportCosts().getTransportCost(prevAct.getLocation(),act.getLocation(),prevAct.getEndTime(),route.getDriver(),route.getVehicle());
|
if (act instanceof BreakActivity) hasBreak = true;
|
||||||
|
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,41 +26,38 @@ 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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the {@link VehicleRoutingAlgorithm}.
|
* Creates the {@link VehicleRoutingAlgorithm}.
|
||||||
*
|
*
|
||||||
* @param vrp the underlying vehicle routing problem
|
* @param vrp the underlying vehicle routing problem
|
||||||
* @return algorithm
|
* @return algorithm
|
||||||
*/
|
*/
|
||||||
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp){
|
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp) {
|
||||||
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
|
||||||
URL resource = Resource.getAsURL("schrimpf.xml");
|
URL resource = Resource.getAsURL("schrimpf.xml");
|
||||||
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
|
||||||
return VehicleRoutingAlgorithms.createAlgorithm(vrp, algorithmConfig);
|
return VehicleRoutingAlgorithms.createAlgorithm(vrp, algorithmConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,14 @@ import org.apache.commons.configuration.XMLConfiguration;
|
||||||
|
|
||||||
public class AlgorithmConfig {
|
public class AlgorithmConfig {
|
||||||
|
|
||||||
private XMLConfiguration xmlConfig;
|
private XMLConfiguration xmlConfig;
|
||||||
|
|
||||||
public AlgorithmConfig(){
|
public AlgorithmConfig() {
|
||||||
xmlConfig = new XMLConfiguration();
|
xmlConfig = new XMLConfiguration();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public XMLConfiguration getXMLConfiguration(){
|
public XMLConfiguration getXMLConfiguration() {
|
||||||
return xmlConfig;
|
return xmlConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,64 +31,61 @@ import java.net.URL;
|
||||||
|
|
||||||
public class AlgorithmConfigXmlReader {
|
public class AlgorithmConfigXmlReader {
|
||||||
|
|
||||||
private static Logger log = LogManager.getLogger(AlgorithmConfigXmlReader.class.getName());
|
private static Logger log = LogManager.getLogger(AlgorithmConfigXmlReader.class.getName());
|
||||||
|
|
||||||
private AlgorithmConfig algorithmConfig;
|
private AlgorithmConfig algorithmConfig;
|
||||||
|
|
||||||
private boolean schemaValidation = true;
|
private boolean schemaValidation = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param schemaValidation the schemaValidation to set
|
* @param schemaValidation the schemaValidation to set
|
||||||
*/
|
*/
|
||||||
public AlgorithmConfigXmlReader setSchemaValidation(boolean schemaValidation) {
|
public AlgorithmConfigXmlReader setSchemaValidation(boolean schemaValidation) {
|
||||||
this.schemaValidation = schemaValidation;
|
this.schemaValidation = schemaValidation;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AlgorithmConfigXmlReader(AlgorithmConfig algorithmConfig){
|
public AlgorithmConfigXmlReader(AlgorithmConfig algorithmConfig) {
|
||||||
this.algorithmConfig = algorithmConfig;
|
this.algorithmConfig = algorithmConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void read(URL url){
|
public void read(URL url) {
|
||||||
log.debug("read algorithm: " + url);
|
log.debug("read algorithm: " + url);
|
||||||
algorithmConfig.getXMLConfiguration().setURL(url);
|
algorithmConfig.getXMLConfiguration().setURL(url);
|
||||||
algorithmConfig.getXMLConfiguration().setAttributeSplittingDisabled(true);
|
algorithmConfig.getXMLConfiguration().setAttributeSplittingDisabled(true);
|
||||||
algorithmConfig.getXMLConfiguration().setDelimiterParsingDisabled(true);
|
algorithmConfig.getXMLConfiguration().setDelimiterParsingDisabled(true);
|
||||||
|
|
||||||
if(schemaValidation){
|
if (schemaValidation) {
|
||||||
final InputStream resource = Resource.getAsInputStream("algorithm_schema.xsd");
|
final InputStream resource = Resource.getAsInputStream("algorithm_schema.xsd");
|
||||||
if(resource != null) {
|
if (resource != null) {
|
||||||
EntityResolver resolver = new EntityResolver() {
|
EntityResolver resolver = new EntityResolver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
|
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
|
||||||
{
|
{
|
||||||
InputSource is = new InputSource(resource);
|
InputSource is = new InputSource(resource);
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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) {
|
throw new RuntimeException(e);
|
||||||
log.error(e);
|
}
|
||||||
e.printStackTrace();
|
}
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void read(String filename){
|
public void read(String filename) {
|
||||||
log.debug("read algorithm-config from file " + filename);
|
log.debug("read algorithm-config from file " + filename);
|
||||||
URL url = Resource.getAsURL(filename);
|
URL url = Resource.getAsURL(filename);
|
||||||
read(url);
|
read(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,82 +33,85 @@ import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
class InsertionFactory {
|
class InsertionFactory {
|
||||||
|
|
||||||
private static Logger log = LogManager.getLogger(InsertionFactory.class.getName());
|
private static Logger log = LogManager.getLogger(InsertionFactory.class.getName());
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
|
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
|
||||||
VehicleFleetManager vehicleFleetManager, StateManager stateManager, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators){
|
VehicleFleetManager vehicleFleetManager, StateManager stateManager, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
|
||||||
|
|
||||||
if(config.containsKey("[@name]")){
|
if (config.containsKey("[@name]")) {
|
||||||
String insertionName = config.getString("[@name]");
|
String insertionName = config.getString("[@name]");
|
||||||
if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){
|
if (!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")) {
|
||||||
throw new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\"");
|
throw new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
InsertionBuilder iBuilder = new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager);
|
InsertionBuilder iBuilder = new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager);
|
||||||
|
|
||||||
if(executorService != null){
|
if (executorService != null) {
|
||||||
iBuilder.setConcurrentMode(executorService, nuOfThreads);
|
iBuilder.setConcurrentMode(executorService, nuOfThreads);
|
||||||
}
|
|
||||||
|
|
||||||
if(config.containsKey("level")){
|
|
||||||
String level = config.getString("level");
|
|
||||||
if(level.equals("local")){
|
|
||||||
iBuilder.setLocalLevel(addDefaultCostCalculators);
|
|
||||||
}
|
|
||||||
else if(level.equals("route")){
|
|
||||||
int forwardLooking = 0;
|
|
||||||
int memory = 1;
|
|
||||||
String forward = config.getString("level[@forwardLooking]");
|
|
||||||
String mem = config.getString("level[@memory]");
|
|
||||||
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");
|
|
||||||
if(mem != null) memory = Integer.parseInt(mem);
|
|
||||||
else log.warn("parameter route[@memory] is missing. by default it is 1");
|
|
||||||
iBuilder.setRouteLevel(forwardLooking, memory, addDefaultCostCalculators);
|
|
||||||
}
|
|
||||||
else throw new IllegalStateException("level " + level + " is not known. currently it only knows \"local\" or \"route\"");
|
|
||||||
}
|
|
||||||
else iBuilder.setLocalLevel(addDefaultCostCalculators);
|
|
||||||
|
|
||||||
if(config.containsKey("considerFixedCosts") || config.containsKey("considerFixedCost")){
|
|
||||||
if(addDefaultCostCalculators){
|
|
||||||
String val = config.getString("considerFixedCosts");
|
|
||||||
if(val == null) val = config.getString("considerFixedCost");
|
|
||||||
if(val.equals("true")){
|
|
||||||
double fixedCostWeight = 0.5;
|
|
||||||
String weight = config.getString("considerFixedCosts[@weight]");
|
|
||||||
if(weight == null) weight = config.getString("considerFixedCost[@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" +
|
|
||||||
"this has to be changed in algorithm-config-xml-file.");
|
|
||||||
iBuilder.considerFixedCosts(fixedCostWeight);
|
|
||||||
}
|
|
||||||
else if(val.equals("false")){
|
|
||||||
|
|
||||||
}
|
|
||||||
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>. " +
|
|
||||||
"if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String timeSliceString = config.getString("experimental[@timeSlice]");
|
|
||||||
String neighbors = config.getString("experimental[@neighboringSlices]");
|
|
||||||
if(timeSliceString != null && neighbors != null){
|
|
||||||
iBuilder.experimentalTimeScheduler(Double.parseDouble(timeSliceString),Integer.parseInt(neighbors));
|
|
||||||
}
|
|
||||||
String allowVehicleSwitch = config.getString("allowVehicleSwitch");
|
|
||||||
if(allowVehicleSwitch != null){
|
|
||||||
iBuilder.setAllowVehicleSwitch(Boolean.parseBoolean(allowVehicleSwitch));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(insertionName.equals("regretInsertion")){
|
|
||||||
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
|
|
||||||
}
|
}
|
||||||
return iBuilder.build();
|
|
||||||
}
|
if (config.containsKey("level")) {
|
||||||
else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
|
String level = config.getString("level");
|
||||||
}
|
if (level.equals("local")) {
|
||||||
|
iBuilder.setLocalLevel(addDefaultCostCalculators);
|
||||||
|
} else if (level.equals("route")) {
|
||||||
|
int forwardLooking = 0;
|
||||||
|
int memory = 1;
|
||||||
|
String forward = config.getString("level[@forwardLooking]");
|
||||||
|
String mem = config.getString("level[@memory]");
|
||||||
|
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");
|
||||||
|
if (mem != null) memory = Integer.parseInt(mem);
|
||||||
|
else log.warn("parameter route[@memory] is missing. by default it is 1");
|
||||||
|
iBuilder.setRouteLevel(forwardLooking, memory, addDefaultCostCalculators);
|
||||||
|
} else
|
||||||
|
throw new IllegalStateException("level " + level + " is not known. currently it only knows \"local\" or \"route\"");
|
||||||
|
} else iBuilder.setLocalLevel(addDefaultCostCalculators);
|
||||||
|
|
||||||
|
if (config.containsKey("considerFixedCosts") || config.containsKey("considerFixedCost")) {
|
||||||
|
if (addDefaultCostCalculators) {
|
||||||
|
String val = config.getString("considerFixedCosts");
|
||||||
|
if (val == null) val = config.getString("considerFixedCost");
|
||||||
|
if (val.equals("true")) {
|
||||||
|
double fixedCostWeight = 0.5;
|
||||||
|
String weight = config.getString("considerFixedCosts[@weight]");
|
||||||
|
if (weight == null) weight = config.getString("considerFixedCost[@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" +
|
||||||
|
"this has to be changed in algorithm-config-xml-file.");
|
||||||
|
iBuilder.considerFixedCosts(fixedCostWeight);
|
||||||
|
} else if (val.equals("false")) {
|
||||||
|
|
||||||
|
} 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>. " +
|
||||||
|
"if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String timeSliceString = config.getString("experimental[@timeSlice]");
|
||||||
|
String neighbors = config.getString("experimental[@neighboringSlices]");
|
||||||
|
if (timeSliceString != null && neighbors != null) {
|
||||||
|
iBuilder.experimentalTimeScheduler(Double.parseDouble(timeSliceString), Integer.parseInt(neighbors));
|
||||||
|
}
|
||||||
|
String allowVehicleSwitch = config.getString("allowVehicleSwitch");
|
||||||
|
if (allowVehicleSwitch != null) {
|
||||||
|
iBuilder.setAllowVehicleSwitch(Boolean.parseBoolean(allowVehicleSwitch));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insertionName.equals("regretInsertion")) {
|
||||||
|
iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
|
||||||
|
|
||||||
|
String fastRegret = config.getString("fastRegret");
|
||||||
|
if (fastRegret != null) {
|
||||||
|
iBuilder.setFastRegret(Boolean.parseBoolean(fastRegret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iBuilder.build();
|
||||||
|
} else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -22,10 +22,8 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public interface AlgorithmEndsListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
|
void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
public interface AlgorithmEndsListener extends VehicleRoutingAlgorithmListener{
|
|
||||||
|
|
||||||
void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,8 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public interface AlgorithmStartsListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
|
void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
public interface AlgorithmStartsListener extends VehicleRoutingAlgorithmListener{
|
|
||||||
|
|
||||||
void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,9 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public interface IterationEndsListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
|
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
|
|
||||||
public interface IterationEndsListener extends VehicleRoutingAlgorithmListener{
|
|
||||||
|
|
||||||
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,9 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public interface IterationStartsListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
|
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
||||||
public interface IterationStartsListener extends VehicleRoutingAlgorithmListener{
|
|
||||||
|
|
||||||
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package jsprit.core.algorithm.listener;
|
package jsprit.core.algorithm.listener;
|
||||||
|
|
||||||
public interface SearchStrategyListener extends VehicleRoutingAlgorithmListener{
|
public interface SearchStrategyListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,6 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package jsprit.core.algorithm.listener;
|
package jsprit.core.algorithm.listener;
|
||||||
|
|
||||||
public interface SearchStrategyModuleListener extends VehicleRoutingAlgorithmListener{
|
public interface SearchStrategyModuleListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,8 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
|
public interface StrategySelectedListener extends VehicleRoutingAlgorithmListener {
|
||||||
|
|
||||||
|
void informSelectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem vehicleRoutingProblem, Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions);
|
||||||
public interface StrategySelectedListener extends VehicleRoutingAlgorithmListener{
|
|
||||||
|
|
||||||
void informSelectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem vehicleRoutingProblem, Collection<VehicleRoutingProblemSolution> vehicleRoutingProblemSolutions);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,159 +24,126 @@ 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) {
|
|
||||||
super();
|
|
||||||
this.priority = priority;
|
|
||||||
this.l = l;
|
|
||||||
}
|
|
||||||
public Priority getPriority() {
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
public VehicleRoutingAlgorithmListener getListener() {
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
public PrioritizedVRAListener(Priority priority, VehicleRoutingAlgorithmListener l) {
|
||||||
// public int hashCode() {
|
super();
|
||||||
// final int prime = 31;
|
this.priority = priority;
|
||||||
// int result = 1;
|
this.l = l;
|
||||||
// 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 Priority getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
public enum Priority {
|
public VehicleRoutingAlgorithmListener getListener() {
|
||||||
HIGH, MEDIUM, LOW
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Priority {
|
||||||
|
HIGH, MEDIUM, LOW
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private TreeSet<PrioritizedVRAListener> algorithmListeners = new TreeSet<PrioritizedVRAListener>(new Comparator<PrioritizedVRAListener>() {
|
private TreeSet<PrioritizedVRAListener> algorithmListeners = new TreeSet<PrioritizedVRAListener>(new Comparator<PrioritizedVRAListener>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(PrioritizedVRAListener o1, PrioritizedVRAListener o2) {
|
public int compare(PrioritizedVRAListener o1, PrioritizedVRAListener o2) {
|
||||||
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) {
|
||||||
}
|
return -1;
|
||||||
else if(o1.getPriority() == Priority.MEDIUM && o2.getPriority() != Priority.MEDIUM){
|
} else if (o2.getPriority() == Priority.MEDIUM && o1.getPriority() != Priority.MEDIUM) {
|
||||||
return -1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if(o2.getPriority() == Priority.MEDIUM && o1.getPriority() != Priority.MEDIUM){
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
});
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
public Collection<VehicleRoutingAlgorithmListener> getAlgorithmListeners() {
|
public Collection<VehicleRoutingAlgorithmListener> getAlgorithmListeners() {
|
||||||
List<VehicleRoutingAlgorithmListener> list = new ArrayList<VehicleRoutingAlgorithmListener>();
|
List<VehicleRoutingAlgorithmListener> list = new ArrayList<VehicleRoutingAlgorithmListener>();
|
||||||
for(PrioritizedVRAListener l : algorithmListeners){
|
for (PrioritizedVRAListener l : algorithmListeners) {
|
||||||
list.add(l.getListener());
|
list.add(l.getListener());
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableCollection(list);
|
return Collections.unmodifiableCollection(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
algorithmListeners.add(new PrioritizedVRAListener(priority, listener));
|
algorithmListeners.add(new PrioritizedVRAListener(priority, listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(VehicleRoutingAlgorithmListener listener){
|
public void addListener(VehicleRoutingAlgorithmListener listener) {
|
||||||
addListener(listener, Priority.LOW);
|
addListener(listener, Priority.LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
for(PrioritizedVRAListener l : algorithmListeners){
|
for (PrioritizedVRAListener l : algorithmListeners) {
|
||||||
if(l.getListener() instanceof AlgorithmEndsListener){
|
if (l.getListener() instanceof AlgorithmEndsListener) {
|
||||||
((AlgorithmEndsListener)l.getListener()).informAlgorithmEnds(problem, solutions);
|
((AlgorithmEndsListener) l.getListener()).informAlgorithmEnds(problem, solutions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
for(PrioritizedVRAListener l : algorithmListeners){
|
for (PrioritizedVRAListener l : algorithmListeners) {
|
||||||
if(l.getListener() instanceof IterationEndsListener){
|
if (l.getListener() instanceof IterationEndsListener) {
|
||||||
((IterationEndsListener)l.getListener()).informIterationEnds(i,problem, solutions);
|
((IterationEndsListener) l.getListener()).informIterationEnds(i, problem, solutions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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){
|
((IterationStartsListener) l.getListener()).informIterationStarts(i, problem, solutions);
|
||||||
((IterationStartsListener)l.getListener()).informIterationStarts(i,problem, solutions);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
public void algorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
|
for (PrioritizedVRAListener l : algorithmListeners) {
|
||||||
|
if (l.getListener() instanceof AlgorithmStartsListener) {
|
||||||
|
((AlgorithmStartsListener) l.getListener()).informAlgorithmStarts(problem, algorithm, solutions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void algorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void add(PrioritizedVRAListener l) {
|
||||||
for(PrioritizedVRAListener l : algorithmListeners){
|
algorithmListeners.add(l);
|
||||||
if(l.getListener() instanceof AlgorithmStartsListener){
|
}
|
||||||
((AlgorithmStartsListener)l.getListener()).informAlgorithmStarts(problem, algorithm, solutions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(PrioritizedVRAListener l){
|
public void addAll(Collection<PrioritizedVRAListener> algorithmListeners) {
|
||||||
algorithmListeners.add(l);
|
for (PrioritizedVRAListener l : algorithmListeners) {
|
||||||
}
|
this.algorithmListeners.add(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void addAll(Collection<PrioritizedVRAListener> algorithmListeners) {
|
public void selectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
for(PrioritizedVRAListener l : algorithmListeners){
|
for (PrioritizedVRAListener l : algorithmListeners) {
|
||||||
this.algorithmListeners.add(l);
|
if (l.getListener() instanceof StrategySelectedListener) {
|
||||||
}
|
((StrategySelectedListener) l.getListener()).informSelectedStrategy(discoveredSolution, problem, solutions);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public void selectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
}
|
||||||
for(PrioritizedVRAListener l : algorithmListeners){
|
|
||||||
if(l.getListener() instanceof StrategySelectedListener){
|
|
||||||
((StrategySelectedListener)l.getListener()).informSelectedStrategy(discoveredSolution, problem, solutions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,61 +30,61 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
public class RuinAndRecreateModule implements SearchStrategyModule{
|
public class RuinAndRecreateModule implements SearchStrategyModule {
|
||||||
|
|
||||||
private InsertionStrategy insertion;
|
private InsertionStrategy insertion;
|
||||||
|
|
||||||
private RuinStrategy ruin;
|
private RuinStrategy ruin;
|
||||||
|
|
||||||
private String moduleName;
|
private String moduleName;
|
||||||
|
|
||||||
public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) {
|
public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) {
|
||||||
super();
|
super();
|
||||||
this.insertion = insertion;
|
this.insertion = insertion;
|
||||||
this.ruin = ruin;
|
this.ruin = ruin;
|
||||||
this.moduleName = moduleName;
|
this.moduleName = moduleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
|
||||||
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
|
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes());
|
||||||
Set<Job> ruinedJobSet = new HashSet<Job>();
|
Set<Job> ruinedJobSet = new HashSet<Job>();
|
||||||
ruinedJobSet.addAll(ruinedJobs);
|
ruinedJobSet.addAll(ruinedJobs);
|
||||||
ruinedJobSet.addAll(vrpSolution.getUnassignedJobs());
|
ruinedJobSet.addAll(vrpSolution.getUnassignedJobs());
|
||||||
Collection<Job> unassignedJobs = insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobSet);
|
Collection<Job> unassignedJobs = insertion.insertJobs(vrpSolution.getRoutes(), ruinedJobSet);
|
||||||
vrpSolution.getUnassignedJobs().clear();
|
vrpSolution.getUnassignedJobs().clear();
|
||||||
vrpSolution.getUnassignedJobs().addAll(unassignedJobs);
|
vrpSolution.getUnassignedJobs().addAll(unassignedJobs);
|
||||||
return vrpSolution;
|
return vrpSolution;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return moduleName;
|
return moduleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
public void addModuleListener(SearchStrategyModuleListener moduleListener) {
|
||||||
if(moduleListener instanceof InsertionListener){
|
if (moduleListener instanceof InsertionListener) {
|
||||||
InsertionListener iListener = (InsertionListener) moduleListener;
|
InsertionListener iListener = (InsertionListener) moduleListener;
|
||||||
if(!insertion.getListeners().contains(iListener)){
|
if (!insertion.getListeners().contains(iListener)) {
|
||||||
insertion.addListener(iListener);
|
insertion.addListener(iListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(moduleListener instanceof RuinListener){
|
if (moduleListener instanceof RuinListener) {
|
||||||
RuinListener rListener = (RuinListener) moduleListener;
|
RuinListener rListener = (RuinListener) moduleListener;
|
||||||
if(!ruin.getListeners().contains(rListener)){
|
if (!ruin.getListeners().contains(rListener)) {
|
||||||
ruin.addListener(rListener);
|
ruin.addListener(rListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionStrategy getInsertion() {
|
public InsertionStrategy getInsertion() {
|
||||||
return insertion;
|
return insertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RuinStrategy getRuin() {
|
public RuinStrategy getRuin() {
|
||||||
return ruin;
|
return ruin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public abstract class AbstractInsertionStrategy implements InsertionStrategy{
|
public abstract class AbstractInsertionStrategy implements InsertionStrategy {
|
||||||
|
|
||||||
protected class Insertion {
|
protected class Insertion {
|
||||||
|
|
||||||
|
|
@ -84,9 +84,9 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy{
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Job> insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs){
|
public Collection<Job> insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
insertionsListeners.informInsertionStarts(vehicleRoutes, unassignedJobs);
|
insertionsListeners.informInsertionStarts(vehicleRoutes, unassignedJobs);
|
||||||
Collection<Job> badJobs = insertUnassignedJobs(vehicleRoutes,unassignedJobs);
|
Collection<Job> badJobs = insertUnassignedJobs(vehicleRoutes, unassignedJobs);
|
||||||
insertionsListeners.informInsertionEndsListeners(vehicleRoutes);
|
insertionsListeners.informInsertionEndsListeners(vehicleRoutes);
|
||||||
return badJobs;
|
return badJobs;
|
||||||
}
|
}
|
||||||
|
|
@ -109,13 +109,13 @@ 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());
|
||||||
}
|
}
|
||||||
for(Event e : iData.getEvents()){
|
for (Event e : iData.getEvents()) {
|
||||||
eventListeners.inform(e);
|
eventListeners.inform(e);
|
||||||
}
|
}
|
||||||
insertionsListeners.informJobInserted(unassignedJob, inRoute, iData.getInsertionCost(), iData.getAdditionalTime());
|
insertionsListeners.informJobInserted(unassignedJob, inRoute, iData.getInsertionCost(), iData.getAdditionalTime());
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2014 Stefan Schroeder
|
* Copyright (C) 2014 Stefan Schroeder
|
||||||
*
|
*
|
||||||
|
|
@ -23,32 +22,34 @@ import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
|
|
||||||
public interface ActivityInsertionCostsCalculator {
|
public interface ActivityInsertionCostsCalculator {
|
||||||
|
|
||||||
public class ActivityInsertionCosts {
|
public class ActivityInsertionCosts {
|
||||||
|
|
||||||
private double additionalCosts;
|
private double additionalCosts;
|
||||||
private double additionalTime;
|
private double additionalTime;
|
||||||
public ActivityInsertionCosts(double additionalCosts, double additionalTime) {
|
|
||||||
super();
|
public ActivityInsertionCosts(double additionalCosts, double additionalTime) {
|
||||||
this.additionalCosts = additionalCosts;
|
super();
|
||||||
this.additionalTime = additionalTime;
|
this.additionalCosts = additionalCosts;
|
||||||
}
|
this.additionalTime = additionalTime;
|
||||||
/**
|
}
|
||||||
* @return the additionalCosts
|
|
||||||
*/
|
/**
|
||||||
public double getAdditionalCosts() {
|
* @return the additionalCosts
|
||||||
return additionalCosts;
|
*/
|
||||||
}
|
public double getAdditionalCosts() {
|
||||||
/**
|
return additionalCosts;
|
||||||
* @return the additionalTime
|
}
|
||||||
*/
|
|
||||||
public double getAdditionalTime() {
|
/**
|
||||||
return additionalTime;
|
* @return the additionalTime
|
||||||
}
|
*/
|
||||||
|
public double getAdditionalTime() {
|
||||||
|
return additionalTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
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,52 +25,50 @@ 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 {
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public double getCosts(JobInsertionContext insertionContext){
|
public double getCosts(JobInsertionContext insertionContext) {
|
||||||
double delta_access = 0.0;
|
double delta_access = 0.0;
|
||||||
double delta_egress = 0.0;
|
double delta_egress = 0.0;
|
||||||
VehicleRoute currentRoute = insertionContext.getRoute();
|
VehicleRoute currentRoute = insertionContext.getRoute();
|
||||||
Vehicle newVehicle = insertionContext.getNewVehicle();
|
Vehicle newVehicle = insertionContext.getNewVehicle();
|
||||||
Driver newDriver = insertionContext.getNewDriver();
|
Driver newDriver = insertionContext.getNewDriver();
|
||||||
double newVehicleDepartureTime = insertionContext.getNewDepTime();
|
double newVehicleDepartureTime = insertionContext.getNewDepTime();
|
||||||
if(!currentRoute.isEmpty()){
|
if (!currentRoute.isEmpty()) {
|
||||||
double accessTransportCostNew = routingCosts.getTransportCost(newVehicle.getStartLocation(), currentRoute.getActivities().get(0).getLocation(), newVehicleDepartureTime, newDriver, newVehicle);
|
double accessTransportCostNew = routingCosts.getTransportCost(newVehicle.getStartLocation(), currentRoute.getActivities().get(0).getLocation(), newVehicleDepartureTime, newDriver, newVehicle);
|
||||||
double accessTransportCostOld = routingCosts.getTransportCost(currentRoute.getStart().getLocation(), currentRoute.getActivities().get(0).getLocation(), currentRoute.getDepartureTime(), currentRoute.getDriver(), currentRoute.getVehicle());
|
double accessTransportCostOld = routingCosts.getTransportCost(currentRoute.getStart().getLocation(), currentRoute.getActivities().get(0).getLocation(), currentRoute.getDepartureTime(), currentRoute.getDriver(), currentRoute.getVehicle());
|
||||||
|
|
||||||
delta_access = accessTransportCostNew - accessTransportCostOld;
|
delta_access = accessTransportCostNew - accessTransportCostOld;
|
||||||
|
|
||||||
if(newVehicle.isReturnToDepot()){
|
if (newVehicle.isReturnToDepot()) {
|
||||||
TourActivity lastActivityBeforeEndOfRoute = currentRoute.getActivities().get(currentRoute.getActivities().size()-1);
|
TourActivity lastActivityBeforeEndOfRoute = currentRoute.getActivities().get(currentRoute.getActivities().size() - 1);
|
||||||
double lastActivityEndTimeWithOldVehicleAndDepartureTime = lastActivityBeforeEndOfRoute.getEndTime();
|
double lastActivityEndTimeWithOldVehicleAndDepartureTime = lastActivityBeforeEndOfRoute.getEndTime();
|
||||||
double lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime = Math.max(0.0, lastActivityEndTimeWithOldVehicleAndDepartureTime + (newVehicleDepartureTime - currentRoute.getDepartureTime()));
|
double lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime = Math.max(0.0, lastActivityEndTimeWithOldVehicleAndDepartureTime + (newVehicleDepartureTime - currentRoute.getDepartureTime()));
|
||||||
double egressTransportCostNew = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocation(), newVehicle.getEndLocation() , lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime, newDriver, newVehicle);
|
double egressTransportCostNew = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocation(), newVehicle.getEndLocation(), lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime, newDriver, newVehicle);
|
||||||
double egressTransportCostOld = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocation(), currentRoute.getEnd().getLocation(), lastActivityEndTimeWithOldVehicleAndDepartureTime, currentRoute.getDriver(), currentRoute.getVehicle());
|
double egressTransportCostOld = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocation(), currentRoute.getEnd().getLocation(), lastActivityEndTimeWithOldVehicleAndDepartureTime, currentRoute.getDriver(), currentRoute.getVehicle());
|
||||||
|
|
||||||
delta_egress = egressTransportCostNew - egressTransportCostOld;
|
delta_egress = egressTransportCostNew - egressTransportCostOld;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return delta_access + delta_egress;
|
return delta_access + delta_egress;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,54 +27,52 @@ 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;
|
||||||
|
|
||||||
private final VehicleRoutingActivityCosts activityCosts;
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts actCosts) {
|
public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts actCosts) {
|
||||||
super();
|
super();
|
||||||
this.routingCosts = routingCosts;
|
this.routingCosts = routingCosts;
|
||||||
this.activityCosts = actCosts;
|
this.activityCosts = actCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @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
|
||||||
* @param vehicle vehicle running the path
|
* @param vehicle vehicle running the path
|
||||||
* @return cost of path
|
* @return cost of path
|
||||||
*/
|
*/
|
||||||
public double costOfPath(final List<TourActivity> path, final double depTime, final Driver driver, final Vehicle vehicle){
|
public double costOfPath(final List<TourActivity> path, final double depTime, final Driver driver, final Vehicle vehicle) {
|
||||||
if(path.isEmpty()){
|
if (path.isEmpty()) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
double cost = 0.0;
|
double cost = 0.0;
|
||||||
Iterator<TourActivity> actIter = path.iterator();
|
Iterator<TourActivity> actIter = path.iterator();
|
||||||
TourActivity prevAct = actIter.next();
|
TourActivity prevAct = actIter.next();
|
||||||
double startCost = 0.0;
|
double startCost = 0.0;
|
||||||
cost += startCost;
|
cost += startCost;
|
||||||
double departureTimePrevAct = depTime;
|
double departureTimePrevAct = depTime;
|
||||||
while(actIter.hasNext()){
|
while (actIter.hasNext()) {
|
||||||
TourActivity act = actIter.next();
|
TourActivity act = actIter.next();
|
||||||
if(act instanceof End){
|
if (act instanceof End) {
|
||||||
if(!vehicle.isReturnToDepot()){
|
if (!vehicle.isReturnToDepot()) {
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double transportCost = routingCosts.getTransportCost(prevAct.getLocation(), act.getLocation(), departureTimePrevAct, driver, vehicle);
|
double transportCost = routingCosts.getTransportCost(prevAct.getLocation(), act.getLocation(), departureTimePrevAct, driver, vehicle);
|
||||||
double transportTime = routingCosts.getTransportTime(prevAct.getLocation(), act.getLocation(), departureTimePrevAct, driver, vehicle);
|
double transportTime = routingCosts.getTransportTime(prevAct.getLocation(), act.getLocation(), departureTimePrevAct, driver, vehicle);
|
||||||
cost += transportCost;
|
cost += transportCost;
|
||||||
double actStartTime = departureTimePrevAct + transportTime;
|
double actStartTime = departureTimePrevAct + transportTime;
|
||||||
departureTimePrevAct = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime();
|
departureTimePrevAct = Math.max(actStartTime, act.getTheoreticalEarliestOperationStartTime()) + act.getOperationTime();
|
||||||
cost += activityCosts.getActivityCost(act, actStartTime, driver, vehicle);
|
cost += activityCosts.getActivityCost(act, actStartTime, driver, vehicle);
|
||||||
prevAct = act;
|
prevAct = act;
|
||||||
}
|
}
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,70 +30,67 @@ 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 {
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(BestInsertion.class);
|
private static Logger logger = LogManager.getLogger(BestInsertion.class);
|
||||||
|
|
||||||
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
||||||
|
|
||||||
private NoiseMaker noiseMaker = new NoiseMaker() {
|
private NoiseMaker noiseMaker = new NoiseMaker() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double makeNoise() {
|
public double makeNoise() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=bestInsertion]";
|
return "[name=bestInsertion]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
|
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
|
||||||
Collections.shuffle(unassignedJobList, random);
|
Collections.shuffle(unassignedJobList, random);
|
||||||
for(Job unassignedJob : unassignedJobList){
|
for (Job unassignedJob : unassignedJobList) {
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
for(VehicleRoute vehicleRoute : vehicleRoutes){
|
for (VehicleRoute vehicleRoute : vehicleRoutes) {
|
||||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||||
if(iData instanceof NoInsertionFound) {
|
if (iData instanceof NoInsertionFound) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()){
|
if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
||||||
bestInsertion = new Insertion(vehicleRoute,iData);
|
bestInsertion = new Insertion(vehicleRoute, iData);
|
||||||
bestInsertionCost = iData.getInsertionCost();
|
bestInsertionCost = iData.getInsertionCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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);
|
||||||
if(!(newIData instanceof NoInsertionFound)){
|
if (!(newIData instanceof NoInsertionFound)) {
|
||||||
if(newIData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()){
|
if (newIData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) {
|
||||||
bestInsertion = new Insertion(newRoute,newIData);
|
bestInsertion = new Insertion(newRoute, newIData);
|
||||||
vehicleRoutes.add(newRoute);
|
vehicleRoutes.add(newRoute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(bestInsertion == null) badJobs.add(unassignedJob);
|
if (bestInsertion == null) badJobs.add(unassignedJob);
|
||||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
}
|
}
|
||||||
return badJobs;
|
return badJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,150 +30,154 @@ import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
public class BestInsertionBuilder {
|
public class BestInsertionBuilder {
|
||||||
|
|
||||||
private VehicleRoutingProblem vrp;
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateManager stateManager;
|
||||||
|
|
||||||
private boolean local = true;
|
private boolean local = true;
|
||||||
|
|
||||||
private ConstraintManager constraintManager;
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
private double weightOfFixedCosts;
|
private double weightOfFixedCosts;
|
||||||
|
|
||||||
private boolean considerFixedCosts = false;
|
private boolean considerFixedCosts = false;
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
|
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
|
||||||
|
|
||||||
private int forwaredLooking;
|
private int forwaredLooking;
|
||||||
|
|
||||||
private int memory;
|
private int memory;
|
||||||
|
|
||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
|
|
||||||
private int nuOfThreads;
|
private int nuOfThreads;
|
||||||
|
|
||||||
private double timeSlice;
|
private double timeSlice;
|
||||||
|
|
||||||
private int nNeighbors;
|
private int nNeighbors;
|
||||||
|
|
||||||
private boolean timeScheduling=false;
|
private boolean timeScheduling = false;
|
||||||
|
|
||||||
private boolean allowVehicleSwitch=true;
|
private boolean allowVehicleSwitch = true;
|
||||||
|
|
||||||
private boolean addDefaultCostCalc=true;
|
private boolean addDefaultCostCalc = true;
|
||||||
|
|
||||||
public BestInsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
public BestInsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
this.constraintManager = constraintManager;
|
this.constraintManager = constraintManager;
|
||||||
this.fleetManager = vehicleFleetManager;
|
this.fleetManager = vehicleFleetManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory){
|
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory) {
|
||||||
local = false;
|
local = false;
|
||||||
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){
|
;
|
||||||
local = false;
|
|
||||||
this.forwaredLooking = forwardLooking;
|
|
||||||
this.memory = memory;
|
|
||||||
this.addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
public BestInsertionBuilder setLocalLevel(){
|
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation) {
|
||||||
local = true;
|
local = false;
|
||||||
return this;
|
this.forwaredLooking = forwardLooking;
|
||||||
};
|
this.memory = memory;
|
||||||
|
this.addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
;
|
||||||
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
|
|
||||||
* is controlled by your custom soft constraints.
|
|
||||||
*
|
|
||||||
* @param addDefaultMarginalCostCalculation
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public BestInsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation){
|
|
||||||
local = true;
|
|
||||||
addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BestInsertionBuilder considerFixedCosts(double weightOfFixedCosts){
|
public BestInsertionBuilder setLocalLevel() {
|
||||||
this.weightOfFixedCosts = weightOfFixedCosts;
|
local = true;
|
||||||
this.considerFixedCosts = true;
|
return this;
|
||||||
return this;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public BestInsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){
|
;
|
||||||
this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
public BestInsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads){
|
/**
|
||||||
this.executor = executor;
|
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
|
||||||
this.nuOfThreads = nuOfThreads;
|
* is controlled by your custom soft constraints.
|
||||||
return this;
|
*
|
||||||
}
|
* @param addDefaultMarginalCostCalculation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public BestInsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation) {
|
||||||
|
local = true;
|
||||||
|
addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BestInsertionBuilder considerFixedCosts(double weightOfFixedCosts) {
|
||||||
|
this.weightOfFixedCosts = weightOfFixedCosts;
|
||||||
|
this.considerFixedCosts = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BestInsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
|
||||||
|
this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
public BestInsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) {
|
||||||
|
this.executor = executor;
|
||||||
|
this.nuOfThreads = nuOfThreads;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public InsertionStrategy build() {
|
public InsertionStrategy build() {
|
||||||
List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
|
List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
|
||||||
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
|
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
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.setStateManager(stateManager);
|
|
||||||
calcBuilder.setVehicleRoutingProblem(vrp);
|
|
||||||
calcBuilder.setVehicleFleetManager(fleetManager);
|
|
||||||
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
|
|
||||||
if(considerFixedCosts) {
|
|
||||||
calcBuilder.considerFixedCosts(weightOfFixedCosts);
|
|
||||||
}
|
|
||||||
if(timeScheduling){
|
|
||||||
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors);
|
|
||||||
}
|
|
||||||
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch);
|
|
||||||
JobInsertionCostsCalculator jobInsertions = calcBuilder.build();
|
|
||||||
InsertionStrategy bestInsertion;
|
|
||||||
if(executor == null){
|
|
||||||
bestInsertion = new BestInsertion(jobInsertions,vrp);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
bestInsertion = new BestInsertionConcurrent(jobInsertions,executor,nuOfThreads,vrp);
|
|
||||||
}
|
}
|
||||||
for(InsertionListener l : iListeners) bestInsertion.addListener(l);
|
calcBuilder.setConstraintManager(constraintManager);
|
||||||
return bestInsertion;
|
calcBuilder.setStateManager(stateManager);
|
||||||
}
|
calcBuilder.setVehicleRoutingProblem(vrp);
|
||||||
|
calcBuilder.setVehicleFleetManager(fleetManager);
|
||||||
/**
|
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
|
||||||
* @deprecated this is experimental and can disappear.
|
if (considerFixedCosts) {
|
||||||
* @param timeSlice the time slice
|
calcBuilder.considerFixedCosts(weightOfFixedCosts);
|
||||||
* @param nNeighbors number of neighbors
|
}
|
||||||
*/
|
if (timeScheduling) {
|
||||||
@Deprecated
|
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors);
|
||||||
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
|
}
|
||||||
this.timeSlice=timeSlice;
|
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch);
|
||||||
this.nNeighbors=nNeighbors;
|
JobInsertionCostsCalculator jobInsertions = calcBuilder.build();
|
||||||
timeScheduling=true;
|
InsertionStrategy bestInsertion;
|
||||||
}
|
if (executor == null) {
|
||||||
|
bestInsertion = new BestInsertion(jobInsertions, vrp);
|
||||||
public void setAllowVehicleSwitch(boolean allowVehicleSwitch) {
|
} else {
|
||||||
this.allowVehicleSwitch = allowVehicleSwitch;
|
bestInsertion = new BestInsertionConcurrent(jobInsertions, executor, nuOfThreads, vrp);
|
||||||
}
|
}
|
||||||
|
for (InsertionListener l : iListeners) bestInsertion.addListener(l);
|
||||||
|
return bestInsertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param timeSlice the time slice
|
||||||
|
* @param nNeighbors number of neighbors
|
||||||
|
* @deprecated this is experimental and can disappear.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
|
||||||
|
this.timeSlice = timeSlice;
|
||||||
|
this.nNeighbors = nNeighbors;
|
||||||
|
timeScheduling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowVehicleSwitch(boolean allowVehicleSwitch) {
|
||||||
|
this.allowVehicleSwitch = allowVehicleSwitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,171 +30,163 @@ 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 {
|
||||||
|
|
||||||
static class Batch {
|
static class Batch {
|
||||||
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Insertion {
|
class Insertion {
|
||||||
|
|
||||||
private final VehicleRoute route;
|
private final VehicleRoute route;
|
||||||
|
|
||||||
private final InsertionData insertionData;
|
private final InsertionData insertionData;
|
||||||
|
|
||||||
public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) {
|
public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) {
|
||||||
super();
|
super();
|
||||||
this.route = vehicleRoute;
|
this.route = vehicleRoute;
|
||||||
this.insertionData = insertionData;
|
this.insertionData = insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VehicleRoute getRoute() {
|
public VehicleRoute getRoute() {
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionData getInsertionData() {
|
public InsertionData getInsertionData() {
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Logger logger = LogManager.getLogger(BestInsertionConcurrent.class);
|
private static Logger logger = LogManager.getLogger(BestInsertionConcurrent.class);
|
||||||
|
|
||||||
private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345;
|
private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345;
|
||||||
|
|
||||||
private final static Vehicle NO_NEW_VEHICLE_YET = null;
|
private final static Vehicle NO_NEW_VEHICLE_YET = null;
|
||||||
|
|
||||||
private final static Driver NO_NEW_DRIVER_YET = null;
|
private final static Driver NO_NEW_DRIVER_YET = null;
|
||||||
|
|
||||||
private InsertionListeners insertionsListeners;
|
private InsertionListeners insertionsListeners;
|
||||||
|
|
||||||
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
private JobInsertionCostsCalculator bestInsertionCostCalculator;
|
||||||
|
|
||||||
private int nuOfBatches;
|
private int nuOfBatches;
|
||||||
|
|
||||||
private ExecutorCompletionService<Insertion> completionService;
|
private ExecutorCompletionService<Insertion> completionService;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void setRandom(Random random) {
|
public void setRandom(Random random) {
|
||||||
super.random = random;
|
super.random = random;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BestInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, ExecutorService executorService, int nuOfBatches, VehicleRoutingProblem vehicleRoutingProblem) {
|
public BestInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, ExecutorService executorService, int nuOfBatches, VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
super(vehicleRoutingProblem);
|
super(vehicleRoutingProblem);
|
||||||
this.insertionsListeners = new InsertionListeners();
|
this.insertionsListeners = new InsertionListeners();
|
||||||
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
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=bestInsertion]";
|
return "[name=bestInsertion]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
|
||||||
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
|
||||||
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
|
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
|
||||||
Collections.shuffle(unassignedJobList, random);
|
Collections.shuffle(unassignedJobList, random);
|
||||||
List<Batch> batches = distributeRoutes(vehicleRoutes,nuOfBatches);
|
List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
|
||||||
for(final Job unassignedJob : unassignedJobList){
|
for (final Job unassignedJob : unassignedJobList) {
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
for(final Batch batch : batches){
|
for (final Batch batch : batches) {
|
||||||
completionService.submit(new Callable<Insertion>() {
|
completionService.submit(new Callable<Insertion>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Insertion call() throws Exception {
|
public Insertion call() throws Exception {
|
||||||
return getBestInsertion(batch,unassignedJob);
|
return getBestInsertion(batch, unassignedJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < batches.size(); i++) {
|
for (int i = 0; i < batches.size(); i++) {
|
||||||
Future<Insertion> futureIData = completionService.take();
|
Future<Insertion> futureIData = completionService.take();
|
||||||
Insertion insertion = futureIData.get();
|
Insertion insertion = futureIData.get();
|
||||||
if (insertion == null) continue;
|
if (insertion == null) continue;
|
||||||
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
|
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
|
||||||
bestInsertion = insertion;
|
bestInsertion = insertion;
|
||||||
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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());
|
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
||||||
System.exit(1);
|
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||||
}
|
if (newIData.getInsertionCost() < bestInsertionCost) {
|
||||||
VehicleRoute newRoute = VehicleRoute.emptyRoute();
|
bestInsertion = new Insertion(newRoute, newIData);
|
||||||
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
vehicleRoutes.add(newRoute);
|
||||||
if(newIData.getInsertionCost() < bestInsertionCost){
|
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
|
||||||
bestInsertion = new Insertion(newRoute,newIData);
|
}
|
||||||
vehicleRoutes.add(newRoute);
|
if (bestInsertion == null) badJobs.add(unassignedJob);
|
||||||
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
|
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
||||||
}
|
}
|
||||||
if(bestInsertion == null) badJobs.add(unassignedJob);
|
return badJobs;
|
||||||
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
|
}
|
||||||
}
|
|
||||||
return badJobs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
|
||||||
Insertion bestInsertion = null;
|
Insertion bestInsertion = null;
|
||||||
double bestInsertionCost = Double.MAX_VALUE;
|
double bestInsertionCost = Double.MAX_VALUE;
|
||||||
for(VehicleRoute vehicleRoute : batch.routes){
|
for (VehicleRoute vehicleRoute : batch.routes) {
|
||||||
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
|
||||||
if(iData instanceof NoInsertionFound) {
|
if (iData instanceof NoInsertionFound) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(iData.getInsertionCost() < bestInsertionCost){
|
if (iData.getInsertionCost() < bestInsertionCost) {
|
||||||
bestInsertion = new Insertion(vehicleRoute,iData);
|
bestInsertion = new Insertion(vehicleRoute, iData);
|
||||||
bestInsertionCost = iData.getInsertionCost();
|
bestInsertionCost = iData.getInsertionCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bestInsertion;
|
return bestInsertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) {
|
private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) {
|
||||||
List<Batch> batches = new ArrayList<Batch>();
|
List<Batch> batches = new ArrayList<Batch>();
|
||||||
for(int i=0;i<nuOfBatches;i++) batches.add(new Batch());
|
for (int i = 0; i < nuOfBatches; i++) batches.add(new Batch());
|
||||||
/*
|
/*
|
||||||
* if route.size < nuOfBatches add as much routes as empty batches are available
|
* if route.size < nuOfBatches add as much routes as empty batches are available
|
||||||
* else add one empty route anyway
|
* else add one empty route anyway
|
||||||
*/
|
*/
|
||||||
if(vehicleRoutes.size()<nuOfBatches){
|
if (vehicleRoutes.size() < nuOfBatches) {
|
||||||
int nOfNewRoutes = nuOfBatches-vehicleRoutes.size();
|
int nOfNewRoutes = nuOfBatches - vehicleRoutes.size();
|
||||||
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());
|
}
|
||||||
}
|
/*
|
||||||
/*
|
* distribute routes to batches equally
|
||||||
* distribute routes to batches equally
|
|
||||||
*/
|
*/
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
for (VehicleRoute route : vehicleRoutes) {
|
||||||
if(count == nuOfBatches) count=0;
|
if (count == nuOfBatches) count = 0;
|
||||||
batches.get(count).routes.add(route);
|
batches.get(count).routes.add(route);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return batches;
|
return batches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -15,22 +15,24 @@ import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
|
||||||
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator{
|
class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
|
|
||||||
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>();
|
||||||
if(vehicleRoutes.isEmpty()){
|
if (vehicleRoutes.isEmpty()) {
|
||||||
// System.out.println("hmm");
|
// System.out.println("hmm");
|
||||||
}
|
}
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
for (VehicleRoute route : vehicleRoutes) {
|
||||||
// if(route.getDepartureTime() == 21600.){
|
// if(route.getDepartureTime() == 21600.){
|
||||||
// System.out.println("hu");
|
// System.out.println("hu");
|
||||||
// }
|
// }
|
||||||
|
|
@ -60,18 +62,17 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsC
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name="+this.getClass().toString()+"]";
|
return "[name=" + this.getClass().toString() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
||||||
double departureTime = newVehicleDepartureTime;
|
double departureTime = newVehicleDepartureTime;
|
||||||
if(currentRoute.isEmpty()){
|
if (currentRoute.isEmpty()) {
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +83,7 @@ class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsC
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDepartureTimeKnowledge(List<Double> departureTimes){
|
public void setDepartureTimeKnowledge(List<Double> departureTimes) {
|
||||||
departureTimeKnowledge=departureTimes;
|
departureTimeKnowledge = departureTimes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,65 +27,64 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
class CalculatesServiceInsertionWithTimeSchedulingInSlices implements JobInsertionCostsCalculator{
|
class CalculatesServiceInsertionWithTimeSchedulingInSlices implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
|
|
||||||
private static Logger log = LogManager.getLogger(CalculatesServiceInsertionWithTimeSchedulingInSlices.class);
|
private static Logger log = LogManager.getLogger(CalculatesServiceInsertionWithTimeSchedulingInSlices.class);
|
||||||
|
|
||||||
private JobInsertionCostsCalculator jic;
|
private JobInsertionCostsCalculator jic;
|
||||||
|
|
||||||
private int nOfDepartureTimes = 3;
|
private int nOfDepartureTimes = 3;
|
||||||
|
|
||||||
private double timeSlice = 900.0;
|
private double timeSlice = 900.0;
|
||||||
|
|
||||||
public CalculatesServiceInsertionWithTimeSchedulingInSlices(JobInsertionCostsCalculator jic, double timeSlice, int neighbors) {
|
public CalculatesServiceInsertionWithTimeSchedulingInSlices(JobInsertionCostsCalculator jic, double timeSlice, int neighbors) {
|
||||||
super();
|
super();
|
||||||
this.jic = jic;
|
this.jic = jic;
|
||||||
this.timeSlice = timeSlice;
|
this.timeSlice = timeSlice;
|
||||||
this.nOfDepartureTimes = neighbors;
|
this.nOfDepartureTimes = neighbors;
|
||||||
log.debug("initialise " + this);
|
log.debug("initialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name="+this.getClass().toString()+"][timeSlice="+timeSlice+"][#timeSlice="+nOfDepartureTimes+"]";
|
return "[name=" + this.getClass().toString() + "][timeSlice=" + timeSlice + "][#timeSlice=" + nOfDepartureTimes + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
||||||
List<Double> vehicleDepartureTimes = new ArrayList<Double>();
|
List<Double> vehicleDepartureTimes = new ArrayList<Double>();
|
||||||
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();
|
||||||
// double latestEnd = newVehicle.getLatestArrival();
|
// double latestEnd = newVehicle.getLatestArrival();
|
||||||
|
|
||||||
for(int i=0;i<nOfDepartureTimes;i++){
|
for (int i = 0; i < nOfDepartureTimes; i++) {
|
||||||
double neighborStartTime_earlier = currentStart - (i+1)*timeSlice;
|
double neighborStartTime_earlier = currentStart - (i + 1) * timeSlice;
|
||||||
// if(neighborStartTime_earlier > earliestDeparture) {
|
// if(neighborStartTime_earlier > earliestDeparture) {
|
||||||
vehicleDepartureTimes.add(neighborStartTime_earlier);
|
vehicleDepartureTimes.add(neighborStartTime_earlier);
|
||||||
// }
|
// }
|
||||||
double neighborStartTime_later = currentStart + (i+1)*timeSlice;
|
double neighborStartTime_later = currentStart + (i + 1) * timeSlice;
|
||||||
// if(neighborStartTime_later < latestEnd) {
|
// if(neighborStartTime_later < latestEnd) {
|
||||||
vehicleDepartureTimes.add(neighborStartTime_later);
|
vehicleDepartureTimes.add(neighborStartTime_later);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
InsertionData bestIData = null;
|
InsertionData bestIData = null;
|
||||||
for(Double departureTime : vehicleDepartureTimes){
|
for (Double departureTime : vehicleDepartureTimes) {
|
||||||
InsertionData iData = jic.getInsertionData(currentRoute, jobToInsert, newVehicle, departureTime, newDriver, bestKnownScore);
|
InsertionData iData = jic.getInsertionData(currentRoute, jobToInsert, newVehicle, departureTime, newDriver, bestKnownScore);
|
||||||
if(bestIData == null) bestIData = iData;
|
if (bestIData == null) bestIData = iData;
|
||||||
else if(iData.getInsertionCost() < bestIData.getInsertionCost()){
|
else if (iData.getInsertionCost() < bestIData.getInsertionCost()) {
|
||||||
iData.setVehicleDepartureTime(departureTime);
|
iData.setVehicleDepartureTime(departureTime);
|
||||||
bestIData = iData;
|
bestIData = iData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// log.info(bestIData);
|
// log.info(bestIData);
|
||||||
return bestIData;
|
return bestIData;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,38 +26,38 @@ import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
|
||||||
final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener{
|
final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener {
|
||||||
|
|
||||||
VehicleRoutingProblem vrp;
|
VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
JobInsertionConsideringFixCostsCalculator calcConsideringFix;
|
JobInsertionConsideringFixCostsCalculator calcConsideringFix;
|
||||||
|
|
||||||
private int nuOfJobsToRecreate;
|
private int nuOfJobsToRecreate;
|
||||||
|
|
||||||
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
|
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
this.calcConsideringFix = calcConsideringFix;
|
this.calcConsideringFix = calcConsideringFix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=configureFixCostCalculator]";
|
return "[name=configureFixCostCalculator]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||||
this.nuOfJobsToRecreate = unassignedJobs.size();
|
this.nuOfJobsToRecreate = unassignedJobs.size();
|
||||||
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size()));
|
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
|
||||||
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
|
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
|
||||||
// log.debug("initialise completenessRatio to " + completenessRatio);
|
// log.debug("initialise completenessRatio to " + completenessRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||||
nuOfJobsToRecreate--;
|
nuOfJobsToRecreate--;
|
||||||
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size()));
|
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
|
||||||
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
|
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio);
|
||||||
// log.debug("set completenessRatio to " + completenessRatio);
|
// log.debug("set completenessRatio to " + completenessRatio);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,38 +28,38 @@ import jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public class DellAmicoFixCostCalculator implements SoftRouteConstraint, InsertionStartsListener, JobInsertedListener{
|
public class DellAmicoFixCostCalculator implements SoftRouteConstraint, InsertionStartsListener, JobInsertedListener {
|
||||||
|
|
||||||
private int nuOfJobsToRecreate;
|
private int nuOfJobsToRecreate;
|
||||||
|
|
||||||
private final JobInsertionConsideringFixCostsCalculator calculator;
|
private final JobInsertionConsideringFixCostsCalculator calculator;
|
||||||
|
|
||||||
private final int nuOfJobs;
|
private final int nuOfJobs;
|
||||||
|
|
||||||
public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
|
public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
|
||||||
super();
|
super();
|
||||||
this.nuOfJobs=nuOfJobs;
|
this.nuOfJobs = nuOfJobs;
|
||||||
calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
|
calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCosts(JobInsertionContext insertionContext) {
|
public double getCosts(JobInsertionContext insertionContext) {
|
||||||
return calculator.getCosts(insertionContext);
|
return calculator.getCosts(insertionContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||||
this.nuOfJobsToRecreate = unassignedJobs.size();
|
this.nuOfJobsToRecreate = unassignedJobs.size();
|
||||||
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)nuOfJobs));
|
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
|
||||||
calculator.setSolutionCompletenessRatio(completenessRatio);
|
calculator.setSolutionCompletenessRatio(completenessRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
|
||||||
nuOfJobsToRecreate--;
|
nuOfJobsToRecreate--;
|
||||||
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)nuOfJobs));
|
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
|
||||||
calculator.setSolutionCompletenessRatio(completenessRatio);
|
calculator.setSolutionCompletenessRatio(completenessRatio);
|
||||||
System.out.println(completenessRatio);
|
System.out.println(completenessRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,11 @@ 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) {
|
||||||
for(EventListener l : listeners){
|
for (EventListener l : listeners) {
|
||||||
l.inform(event);
|
l.inform(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,14 @@ class InsertActivityListener implements EventListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void inform(Event event) {
|
public void inform(Event event) {
|
||||||
if(event instanceof InsertActivity){
|
if (event instanceof InsertActivity) {
|
||||||
InsertActivity insertActivity = (InsertActivity) event;
|
InsertActivity insertActivity = (InsertActivity) event;
|
||||||
if(!insertActivity.getNewVehicle().isReturnToDepot()){
|
if (!insertActivity.getNewVehicle().isReturnToDepot()) {
|
||||||
if(insertActivity.getIndex()>=insertActivity.getVehicleRoute().getActivities().size()){
|
if (insertActivity.getIndex() >= insertActivity.getVehicleRoute().getActivities().size()) {
|
||||||
insertActivity.getVehicleRoute().getEnd().setLocation(insertActivity.getActivity().getLocation());
|
insertActivity.getVehicleRoute().getEnd().setLocation(insertActivity.getActivity().getLocation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
insertActivity.getVehicleRoute().getTourActivities().addActivity(insertActivity.getIndex(),((InsertActivity) event).getActivity());
|
insertActivity.getVehicleRoute().getTourActivities().addActivity(insertActivity.getIndex(), ((InsertActivity) event).getActivity());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -30,33 +30,33 @@ import java.util.List;
|
||||||
|
|
||||||
class Inserter {
|
class Inserter {
|
||||||
|
|
||||||
interface JobInsertionHandler {
|
interface JobInsertionHandler {
|
||||||
|
|
||||||
void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route);
|
void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route);
|
||||||
|
|
||||||
void setNextHandler(JobInsertionHandler handler);
|
void setNextHandler(JobInsertionHandler handler);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class JobExceptionHandler implements JobInsertionHandler{
|
class JobExceptionHandler implements JobInsertionHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleJobInsertion(Job job, InsertionData iData,VehicleRoute route) {
|
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
||||||
throw new IllegalStateException("job insertion is not supported. Do not know job type.");
|
throw new IllegalStateException("job insertion is not supported. Do not know job type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setNextHandler(JobInsertionHandler handler) {
|
public void setNextHandler(JobInsertionHandler handler) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ServiceInsertionHandler implements JobInsertionHandler{
|
class ServiceInsertionHandler implements JobInsertionHandler {
|
||||||
|
|
||||||
private TourActivityFactory activityFactory = new DefaultTourActivityFactory();
|
private TourActivityFactory activityFactory = new DefaultTourActivityFactory();
|
||||||
|
|
||||||
private JobInsertionHandler delegator = new JobExceptionHandler();
|
private JobInsertionHandler delegator = new JobExceptionHandler();
|
||||||
|
|
||||||
private VehicleRoutingProblem vehicleRoutingProblem;
|
private VehicleRoutingProblem vehicleRoutingProblem;
|
||||||
|
|
||||||
|
|
@ -65,94 +65,93 @@ class Inserter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
||||||
if(job instanceof Service){
|
if (job instanceof Service) {
|
||||||
route.setVehicleAndDepartureTime(iData.getSelectedVehicle(),iData.getVehicleDepartureTime());
|
route.setVehicleAndDepartureTime(iData.getSelectedVehicle(), iData.getVehicleDepartureTime());
|
||||||
if(!iData.getSelectedVehicle().isReturnToDepot()){
|
if (!iData.getSelectedVehicle().isReturnToDepot()) {
|
||||||
if(iData.getDeliveryInsertionIndex()>=route.getTourActivities().getActivities().size()){
|
if (iData.getDeliveryInsertionIndex() >= route.getTourActivities().getActivities().size()) {
|
||||||
setEndLocation(route,(Service)job);
|
setEndLocation(route, (Service) job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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) {
|
||||||
route.getEnd().setLocation(service.getLocation());
|
route.getEnd().setLocation(service.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNextHandler(JobInsertionHandler jobInsertionHandler){
|
public void setNextHandler(JobInsertionHandler jobInsertionHandler) {
|
||||||
this.delegator = jobInsertionHandler;
|
this.delegator = jobInsertionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShipmentInsertionHandler implements JobInsertionHandler {
|
class ShipmentInsertionHandler implements JobInsertionHandler {
|
||||||
|
|
||||||
private final VehicleRoutingProblem vehicleRoutingProblem;
|
private final VehicleRoutingProblem vehicleRoutingProblem;
|
||||||
|
|
||||||
private TourShipmentActivityFactory activityFactory = new DefaultShipmentActivityFactory();
|
private TourShipmentActivityFactory activityFactory = new DefaultShipmentActivityFactory();
|
||||||
|
|
||||||
private JobInsertionHandler delegator = new JobExceptionHandler();
|
private JobInsertionHandler delegator = new JobExceptionHandler();
|
||||||
|
|
||||||
public ShipmentInsertionHandler(VehicleRoutingProblem vehicleRoutingProblem) {
|
public ShipmentInsertionHandler(VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
this.vehicleRoutingProblem = vehicleRoutingProblem;
|
this.vehicleRoutingProblem = vehicleRoutingProblem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
|
||||||
if(job instanceof Shipment){
|
if (job instanceof Shipment) {
|
||||||
List<AbstractActivity> acts = vehicleRoutingProblem.copyAndGetActivities(job);
|
List<AbstractActivity> acts = vehicleRoutingProblem.copyAndGetActivities(job);
|
||||||
TourActivity pickupShipment = acts.get(0);
|
TourActivity pickupShipment = acts.get(0);
|
||||||
TourActivity deliverShipment = acts.get(1);
|
TourActivity deliverShipment = acts.get(1);
|
||||||
route.setVehicleAndDepartureTime(iData.getSelectedVehicle(),iData.getVehicleDepartureTime());
|
route.setVehicleAndDepartureTime(iData.getSelectedVehicle(), iData.getVehicleDepartureTime());
|
||||||
if(!iData.getSelectedVehicle().isReturnToDepot()){
|
if (!iData.getSelectedVehicle().isReturnToDepot()) {
|
||||||
if(iData.getDeliveryInsertionIndex()>=route.getActivities().size()){
|
if (iData.getDeliveryInsertionIndex() >= route.getActivities().size()) {
|
||||||
setEndLocation(route,(Shipment)job);
|
setEndLocation(route, (Shipment) job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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) {
|
||||||
route.getEnd().setLocation(shipment.getDeliveryLocation());
|
route.getEnd().setLocation(shipment.getDeliveryLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setNextHandler(JobInsertionHandler jobInsertionHandler){
|
public void setNextHandler(JobInsertionHandler jobInsertionHandler) {
|
||||||
this.delegator = jobInsertionHandler;
|
this.delegator = jobInsertionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private InsertionListeners insertionListeners;
|
private InsertionListeners insertionListeners;
|
||||||
|
|
||||||
private JobInsertionHandler jobInsertionHandler;
|
private JobInsertionHandler jobInsertionHandler;
|
||||||
|
|
||||||
private VehicleRoutingProblem vehicleRoutingProblem;
|
private VehicleRoutingProblem vehicleRoutingProblem;
|
||||||
|
|
||||||
public Inserter(InsertionListeners insertionListeners, VehicleRoutingProblem vehicleRoutingProblem) {
|
public Inserter(InsertionListeners insertionListeners, VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
this.insertionListeners = insertionListeners;
|
this.insertionListeners = insertionListeners;
|
||||||
new DefaultTourActivityFactory();
|
new DefaultTourActivityFactory();
|
||||||
jobInsertionHandler = new ServiceInsertionHandler(vehicleRoutingProblem);
|
jobInsertionHandler = new ServiceInsertionHandler(vehicleRoutingProblem);
|
||||||
jobInsertionHandler.setNextHandler(new ShipmentInsertionHandler(vehicleRoutingProblem));
|
jobInsertionHandler.setNextHandler(new ShipmentInsertionHandler(vehicleRoutingProblem));
|
||||||
}
|
}
|
||||||
|
|
||||||
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))
|
||||||
if(job == null) throw new IllegalStateException("cannot insert null-job");
|
throw new IllegalStateException("insertionData null. cannot insert job.");
|
||||||
if(!(vehicleRoute.getVehicle().getId().equals(insertionData.getSelectedVehicle().getId()))){
|
if (job == null) throw new IllegalStateException("cannot insert null-job");
|
||||||
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
|
if (!(vehicleRoute.getVehicle().getId().equals(insertionData.getSelectedVehicle().getId()))) {
|
||||||
vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
|
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
|
||||||
}
|
vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
|
||||||
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
|
}
|
||||||
|
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
|
||||||
|
|
||||||
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
|
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,173 +30,196 @@ import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
public class InsertionBuilder {
|
public class InsertionBuilder {
|
||||||
|
|
||||||
|
private boolean fastRegret;
|
||||||
|
|
||||||
|
|
||||||
public enum Strategy {
|
public enum Strategy {
|
||||||
REGRET, BEST
|
REGRET, BEST
|
||||||
}
|
}
|
||||||
|
|
||||||
private VehicleRoutingProblem vrp;
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private StateManager stateManager;
|
private StateManager stateManager;
|
||||||
|
|
||||||
private boolean local = true;
|
private boolean local = true;
|
||||||
|
|
||||||
private ConstraintManager constraintManager;
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
private double weightOfFixedCosts;
|
private double weightOfFixedCosts;
|
||||||
|
|
||||||
private boolean considerFixedCosts = false;
|
private boolean considerFixedCosts = false;
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
|
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
|
||||||
|
|
||||||
private int forwaredLooking;
|
private int forwaredLooking;
|
||||||
|
|
||||||
private int memory;
|
private int memory;
|
||||||
|
|
||||||
private ExecutorService executor;
|
private ExecutorService executor;
|
||||||
|
|
||||||
private int nuOfThreads;
|
private int nuOfThreads;
|
||||||
|
|
||||||
private double timeSlice;
|
private double timeSlice;
|
||||||
|
|
||||||
private int nNeighbors;
|
private int nNeighbors;
|
||||||
|
|
||||||
private boolean timeScheduling=false;
|
private boolean timeScheduling = false;
|
||||||
|
|
||||||
private boolean allowVehicleSwitch=true;
|
private boolean allowVehicleSwitch = true;
|
||||||
|
|
||||||
private boolean addDefaultCostCalc=true;
|
private boolean addDefaultCostCalc = true;
|
||||||
|
|
||||||
private Strategy strategy = Strategy.BEST;
|
private Strategy strategy = Strategy.BEST;
|
||||||
|
|
||||||
public InsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
private boolean isFastRegret = false;
|
||||||
super();
|
|
||||||
this.vrp = vrp;
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
this.constraintManager = constraintManager;
|
|
||||||
this.fleetManager = vehicleFleetManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertionBuilder setInsertionStrategy(Strategy strategy){
|
public InsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
||||||
|
super();
|
||||||
|
this.vrp = vrp;
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
this.constraintManager = constraintManager;
|
||||||
|
this.fleetManager = vehicleFleetManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionBuilder setInsertionStrategy(Strategy strategy) {
|
||||||
this.strategy = strategy;
|
this.strategy = strategy;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionBuilder setRouteLevel(int forwardLooking, int memory){
|
public InsertionBuilder setRouteLevel(int forwardLooking, int memory) {
|
||||||
local = false;
|
local = false;
|
||||||
this.forwaredLooking = forwardLooking;
|
this.forwaredLooking = forwardLooking;
|
||||||
this.memory = memory;
|
this.memory = memory;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation){
|
public InsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation) {
|
||||||
local = false;
|
local = false;
|
||||||
this.forwaredLooking = forwardLooking;
|
this.forwaredLooking = forwardLooking;
|
||||||
this.memory = memory;
|
this.memory = memory;
|
||||||
this.addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
this.addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionBuilder setLocalLevel(){
|
public InsertionBuilder setFastRegret(boolean fastRegret) {
|
||||||
local = true;
|
this.isFastRegret = fastRegret;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
|
|
||||||
* is controlled by your custom soft constraints.
|
|
||||||
*
|
|
||||||
* @param addDefaultMarginalCostCalculation
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public InsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation){
|
|
||||||
local = true;
|
|
||||||
addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertionBuilder considerFixedCosts(double weightOfFixedCosts){
|
|
||||||
this.weightOfFixedCosts = weightOfFixedCosts;
|
|
||||||
this.considerFixedCosts = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){
|
|
||||||
this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads){
|
|
||||||
this.executor = executor;
|
|
||||||
this.nuOfThreads = nuOfThreads;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public InsertionStrategy build() {
|
public InsertionBuilder setLocalLevel() {
|
||||||
List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
|
local = true;
|
||||||
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
|
return this;
|
||||||
JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners);
|
}
|
||||||
if(local){
|
|
||||||
calcBuilder.setLocalLevel(addDefaultCostCalc);
|
/**
|
||||||
}
|
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
|
||||||
else {
|
* is controlled by your custom soft constraints.
|
||||||
calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc);
|
*
|
||||||
}
|
* @param addDefaultMarginalCostCalculation
|
||||||
calcBuilder.setConstraintManager(constraintManager);
|
* @return
|
||||||
calcBuilder.setStateManager(stateManager);
|
*/
|
||||||
calcBuilder.setVehicleRoutingProblem(vrp);
|
public InsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation) {
|
||||||
calcBuilder.setVehicleFleetManager(fleetManager);
|
local = true;
|
||||||
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
|
addDefaultCostCalc = addDefaultMarginalCostCalculation;
|
||||||
if(considerFixedCosts) {
|
return this;
|
||||||
calcBuilder.considerFixedCosts(weightOfFixedCosts);
|
}
|
||||||
}
|
|
||||||
if(timeScheduling){
|
public InsertionBuilder considerFixedCosts(double weightOfFixedCosts) {
|
||||||
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors);
|
this.weightOfFixedCosts = weightOfFixedCosts;
|
||||||
}
|
this.considerFixedCosts = true;
|
||||||
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch);
|
return this;
|
||||||
JobInsertionCostsCalculator costCalculator = calcBuilder.build();
|
}
|
||||||
|
|
||||||
|
public InsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
|
||||||
|
this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) {
|
||||||
|
this.executor = executor;
|
||||||
|
this.nuOfThreads = nuOfThreads;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public InsertionStrategy build() {
|
||||||
|
List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
|
||||||
|
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
|
||||||
|
JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners);
|
||||||
|
if (local) {
|
||||||
|
calcBuilder.setLocalLevel(addDefaultCostCalc);
|
||||||
|
} else {
|
||||||
|
calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc);
|
||||||
|
}
|
||||||
|
calcBuilder.setConstraintManager(constraintManager);
|
||||||
|
calcBuilder.setStateManager(stateManager);
|
||||||
|
calcBuilder.setVehicleRoutingProblem(vrp);
|
||||||
|
calcBuilder.setVehicleFleetManager(fleetManager);
|
||||||
|
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
|
||||||
|
if (considerFixedCosts) {
|
||||||
|
calcBuilder.considerFixedCosts(weightOfFixedCosts);
|
||||||
|
}
|
||||||
|
if (timeScheduling) {
|
||||||
|
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors);
|
||||||
|
}
|
||||||
|
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch);
|
||||||
|
JobInsertionCostsCalculator costCalculator = calcBuilder.build();
|
||||||
|
|
||||||
InsertionStrategy insertion;
|
InsertionStrategy insertion;
|
||||||
if(strategy.equals(Strategy.BEST)) {
|
if (strategy.equals(Strategy.BEST)) {
|
||||||
if (executor == null) {
|
if (executor == null) {
|
||||||
insertion = new BestInsertion(costCalculator, vrp);
|
insertion = new BestInsertion(costCalculator, vrp);
|
||||||
} 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 {
|
||||||
|
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{
|
||||||
|
RegretInsertionConcurrent regret = new RegretInsertionConcurrent(costCalculator, vrp, executor);
|
||||||
|
insertion = regret;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
} else throw new IllegalStateException("you should never get here");
|
||||||
insertion = new RegretInsertionConcurrent(costCalculator,vrp,executor);
|
for (InsertionListener l : iListeners) insertion.addListener(l);
|
||||||
}
|
return insertion;
|
||||||
}
|
}
|
||||||
else throw new IllegalStateException("you should never get here");
|
|
||||||
for(InsertionListener l : iListeners) insertion.addListener(l);
|
|
||||||
return insertion;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated this is experimental and can disappear.
|
|
||||||
* @param timeSlice the time slice
|
|
||||||
* @param nNeighbors number of neighbors
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
|
|
||||||
this.timeSlice=timeSlice;
|
|
||||||
this.nNeighbors=nNeighbors;
|
|
||||||
timeScheduling=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertionBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) {
|
|
||||||
this.allowVehicleSwitch = allowVehicleSwitch;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param timeSlice the time slice
|
||||||
|
* @param nNeighbors number of neighbors
|
||||||
|
* @deprecated this is experimental and can disappear.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
|
||||||
|
this.timeSlice = timeSlice;
|
||||||
|
this.nNeighbors = nNeighbors;
|
||||||
|
timeScheduling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InsertionBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) {
|
||||||
|
this.allowVehicleSwitch = allowVehicleSwitch;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,140 +27,138 @@ 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 {
|
||||||
|
|
||||||
public static class NoInsertionFound extends InsertionData{
|
public static class NoInsertionFound extends InsertionData {
|
||||||
|
|
||||||
public NoInsertionFound() {
|
public NoInsertionFound() {
|
||||||
super(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);
|
super(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InsertionData noInsertion = new NoInsertionFound();
|
private static InsertionData noInsertion = new NoInsertionFound();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an instance of InsertionData that represents an EmptyInsertionData (which might indicate
|
* Returns an instance of InsertionData that represents an EmptyInsertionData (which might indicate
|
||||||
* that no insertion has been found). It is internally instantiated as follows:<br>
|
* that no insertion has been found). It is internally instantiated as follows:<br>
|
||||||
* <code>new InsertionData(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);</code><br>
|
* <code>new InsertionData(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);</code><br>
|
||||||
* where NO_INDEX=-1.
|
* where NO_INDEX=-1.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static InsertionData createEmptyInsertionData(){
|
public static InsertionData createEmptyInsertionData() {
|
||||||
return noInsertion;
|
return noInsertion;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int NO_INDEX = -1;
|
static int NO_INDEX = -1;
|
||||||
|
|
||||||
private final double insertionCost;
|
private final double insertionCost;
|
||||||
|
|
||||||
private final int pickupInsertionIndex;
|
private final int pickupInsertionIndex;
|
||||||
|
|
||||||
private final int deliveryInsertionIndex;
|
private final int deliveryInsertionIndex;
|
||||||
|
|
||||||
private final Vehicle selectedVehicle;
|
private final Vehicle selectedVehicle;
|
||||||
|
|
||||||
private final Driver selectedDriver;
|
private final Driver selectedDriver;
|
||||||
|
|
||||||
private double departureTime;
|
private double departureTime;
|
||||||
|
|
||||||
private double additionalTime;
|
private double additionalTime;
|
||||||
|
|
||||||
private List<Event> events = new ArrayList<Event>();
|
private List<Event> events = new ArrayList<Event>();
|
||||||
|
|
||||||
List<Event> getEvents(){
|
List<Event> getEvents() {
|
||||||
return events;
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the additionalTime
|
* @return the additionalTime
|
||||||
*/
|
*/
|
||||||
public double getAdditionalTime() {
|
public double getAdditionalTime() {
|
||||||
return additionalTime;
|
return additionalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param additionalTime the additionalTime to set
|
* @param additionalTime the additionalTime to set
|
||||||
*/
|
*/
|
||||||
public void setAdditionalTime(double additionalTime) {
|
public void setAdditionalTime(double additionalTime) {
|
||||||
this.additionalTime = additionalTime;
|
this.additionalTime = additionalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver){
|
public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver) {
|
||||||
this.insertionCost = insertionCost;
|
this.insertionCost = insertionCost;
|
||||||
this.pickupInsertionIndex = pickupInsertionIndex;
|
this.pickupInsertionIndex = pickupInsertionIndex;
|
||||||
this.deliveryInsertionIndex = deliveryInsertionIndex;
|
this.deliveryInsertionIndex = deliveryInsertionIndex;
|
||||||
this.selectedVehicle = vehicle;
|
this.selectedVehicle = vehicle;
|
||||||
this.selectedDriver = driver;
|
this.selectedDriver = driver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[iCost="+insertionCost+"][pickupIndex="+pickupInsertionIndex+"][deliveryIndex="+deliveryInsertionIndex+"][depTime="+departureTime+"][vehicle="+selectedVehicle+"][driver="+selectedDriver+"]";
|
return "[iCost=" + insertionCost + "][pickupIndex=" + pickupInsertionIndex + "][deliveryIndex=" + deliveryInsertionIndex + "][depTime=" + departureTime + "][vehicle=" + selectedVehicle + "][driver=" + selectedDriver + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns insertionIndex of deliveryActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
|
* Returns insertionIndex of deliveryActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int getDeliveryInsertionIndex(){
|
public int getDeliveryInsertionIndex() {
|
||||||
return deliveryInsertionIndex;
|
return deliveryInsertionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns insertionIndex of pickkupActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
|
* Returns insertionIndex of pickkupActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public int getPickupInsertionIndex(){
|
public int getPickupInsertionIndex() {
|
||||||
return pickupInsertionIndex;
|
return pickupInsertionIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns insertion costs (which might be the additional costs of inserting the corresponding job).
|
* Returns insertion costs (which might be the additional costs of inserting the corresponding job).
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public double getInsertionCost() {
|
public double getInsertionCost() {
|
||||||
return insertionCost;
|
return insertionCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the vehicle to be employed.
|
* Returns the vehicle to be employed.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Vehicle getSelectedVehicle() {
|
public Vehicle getSelectedVehicle() {
|
||||||
return selectedVehicle;
|
return selectedVehicle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the vehicle to be employed.
|
* Returns the vehicle to be employed.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Driver getSelectedDriver(){
|
public Driver getSelectedDriver() {
|
||||||
return selectedDriver;
|
return selectedDriver;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the departureTime
|
* @return the departureTime
|
||||||
*/
|
*/
|
||||||
public double getVehicleDepartureTime() {
|
public double getVehicleDepartureTime() {
|
||||||
return departureTime;
|
return departureTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param departureTime the departureTime to set
|
|
||||||
*/
|
|
||||||
public void setVehicleDepartureTime(double departureTime) {
|
|
||||||
this.departureTime = departureTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param departureTime the departureTime to set
|
||||||
|
*/
|
||||||
|
public void setVehicleDepartureTime(double departureTime) {
|
||||||
|
this.departureTime = departureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,27 +23,26 @@ 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 unassignedJobs jobs to be inserted
|
* @param vehicleRoutes existing vehicle routes
|
||||||
|
* @param unassignedJobs jobs to be inserted
|
||||||
*/
|
*/
|
||||||
public Collection<Job> insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
public Collection<Job> insertJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
|
||||||
|
|
||||||
public void addListener(InsertionListener insertionListener);
|
public void addListener(InsertionListener insertionListener);
|
||||||
|
|
||||||
public void removeListener(InsertionListener insertionListener);
|
public void removeListener(InsertionListener insertionListener);
|
||||||
|
|
||||||
public Collection<InsertionListener> getListeners();
|
public Collection<InsertionListener> getListeners();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,6 @@ import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
|
|
||||||
public interface InsertionStrategyFactory {
|
public interface InsertionStrategyFactory {
|
||||||
|
|
||||||
public InsertionStrategy createStrategy(VehicleRoutingProblem vrp);
|
public InsertionStrategy createStrategy(VehicleRoutingProblem vrp);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,18 +27,18 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
class JobCalculatorSwitcher implements JobInsertionCostsCalculator{
|
class JobCalculatorSwitcher implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
private Map<Class<? extends Job>,JobInsertionCostsCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCostsCalculator>();
|
private Map<Class<? extends Job>, JobInsertionCostsCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCostsCalculator>();
|
||||||
|
|
||||||
void put(Class<? extends Job> jobClass, JobInsertionCostsCalculator jic){
|
void put(Class<? extends Job> jobClass, JobInsertionCostsCalculator jic) {
|
||||||
calcMap.put(jobClass, jic);
|
calcMap.put(jobClass, jic);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore){
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
|
||||||
JobInsertionCostsCalculator jic = calcMap.get(jobToInsert.getClass());
|
JobInsertionCostsCalculator jic = calcMap.get(jobToInsert.getClass());
|
||||||
if(jic==null) throw new IllegalStateException("cannot find calculator for " + jobToInsert.getClass());
|
if (jic == null) throw new IllegalStateException("cannot find calculator for " + jobToInsert.getClass());
|
||||||
return jic.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownScore);
|
return jic.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,107 +30,103 @@ import jsprit.core.problem.vehicle.VehicleImpl.NoVehicle;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator, SoftRouteConstraint{
|
final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator, SoftRouteConstraint {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(JobInsertionConsideringFixCostsCalculator.class);
|
private static final Logger logger = LogManager.getLogger(JobInsertionConsideringFixCostsCalculator.class);
|
||||||
|
|
||||||
private final JobInsertionCostsCalculator standardServiceInsertion;
|
private final JobInsertionCostsCalculator standardServiceInsertion;
|
||||||
|
|
||||||
private double weight_deltaFixCost = 0.5;
|
private double weight_deltaFixCost = 0.5;
|
||||||
|
|
||||||
private double solution_completeness_ratio = 0.5;
|
private double solution_completeness_ratio = 0.5;
|
||||||
|
|
||||||
private RouteAndActivityStateGetter stateGetter;
|
private RouteAndActivityStateGetter stateGetter;
|
||||||
|
|
||||||
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) {
|
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) {
|
||||||
super();
|
super();
|
||||||
this.standardServiceInsertion = standardInsertionCalculator;
|
this.standardServiceInsertion = standardInsertionCalculator;
|
||||||
this.stateGetter = stateGetter;
|
this.stateGetter = stateGetter;
|
||||||
logger.debug("inialise " + this);
|
logger.debug("inialise {}", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
|
public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) {
|
||||||
double fixcost_contribution = getFixCostContribution(currentRoute,jobToInsert, newVehicle);
|
double fixcost_contribution = getFixCostContribution(currentRoute, jobToInsert, newVehicle);
|
||||||
if(fixcost_contribution > bestKnownPrice){
|
if (fixcost_contribution > bestKnownPrice) {
|
||||||
return InsertionData.createEmptyInsertionData();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
|
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
|
||||||
if(iData instanceof NoInsertionFound){
|
if (iData instanceof NoInsertionFound) {
|
||||||
return iData;
|
return iData;
|
||||||
}
|
}
|
||||||
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
|
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
|
||||||
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
insertionData.getEvents().addAll(iData.getEvents());
|
insertionData.getEvents().addAll(iData.getEvents());
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings="+weight_deltaFixCost+"]";
|
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weight_deltaFixCost + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSolutionCompletenessRatio(double ratio){
|
public void setSolutionCompletenessRatio(double ratio) {
|
||||||
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)){
|
currentFix += route.getVehicle().getType().getVehicleCostParams().fix;
|
||||||
currentFix += route.getVehicle().getType().getVehicleCostParams().fix;
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
|
||||||
if(!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)){
|
return Double.MAX_VALUE;
|
||||||
return Double.MAX_VALUE;
|
}
|
||||||
}
|
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);
|
Capacity load = Capacity.addup(currentLoad, job.getSize());
|
||||||
// int currentLoad = getCurrentMaxLoadInRoute(route);
|
double currentRelFix = 0.0;
|
||||||
Capacity load = Capacity.addup(currentLoad, job.getSize());
|
if (route.getVehicle() != null) {
|
||||||
// double load = currentLoad + job.getCapacityDemand();
|
if (!(route.getVehicle() instanceof NoVehicle)) {
|
||||||
double currentRelFix = 0.0;
|
currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
|
||||||
if(route.getVehicle() != null){
|
}
|
||||||
if(!(route.getVehicle() instanceof NoVehicle)){
|
}
|
||||||
currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
|
if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
|
||||||
}
|
return Double.MAX_VALUE;
|
||||||
}
|
}
|
||||||
if(!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)){
|
double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix;
|
||||||
return Double.MAX_VALUE;
|
return relativeFixCost;
|
||||||
}
|
}
|
||||||
double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix* (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix;
|
|
||||||
return relativeFixCost;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
|
private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) {
|
||||||
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
|
Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class);
|
||||||
if(maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
|
if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build();
|
||||||
return maxLoad;
|
return maxLoad;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCosts(JobInsertionContext insertionContext) {
|
public double getCosts(JobInsertionContext insertionContext) {
|
||||||
return getFixCostContribution(insertionContext.getRoute(), insertionContext.getJob(), insertionContext.getNewVehicle());
|
return getFixCostContribution(insertionContext.getRoute(), insertionContext.getJob(), insertionContext.getNewVehicle());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
|
|
||||||
|
|
||||||
public interface JobInsertionCostsCalculator {
|
public interface JobInsertionCostsCalculator {
|
||||||
|
|
||||||
public InsertionData getInsertionData(VehicleRoute currentRoute, Job newJob, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownCosts);
|
public InsertionData getInsertionData(VehicleRoute currentRoute, Job newJob, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownCosts);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,250 +32,251 @@ 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 {
|
||||||
|
|
||||||
private JobInsertionCostsCalculator calculator;
|
private JobInsertionCostsCalculator calculator;
|
||||||
|
|
||||||
public JobInsertionCostsCalculator getCalculator() {
|
public JobInsertionCostsCalculator getCalculator() {
|
||||||
return calculator;
|
return calculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PrioritizedVRAListener> algorithmListener = new ArrayList<PrioritizedVRAListener>();
|
private List<PrioritizedVRAListener> algorithmListener = new ArrayList<PrioritizedVRAListener>();
|
||||||
private List<InsertionListener> insertionListener = new ArrayList<InsertionListener>();
|
private List<InsertionListener> insertionListener = new ArrayList<InsertionListener>();
|
||||||
|
|
||||||
public CalculatorPlusListeners(JobInsertionCostsCalculator calculator) {
|
public CalculatorPlusListeners(JobInsertionCostsCalculator calculator) {
|
||||||
super();
|
super();
|
||||||
this.calculator = calculator;
|
this.calculator = calculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PrioritizedVRAListener> getAlgorithmListener() {
|
public List<PrioritizedVRAListener> getAlgorithmListener() {
|
||||||
return algorithmListener;
|
return algorithmListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<InsertionListener> getInsertionListener() {
|
public List<InsertionListener> getInsertionListener() {
|
||||||
return insertionListener;
|
return insertionListener;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<InsertionListener> insertionListeners;
|
private List<InsertionListener> insertionListeners;
|
||||||
|
|
||||||
private List<PrioritizedVRAListener> algorithmListeners;
|
private List<PrioritizedVRAListener> algorithmListeners;
|
||||||
|
|
||||||
private VehicleRoutingProblem vrp;
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private RouteAndActivityStateGetter states;
|
private RouteAndActivityStateGetter states;
|
||||||
|
|
||||||
private boolean local = true;
|
private boolean local = true;
|
||||||
|
|
||||||
private int forwardLooking = 0;
|
private int forwardLooking = 0;
|
||||||
|
|
||||||
private int memory = 1;
|
private int memory = 1;
|
||||||
|
|
||||||
private boolean considerFixedCost = false;
|
private boolean considerFixedCost = false;
|
||||||
|
|
||||||
private double weightOfFixedCost = 0;
|
private double weightOfFixedCost = 0;
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
private boolean timeScheduling = false;
|
private boolean timeScheduling = false;
|
||||||
|
|
||||||
private double timeSlice;
|
private double timeSlice;
|
||||||
|
|
||||||
private int neighbors;
|
private int neighbors;
|
||||||
|
|
||||||
private ConstraintManager constraintManager;
|
private ConstraintManager constraintManager;
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator activityInsertionCostCalculator = null;
|
private ActivityInsertionCostsCalculator activityInsertionCostCalculator = null;
|
||||||
|
|
||||||
private boolean allowVehicleSwitch = true;
|
private boolean allowVehicleSwitch = true;
|
||||||
|
|
||||||
private boolean addDefaultCostCalc = true;
|
private boolean addDefaultCostCalc = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
* @param insertionListeners
|
* @param insertionListeners
|
||||||
* @param algorithmListeners
|
* @param algorithmListeners
|
||||||
*/
|
*/
|
||||||
public JobInsertionCostsCalculatorBuilder(List<InsertionListener> insertionListeners, List<PrioritizedVRAListener> algorithmListeners) {
|
public JobInsertionCostsCalculatorBuilder(List<InsertionListener> insertionListeners, List<PrioritizedVRAListener> algorithmListeners) {
|
||||||
super();
|
super();
|
||||||
this.insertionListeners = insertionListeners;
|
this.insertionListeners = insertionListeners;
|
||||||
this.algorithmListeners = algorithmListeners;
|
this.algorithmListeners = algorithmListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
||||||
this.states = stateManager;
|
this.states = stateManager;
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets routingProblem. MUST be set.
|
|
||||||
*
|
|
||||||
* @param vehicleRoutingProblem
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public JobInsertionCostsCalculatorBuilder setVehicleRoutingProblem(VehicleRoutingProblem vehicleRoutingProblem){
|
|
||||||
this.vrp = vehicleRoutingProblem;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets fleetManager. MUST be set.
|
|
||||||
*
|
|
||||||
* @param fleetManager
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public JobInsertionCostsCalculatorBuilder setVehicleFleetManager(VehicleFleetManager fleetManager){
|
|
||||||
this.fleetManager = fleetManager;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a flag to build a calculator based on local calculations.
|
|
||||||
*
|
|
||||||
* <p>Insertion of a job and job-activity is evaluated based on the previous and next activity.
|
|
||||||
* @param addDefaultCostCalc
|
|
||||||
*/
|
|
||||||
public JobInsertionCostsCalculatorBuilder setLocalLevel(boolean addDefaultCostCalc){
|
|
||||||
local = true;
|
|
||||||
this.addDefaultCostCalc = addDefaultCostCalc;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobInsertionCostsCalculatorBuilder setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){
|
/**
|
||||||
this.activityInsertionCostCalculator = activityInsertionCostsCalculator;
|
* Sets routingProblem. MUST be set.
|
||||||
|
*
|
||||||
|
* @param vehicleRoutingProblem
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public JobInsertionCostsCalculatorBuilder setVehicleRoutingProblem(VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
|
this.vrp = vehicleRoutingProblem;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a flag to build a calculator that evaluates job insertion on route-level.
|
* Sets fleetManager. MUST be set.
|
||||||
*
|
*
|
||||||
* @param forwardLooking
|
* @param fleetManager
|
||||||
* @param memory
|
* @return
|
||||||
* @param addDefaultMarginalCostCalc
|
*/
|
||||||
*/
|
public JobInsertionCostsCalculatorBuilder setVehicleFleetManager(VehicleFleetManager fleetManager) {
|
||||||
public JobInsertionCostsCalculatorBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalc){
|
this.fleetManager = fleetManager;
|
||||||
local = false;
|
|
||||||
this.forwardLooking = forwardLooking;
|
|
||||||
this.memory = memory;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a flag to consider also fixed-cost when evaluating the insertion of a job. The weight of the fixed-cost can be determined by setting
|
* Sets a flag to build a calculator based on local calculations.
|
||||||
* weightofFixedCosts.
|
* <p/>
|
||||||
*
|
* <p>Insertion of a job and job-activity is evaluated based on the previous and next activity.
|
||||||
* @param weightOfFixedCosts
|
*
|
||||||
*/
|
* @param addDefaultCostCalc
|
||||||
public JobInsertionCostsCalculatorBuilder considerFixedCosts(double weightOfFixedCosts){
|
*/
|
||||||
considerFixedCost = true;
|
public JobInsertionCostsCalculatorBuilder setLocalLevel(boolean addDefaultCostCalc) {
|
||||||
this.weightOfFixedCost = weightOfFixedCosts;
|
local = true;
|
||||||
|
this.addDefaultCostCalc = addDefaultCostCalc;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobInsertionCostsCalculatorBuilder experimentalTimeScheduler(double timeSlice, int neighbors){
|
public JobInsertionCostsCalculatorBuilder setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
|
||||||
timeScheduling = true;
|
this.activityInsertionCostCalculator = activityInsertionCostsCalculator;
|
||||||
this.timeSlice = timeSlice;
|
|
||||||
this.neighbors = neighbors;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the jobInsertionCalculator.
|
* Sets a flag to build a calculator that evaluates job insertion on route-level.
|
||||||
*
|
*
|
||||||
* @return jobInsertionCalculator.
|
* @param forwardLooking
|
||||||
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
|
* @param memory
|
||||||
*/
|
* @param addDefaultMarginalCostCalc
|
||||||
public JobInsertionCostsCalculator build(){
|
*/
|
||||||
if(vrp == null) throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
|
public JobInsertionCostsCalculatorBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalc) {
|
||||||
if(states == null) throw new IllegalStateException("states is null, but is must be set (this.setStateManager(states))");
|
local = false;
|
||||||
if(fleetManager == null) throw new IllegalStateException("fleetManager is null, but it must be set (this.setVehicleFleetManager(fleetManager))");
|
this.forwardLooking = forwardLooking;
|
||||||
JobInsertionCostsCalculator baseCalculator = null;
|
this.memory = memory;
|
||||||
CalculatorPlusListeners standardLocal = null;
|
return this;
|
||||||
if(local){
|
}
|
||||||
standardLocal = createStandardLocal(vrp, states);
|
|
||||||
}
|
/**
|
||||||
else{
|
* Sets a flag to consider also fixed-cost when evaluating the insertion of a job. The weight of the fixed-cost can be determined by setting
|
||||||
checkServicesOnly();
|
* weightofFixedCosts.
|
||||||
standardLocal = createStandardRoute(vrp, states,forwardLooking,memory);
|
*
|
||||||
}
|
* @param weightOfFixedCosts
|
||||||
baseCalculator = standardLocal.getCalculator();
|
*/
|
||||||
addAlgorithmListeners(standardLocal.getAlgorithmListener());
|
public JobInsertionCostsCalculatorBuilder considerFixedCosts(double weightOfFixedCosts) {
|
||||||
addInsertionListeners(standardLocal.getInsertionListener());
|
considerFixedCost = true;
|
||||||
if(considerFixedCost){
|
this.weightOfFixedCost = weightOfFixedCosts;
|
||||||
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
|
return this;
|
||||||
baseCalculator = withFixed.getCalculator();
|
}
|
||||||
addAlgorithmListeners(withFixed.getAlgorithmListener());
|
|
||||||
addInsertionListeners(withFixed.getInsertionListener());
|
public JobInsertionCostsCalculatorBuilder experimentalTimeScheduler(double timeSlice, int neighbors) {
|
||||||
}
|
timeScheduling = true;
|
||||||
if(timeScheduling){
|
this.timeSlice = timeSlice;
|
||||||
|
this.neighbors = neighbors;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the jobInsertionCalculator.
|
||||||
|
*
|
||||||
|
* @return jobInsertionCalculator.
|
||||||
|
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
|
||||||
|
*/
|
||||||
|
public JobInsertionCostsCalculator build() {
|
||||||
|
if (vrp == null)
|
||||||
|
throw new IllegalStateException("vehicle-routing-problem is null, but it must be set (this.setVehicleRoutingProblem(vrp))");
|
||||||
|
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;
|
||||||
|
CalculatorPlusListeners standardLocal = null;
|
||||||
|
if (local) {
|
||||||
|
standardLocal = createStandardLocal(vrp, states);
|
||||||
|
} else {
|
||||||
|
checkServicesOnly();
|
||||||
|
standardLocal = createStandardRoute(vrp, states, forwardLooking, memory);
|
||||||
|
}
|
||||||
|
baseCalculator = standardLocal.getCalculator();
|
||||||
|
addAlgorithmListeners(standardLocal.getAlgorithmListener());
|
||||||
|
addInsertionListeners(standardLocal.getInsertionListener());
|
||||||
|
if (considerFixedCost) {
|
||||||
|
CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost);
|
||||||
|
baseCalculator = withFixed.getCalculator();
|
||||||
|
addAlgorithmListeners(withFixed.getAlgorithmListener());
|
||||||
|
addInsertionListeners(withFixed.getInsertionListener());
|
||||||
|
}
|
||||||
|
if (timeScheduling) {
|
||||||
// baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors);
|
// baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors);
|
||||||
CalculatesServiceInsertionWithTimeScheduling wts = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator,timeSlice,neighbors);
|
CalculatesServiceInsertionWithTimeScheduling wts = new CalculatesServiceInsertionWithTimeScheduling(baseCalculator, timeSlice, neighbors);
|
||||||
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(wts);
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(wts);
|
||||||
calcPlusListeners.getInsertionListener().add(new CalculatesServiceInsertionWithTimeScheduling.KnowledgeInjection(wts));
|
calcPlusListeners.getInsertionListener().add(new CalculatesServiceInsertionWithTimeScheduling.KnowledgeInjection(wts));
|
||||||
addInsertionListeners(calcPlusListeners.getInsertionListener());
|
addInsertionListeners(calcPlusListeners.getInsertionListener());
|
||||||
baseCalculator = calcPlusListeners.getCalculator();
|
baseCalculator = calcPlusListeners.getCalculator();
|
||||||
}
|
}
|
||||||
return createFinalInsertion(fleetManager, baseCalculator, states);
|
return createFinalInsertion(fleetManager, baseCalculator, states);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkServicesOnly() {
|
private void checkServicesOnly() {
|
||||||
for(Job j : vrp.getJobs().values()){
|
for (Job j : vrp.getJobs().values()) {
|
||||||
if(j instanceof Shipment){
|
if (j instanceof Shipment) {
|
||||||
throw new UnsupportedOperationException("currently the 'insert-on-route-level' option is only available for services (i.e. service, pickup, delivery), \n" +
|
throw new UnsupportedOperationException("currently the 'insert-on-route-level' option is only available for services (i.e. service, pickup, delivery), \n" +
|
||||||
"if you want to deal with shipments switch to option 'local-level' by either setting bestInsertionBuilder.setLocalLevel() or \n"
|
"if you want to deal with shipments switch to option 'local-level' by either setting bestInsertionBuilder.setLocalLevel() or \n"
|
||||||
+ "by omitting the xml-tag '<level forwardLooking=2 memory=1>route</level>' when defining your insertionStrategy in algo-config.xml file");
|
+ "by omitting the xml-tag '<level forwardLooking=2 memory=1>route</level>' when defining your insertionStrategy in algo-config.xml file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addInsertionListeners(List<InsertionListener> list) {
|
private void addInsertionListeners(List<InsertionListener> list) {
|
||||||
for(InsertionListener iL : list){
|
for (InsertionListener iL : list) {
|
||||||
insertionListeners.add(iL);
|
insertionListeners.add(iL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAlgorithmListeners(List<PrioritizedVRAListener> list) {
|
private void addAlgorithmListeners(List<PrioritizedVRAListener> list) {
|
||||||
for(PrioritizedVRAListener aL : list){
|
for (PrioritizedVRAListener aL : list) {
|
||||||
algorithmListeners.add(aL);
|
algorithmListeners.add(aL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalculatorPlusListeners createStandardLocal(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter statesManager){
|
private CalculatorPlusListeners createStandardLocal(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter statesManager) {
|
||||||
if(constraintManager == null) throw new IllegalStateException("constraint-manager is null");
|
if (constraintManager == null) throw new IllegalStateException("constraint-manager is null");
|
||||||
|
|
||||||
ActivityInsertionCostsCalculator actInsertionCalc;
|
ActivityInsertionCostsCalculator actInsertionCalc;
|
||||||
if(activityInsertionCostCalculator == null && addDefaultCostCalc){
|
ConfigureLocalActivityInsertionCalculator configLocal = null;
|
||||||
actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts());
|
if (activityInsertionCostCalculator == null && addDefaultCostCalc) {
|
||||||
}
|
actInsertionCalc = new LocalActivityInsertionCostsCalculator(vrp.getTransportCosts(), vrp.getActivityCosts(), statesManager);
|
||||||
else if(activityInsertionCostCalculator == null && !addDefaultCostCalc){
|
configLocal = new ConfigureLocalActivityInsertionCalculator(vrp, (LocalActivityInsertionCostsCalculator) actInsertionCalc);
|
||||||
actInsertionCalc = new ActivityInsertionCostsCalculator(){
|
} else if (activityInsertionCostCalculator == null && !addDefaultCostCalc) {
|
||||||
|
actInsertionCalc = new ActivityInsertionCostsCalculator() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct,
|
public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct,
|
||||||
double depTimeAtPrevAct) {
|
double depTimeAtPrevAct) {
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
} else {
|
||||||
else{
|
actInsertionCalc = activityInsertionCostCalculator;
|
||||||
actInsertionCalc = activityInsertionCostCalculator;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
JobActivityFactory activityFactory = new JobActivityFactory() {
|
JobActivityFactory activityFactory = new JobActivityFactory() {
|
||||||
|
|
||||||
|
|
@ -285,55 +286,61 @@ public class JobInsertionCostsCalculatorBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
ShipmentInsertionCalculator shipmentInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager);
|
ShipmentInsertionCalculator shipmentInsertion = new ShipmentInsertionCalculator(vrp.getTransportCosts(), actInsertionCalc, constraintManager);
|
||||||
shipmentInsertion.setJobActivityFactory(activityFactory);
|
shipmentInsertion.setJobActivityFactory(activityFactory);
|
||||||
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) {
|
||||||
final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2);
|
final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2);
|
||||||
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
|
withFixCost.setWeightOfFixCost(weightOfFixedCosts);
|
||||||
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
|
CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost);
|
||||||
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
|
calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost));
|
||||||
return calcPlusListeners;
|
return calcPlusListeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory){
|
private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory) {
|
||||||
ActivityInsertionCostsCalculator routeLevelCostEstimator;
|
ActivityInsertionCostsCalculator routeLevelCostEstimator;
|
||||||
if(activityInsertionCostCalculator == null && addDefaultCostCalc){
|
if (activityInsertionCostCalculator == null && addDefaultCostCalc) {
|
||||||
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.);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct,
|
public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct,
|
||||||
double depTimeAtPrevAct) {
|
double depTimeAtPrevAct) {
|
||||||
return 0.;
|
return 0.;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
} 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);
|
||||||
jobInsertionCalculator.setNuOfActsForwardLooking(forwardLooking);
|
jobInsertionCalculator.setNuOfActsForwardLooking(forwardLooking);
|
||||||
jobInsertionCalculator.setMemorySize(solutionMemory);
|
jobInsertionCalculator.setMemorySize(solutionMemory);
|
||||||
jobInsertionCalculator.setStates(activityStates2);
|
jobInsertionCalculator.setStates(activityStates2);
|
||||||
jobInsertionCalculator.setJobActivityFactory(new JobActivityFactory() {
|
jobInsertionCalculator.setJobActivityFactory(new JobActivityFactory() {
|
||||||
@Override
|
@Override
|
||||||
public List<AbstractActivity> createActivities(Job job) {
|
public List<AbstractActivity> createActivities(Job job) {
|
||||||
|
|
@ -341,23 +348,23 @@ public class JobInsertionCostsCalculatorBuilder {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return new CalculatorPlusListeners(jobInsertionCalculator);
|
return new CalculatorPlusListeners(jobInsertionCalculator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JobInsertionCostsCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCostsCalculator baseCalc, RouteAndActivityStateGetter activityStates2){
|
private JobInsertionCostsCalculator createFinalInsertion(VehicleFleetManager fleetManager, JobInsertionCostsCalculator baseCalc, RouteAndActivityStateGetter activityStates2) {
|
||||||
VehicleTypeDependentJobInsertionCalculator vehicleTypeDependentJobInsertionCalculator = new VehicleTypeDependentJobInsertionCalculator(vrp, fleetManager, baseCalc);
|
VehicleTypeDependentJobInsertionCalculator vehicleTypeDependentJobInsertionCalculator = new VehicleTypeDependentJobInsertionCalculator(vrp, fleetManager, baseCalc);
|
||||||
vehicleTypeDependentJobInsertionCalculator.setVehicleSwitchAllowed(allowVehicleSwitch);
|
vehicleTypeDependentJobInsertionCalculator.setVehicleSwitchAllowed(allowVehicleSwitch);
|
||||||
return vehicleTypeDependentJobInsertionCalculator;
|
return vehicleTypeDependentJobInsertionCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobInsertionCostsCalculatorBuilder setConstraintManager(ConstraintManager constraintManager) {
|
public JobInsertionCostsCalculatorBuilder setConstraintManager(ConstraintManager constraintManager) {
|
||||||
this.constraintManager = constraintManager;
|
this.constraintManager = constraintManager;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobInsertionCostsCalculatorBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) {
|
public JobInsertionCostsCalculatorBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) {
|
||||||
this.allowVehicleSwitch = allowVehicleSwitch;
|
this.allowVehicleSwitch = allowVehicleSwitch;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,6 @@ import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
|
|
||||||
public interface JobInsertionCostsCalculatorLight {
|
public interface JobInsertionCostsCalculatorLight {
|
||||||
|
|
||||||
public InsertionData getInsertionData(Job unassignedJob, VehicleRoute route, double bestKnownCosts);
|
public InsertionData getInsertionData(Job unassignedJob, VehicleRoute route, double bestKnownCosts);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,23 +38,23 @@ public class JobInsertionCostsCalculatorLightFactory {
|
||||||
* Returns standard insertion calculator, i.e. the calculator that identifies best insertion positions for the
|
* Returns standard insertion calculator, i.e. the calculator that identifies best insertion positions for the
|
||||||
* jobs to be inserted. The position basically consists of the route and the according indices.
|
* jobs to be inserted. The position basically consists of the route and the according indices.
|
||||||
*
|
*
|
||||||
* @param vrp vehicle routing problem
|
* @param vrp vehicle routing problem
|
||||||
* @param fleetManager fleet manager
|
* @param fleetManager fleet manager
|
||||||
* @param stateManager state manager
|
* @param stateManager state manager
|
||||||
* @param constraintManager constraint manager
|
* @param constraintManager constraint manager
|
||||||
* @return insertion calculator
|
* @return insertion calculator
|
||||||
*/
|
*/
|
||||||
public static JobInsertionCostsCalculatorLight createStandardCalculator(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager){
|
public static JobInsertionCostsCalculatorLight createStandardCalculator(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) {
|
||||||
List<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener> al = new ArrayList<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener>();
|
List<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener> al = new ArrayList<VehicleRoutingAlgorithmListeners.PrioritizedVRAListener>();
|
||||||
List<InsertionListener> il = new ArrayList<InsertionListener>();
|
List<InsertionListener> il = new ArrayList<InsertionListener>();
|
||||||
JobInsertionCostsCalculatorBuilder builder = new JobInsertionCostsCalculatorBuilder(il,al);
|
JobInsertionCostsCalculatorBuilder builder = new JobInsertionCostsCalculatorBuilder(il, al);
|
||||||
builder.setVehicleRoutingProblem(vrp).setConstraintManager(constraintManager).setStateManager(stateManager).setVehicleFleetManager(fleetManager);
|
builder.setVehicleRoutingProblem(vrp).setConstraintManager(constraintManager).setStateManager(stateManager).setVehicleFleetManager(fleetManager);
|
||||||
final JobInsertionCostsCalculator calculator = builder.build();
|
final JobInsertionCostsCalculator calculator = builder.build();
|
||||||
return new JobInsertionCostsCalculatorLight() {
|
return new JobInsertionCostsCalculatorLight() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InsertionData getInsertionData(Job unassignedJob, VehicleRoute route, double bestKnownCosts) {
|
public InsertionData getInsertionData(Job unassignedJob, VehicleRoute route, double bestKnownCosts) {
|
||||||
return calculator.getInsertionData(route,unassignedJob,AbstractInsertionStrategy.NO_NEW_VEHICLE_YET,AbstractInsertionStrategy.NO_NEW_DEPARTURE_TIME_YET,AbstractInsertionStrategy.NO_NEW_DRIVER_YET,bestKnownCosts);
|
return calculator.getInsertionData(route, unassignedJob, AbstractInsertionStrategy.NO_NEW_VEHICLE_YET, AbstractInsertionStrategy.NO_NEW_DEPARTURE_TIME_YET, AbstractInsertionStrategy.NO_NEW_DRIVER_YET, bestKnownCosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (C) 2014 Stefan Schroeder
|
* Copyright (C) 2014 Stefan Schroeder
|
||||||
*
|
*
|
||||||
|
|
@ -18,72 +17,94 @@
|
||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts activityCosts;
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private double activityCostsWeight = 1.;
|
||||||
|
|
||||||
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts) {
|
private double solutionCompletenessRatio = 1.;
|
||||||
super();
|
|
||||||
this.routingCosts = routingCosts;
|
|
||||||
this.activityCosts = actCosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
private RouteAndActivityStateGetter stateManager;
|
||||||
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
|
|
||||||
|
|
||||||
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
public LocalActivityInsertionCostsCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) {
|
||||||
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
super();
|
||||||
double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
|
this.routingCosts = routingCosts;
|
||||||
double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct);
|
this.activityCosts = actCosts;
|
||||||
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
//open routes
|
@Override
|
||||||
if(nextAct instanceof End){
|
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
|
||||||
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_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
double tp_time_newAct_nextAct = routingCosts.getTransportTime(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
|
double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
|
||||||
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct);
|
||||||
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + act_costs_newAct + act_costs_nextAct;
|
|
||||||
|
|
||||||
double oldCosts;
|
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
if(iFacts.getRoute().isEmpty()){
|
|
||||||
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());
|
|
||||||
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
|
||||||
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 arrTime_nextAct = routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), 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;
|
|
||||||
}
|
|
||||||
return totalCosts - oldCosts;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isEnd(nextAct) && !toDepot(iFacts.getNewVehicle())) return tp_costs_prevAct_newAct;
|
||||||
|
|
||||||
|
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 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 totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + solutionCompletenessRatio * activityCostsWeight * (act_costs_newAct + act_costs_nextAct);
|
||||||
|
|
||||||
|
double oldCosts = 0.;
|
||||||
|
if (iFacts.getRoute().isEmpty()) {
|
||||||
|
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
|
oldCosts += tp_costs_prevAct_nextAct;
|
||||||
|
} else {
|
||||||
|
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,15 @@
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
package jsprit.core.algorithm.recreate;
|
package jsprit.core.algorithm.recreate;
|
||||||
|
|
||||||
public class NoSolutionFoundException extends IllegalStateException{
|
public class NoSolutionFoundException extends IllegalStateException {
|
||||||
|
|
||||||
public NoSolutionFoundException(String errorMsg) {
|
public NoSolutionFoundException(String errorMsg) {
|
||||||
super(errorMsg);
|
super(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,224 +17,106 @@
|
||||||
|
|
||||||
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() {
|
private ScoringFunction scoringFunction;
|
||||||
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 JobInsertionCostsCalculator insertionCostsCalculator;
|
private JobInsertionCostsCalculator insertionCostsCalculator;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
public void setScoringFunction(ScoringFunction scoringFunction) {
|
public void setScoringFunction(ScoringFunction scoringFunction) {
|
||||||
this.scoringFunction = scoringFunction;
|
this.scoringFunction = scoringFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
|
public RegretInsertion(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem) {
|
||||||
super(vehicleRoutingProblem);
|
super(vehicleRoutingProblem);
|
||||||
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
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=regretInsertion][additionalScorer="+scoringFunction+"]";
|
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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>();
|
||||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||||
if(bestScoredJob != null){
|
if (bestScoredJob != null) {
|
||||||
if(bestScoredJob.isNewRoute()){
|
if (bestScoredJob.isNewRoute()) {
|
||||||
routes.add(bestScoredJob.getRoute());
|
routes.add(bestScoredJob.getRoute());
|
||||||
}
|
}
|
||||||
insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(),bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
}
|
}
|
||||||
for(Job bad : badJobList) {
|
for (Job bad : badJobList) {
|
||||||
jobs.remove(bad);
|
jobs.remove(bad);
|
||||||
badJobs.add(bad);
|
badJobs.add(bad);
|
||||||
}
|
}
|
||||||
|
|
@ -242,18 +124,29 @@ 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;
|
||||||
}
|
}
|
||||||
if(bestScoredJob == null) bestScoredJob = scoredJob;
|
if (bestScoredJob == null) bestScoredJob = scoredJob;
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -298,31 +191,29 @@ public class RegretInsertion extends AbstractInsertionStrategy {
|
||||||
secondBest = iData;
|
secondBest = iData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
|
static double score(Job unassignedJob, InsertionData best, InsertionData secondBest, ScoringFunction scoringFunction) {
|
||||||
if(best == null){
|
if (best == null) {
|
||||||
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
|
throw new IllegalStateException("cannot insert job " + unassignedJob.getId());
|
||||||
}
|
}
|
||||||
double score;
|
double score;
|
||||||
if(secondBest == null){ //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob
|
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 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,80 +26,101 @@ 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;
|
||||||
|
|
||||||
private final JobInsertionCostsCalculator insertionCostsCalculator;
|
private final JobInsertionCostsCalculator insertionCostsCalculator;
|
||||||
|
|
||||||
private final ExecutorCompletionService<ScoredJob> completionService;
|
private final ExecutorCompletionService<ScoredJob> completionService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
public void setScoringFunction(ScoringFunction scoringFunction) {
|
public void setScoringFunction(ScoringFunction scoringFunction) {
|
||||||
this.scoringFunction = scoringFunction;
|
this.scoringFunction = scoringFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService) {
|
public RegretInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, VehicleRoutingProblem vehicleRoutingProblem, ExecutorService executorService) {
|
||||||
super(vehicleRoutingProblem);
|
super(vehicleRoutingProblem);
|
||||||
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
|
||||||
this.insertionCostsCalculator = jobInsertionCalculator;
|
this.insertionCostsCalculator = jobInsertionCalculator;
|
||||||
this.vrp = vehicleRoutingProblem;
|
this.vrp = vehicleRoutingProblem;
|
||||||
completionService = new ExecutorCompletionService<ScoredJob>(executorService);
|
completionService = new ExecutorCompletionService<ScoredJob>(executorService);
|
||||||
logger.debug("initialise " + this);
|
logger.debug("initialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=regretInsertion][additionalScorer="+scoringFunction+"]";
|
return "[name=regretInsertion][additionalScorer=" + scoringFunction + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
*/
|
||||||
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
@Override
|
||||||
|
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>();
|
||||||
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList);
|
||||||
if(bestScoredJob != null){
|
if (bestScoredJob != null) {
|
||||||
if(bestScoredJob.isNewRoute()){
|
if (bestScoredJob.isNewRoute()) {
|
||||||
routes.add(bestScoredJob.getRoute());
|
routes.add(bestScoredJob.getRoute());
|
||||||
}
|
}
|
||||||
insertJob(bestScoredJob.getJob(),bestScoredJob.getInsertionData(),bestScoredJob.getRoute());
|
insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute());
|
||||||
jobs.remove(bestScoredJob.getJob());
|
jobs.remove(bestScoredJob.getJob());
|
||||||
}
|
}
|
||||||
for(Job j : badJobList) {
|
for (Job j : badJobList) {
|
||||||
jobs.remove(j);
|
jobs.remove(j);
|
||||||
badJobs.add(j);
|
badJobs.add(j);
|
||||||
}
|
}
|
||||||
|
|
@ -123,38 +142,39 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try {
|
||||||
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;
|
bestScoredJob = sJob;
|
||||||
|
} else if (sJob.getScore() == bestScoredJob.getScore()) {
|
||||||
|
if (sJob.getJob().getId().compareTo(bestScoredJob.getJob().getId()) <= 0) {
|
||||||
|
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
|
||||||
*
|
*
|
||||||
|
|
@ -32,65 +31,68 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator{
|
class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator {
|
||||||
|
|
||||||
private VehicleRoutingActivityCosts activityCosts;
|
private VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
||||||
|
|
||||||
private RouteAndActivityStateGetter stateManager;
|
private RouteAndActivityStateGetter stateManager;
|
||||||
|
|
||||||
private int nuOfActivities2LookForward = 0;
|
private int nuOfActivities2LookForward = 0;
|
||||||
|
|
||||||
public RouteLevelActivityInsertionCostsEstimator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) {
|
public RouteLevelActivityInsertionCostsEstimator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) {
|
||||||
super();
|
super();
|
||||||
this.activityCosts = actCosts;
|
this.activityCosts = actCosts;
|
||||||
this.stateManager = stateManager;
|
this.stateManager = stateManager;
|
||||||
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(routingCosts, activityCosts);
|
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(routingCosts, activityCosts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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);
|
||||||
int actIndex;
|
path.add(newAct);
|
||||||
if(prevAct instanceof Start) actIndex = 0;
|
path.add(nextAct);
|
||||||
else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(nextAct);
|
int actIndex;
|
||||||
if(nuOfActivities2LookForward > 0 && !(nextAct instanceof End)){ path.addAll(getForwardLookingPath(iFacts.getRoute(),actIndex)); }
|
if (prevAct instanceof Start) actIndex = 0;
|
||||||
|
else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(nextAct);
|
||||||
|
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).
|
||||||
*/
|
*/
|
||||||
double forwardPathCost_newVehicle = auxilliaryPathCostCalculator.costOfPath(path, depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double forwardPathCost_newVehicle = auxilliaryPathCostCalculator.costOfPath(path, depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
||||||
return forwardPathCost_newVehicle - (actCostsOld(iFacts.getRoute(), path.get(path.size()-1)) - actCostsOld(iFacts.getRoute(), prevAct));
|
return forwardPathCost_newVehicle - (actCostsOld(iFacts.getRoute(), path.get(path.size() - 1)) - actCostsOld(iFacts.getRoute(), prevAct));
|
||||||
}
|
}
|
||||||
|
|
||||||
private double actCostsOld(VehicleRoute vehicleRoute, TourActivity act) {
|
private double actCostsOld(VehicleRoute vehicleRoute, TourActivity act) {
|
||||||
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.;
|
||||||
return cost_at_act;
|
return cost_at_act;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<TourActivity> getForwardLookingPath(VehicleRoute route, int actIndex) {
|
private List<TourActivity> getForwardLookingPath(VehicleRoute route, int actIndex) {
|
||||||
List<TourActivity> forwardLookingPath = new ArrayList<TourActivity>();
|
List<TourActivity> forwardLookingPath = new ArrayList<TourActivity>();
|
||||||
int nuOfActsInPath = 0;
|
int nuOfActsInPath = 0;
|
||||||
int index = actIndex + 1;
|
int index = actIndex + 1;
|
||||||
while(index < route.getTourActivities().getActivities().size() && nuOfActsInPath < nuOfActivities2LookForward){
|
while (index < route.getTourActivities().getActivities().size() && nuOfActsInPath < nuOfActivities2LookForward) {
|
||||||
forwardLookingPath.add(route.getTourActivities().getActivities().get(index));
|
forwardLookingPath.add(route.getTourActivities().getActivities().get(index));
|
||||||
index++;
|
index++;
|
||||||
nuOfActsInPath++;
|
nuOfActsInPath++;
|
||||||
}
|
}
|
||||||
if(nuOfActsInPath < nuOfActivities2LookForward){
|
if (nuOfActsInPath < nuOfActivities2LookForward) {
|
||||||
forwardLookingPath.add(route.getEnd());
|
forwardLookingPath.add(route.getEnd());
|
||||||
}
|
}
|
||||||
return forwardLookingPath;
|
return forwardLookingPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForwardLooking(int nActivities) {
|
public void setForwardLooking(int nActivities) {
|
||||||
this.nuOfActivities2LookForward = nActivities;
|
this.nuOfActivities2LookForward = nActivities;
|
||||||
|
|
|
||||||
|
|
@ -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,76 +41,74 @@ 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 {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(ServiceInsertionCalculator.class);
|
private static final Logger logger = LogManager.getLogger(ServiceInsertionCalculator.class);
|
||||||
|
|
||||||
private HardRouteConstraint hardRouteLevelConstraint;
|
private HardRouteConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
private HardActivityConstraint hardActivityLevelConstraint;
|
private HardActivityConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
private SoftRouteConstraint softRouteConstraint;
|
private SoftRouteConstraint softRouteConstraint;
|
||||||
|
|
||||||
private SoftActivityConstraint softActivityConstraint;
|
private SoftActivityConstraint softActivityConstraint;
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts transportCosts;
|
private VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
|
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
|
||||||
|
|
||||||
private JobActivityFactory activityFactory;
|
private JobActivityFactory activityFactory;
|
||||||
|
|
||||||
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
||||||
|
|
||||||
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
|
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) {
|
||||||
super();
|
super();
|
||||||
this.transportCosts = routingCosts;
|
this.transportCosts = routingCosts;
|
||||||
hardRouteLevelConstraint = constraintManager;
|
hardRouteLevelConstraint = constraintManager;
|
||||||
hardActivityLevelConstraint = constraintManager;
|
hardActivityLevelConstraint = constraintManager;
|
||||||
softActivityConstraint = constraintManager;
|
softActivityConstraint = constraintManager;
|
||||||
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) {
|
||||||
this.activityFactory = jobActivityFactory;
|
this.activityFactory = jobActivityFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=calculatesServiceInsertion]";
|
return "[name=calculatesServiceInsertion]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
Service service = (Service) jobToInsert;
|
||||||
Service service = (Service)jobToInsert;
|
|
||||||
int insertionIndex = InsertionData.NO_INDEX;
|
int insertionIndex = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
TourActivity deliveryAct2Insert = activityFactory.createActivities(service).get(0);
|
TourActivity deliveryAct2Insert = activityFactory.createActivities(service).get(0);
|
||||||
insertionContext.getAssociatedActivities().add(deliveryAct2Insert);
|
insertionContext.getAssociatedActivities().add(deliveryAct2Insert);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check hard constraints at route level
|
check hard constraints at route level
|
||||||
*/
|
*/
|
||||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
||||||
return InsertionData.createEmptyInsertionData();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
check soft constraints at route level
|
check soft constraints at route level
|
||||||
*/
|
*/
|
||||||
double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext);
|
double additionalICostsAtRouteLevel = softRouteConstraint.getCosts(insertionContext);
|
||||||
|
|
||||||
double bestCost = bestKnownCosts;
|
double bestCost = bestKnownCosts;
|
||||||
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
|
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
|
||||||
TimeWindow bestTimeWindow = null;
|
TimeWindow bestTimeWindow = null;
|
||||||
|
|
||||||
|
|
@ -118,70 +116,70 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
generate new start and end for new vehicle
|
generate new start and end for new vehicle
|
||||||
*/
|
*/
|
||||||
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
|
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
|
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
TourActivity prevAct = start;
|
||||||
double prevActStartTime = newVehicleDepartureTime;
|
double prevActStartTime = newVehicleDepartureTime;
|
||||||
int actIndex = 0;
|
int actIndex = 0;
|
||||||
Iterator<TourActivity> activityIterator = currentRoute.getActivities().iterator();
|
Iterator<TourActivity> activityIterator = currentRoute.getActivities().iterator();
|
||||||
boolean tourEnd = false;
|
boolean tourEnd = false;
|
||||||
while(!tourEnd){
|
while(!tourEnd){
|
||||||
TourActivity nextAct;
|
TourActivity nextAct;
|
||||||
if(activityIterator.hasNext()) nextAct = activityIterator.next();
|
if(activityIterator.hasNext()) nextAct = activityIterator.next();
|
||||||
else{
|
else{
|
||||||
nextAct = end;
|
nextAct = end;
|
||||||
tourEnd = true;
|
tourEnd = true;
|
||||||
}
|
}
|
||||||
double actArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(),deliveryAct2Insert.getLocation(),prevActStartTime,newDriver,newVehicle);
|
double actArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(),deliveryAct2Insert.getLocation(),prevActStartTime,newDriver,newVehicle);
|
||||||
Collection<TimeWindow> timeWindows = service.getTimeWindows(actArrTime);
|
Collection<TimeWindow> timeWindows = service.getTimeWindows(actArrTime);
|
||||||
TimeWindow timeWindow = getNextTimeWindow(actArrTime,timeWindows);
|
TimeWindow timeWindow = getNextTimeWindow(actArrTime,timeWindows);
|
||||||
if(timeWindow == null) break;
|
if(timeWindow == null) break;
|
||||||
boolean not_fulfilled_break = true;
|
boolean not_fulfilled_break = true;
|
||||||
// for(TimeWindow timeWindow : timeWindows) {
|
// for(TimeWindow timeWindow : timeWindows) {
|
||||||
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(timeWindow.getStart());
|
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(timeWindow.getStart());
|
||||||
deliveryAct2Insert.setTheoreticalLatestOperationStartTime(timeWindow.getEnd());
|
deliveryAct2Insert.setTheoreticalLatestOperationStartTime(timeWindow.getEnd());
|
||||||
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||||
if (status.equals(ConstraintsStatus.FULFILLED)) {
|
if (status.equals(ConstraintsStatus.FULFILLED)) {
|
||||||
//from job2insert induced costs at activity level
|
//from job2insert induced costs at activity level
|
||||||
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime);
|
||||||
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime);
|
||||||
if (additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost) {
|
if (additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts < bestCost) {
|
||||||
bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts;
|
bestCost = additionalICostsAtRouteLevel + additionalICostsAtActLevel + additionalTransportationCosts;
|
||||||
insertionIndex = actIndex;
|
insertionIndex = actIndex;
|
||||||
bestTimeWindow = timeWindow;
|
bestTimeWindow = timeWindow;
|
||||||
}
|
}
|
||||||
not_fulfilled_break = false;
|
not_fulfilled_break = false;
|
||||||
} else if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
} else if (status.equals(ConstraintsStatus.NOT_FULFILLED)) {
|
||||||
not_fulfilled_break = false;
|
not_fulfilled_break = false;
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
if(not_fulfilled_break) break;
|
if(not_fulfilled_break) break;
|
||||||
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle);
|
double nextActArrTime = prevActStartTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActStartTime, newDriver, newVehicle);
|
||||||
prevActStartTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
prevActStartTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
||||||
prevAct = nextAct;
|
prevAct = nextAct;
|
||||||
actIndex++;
|
actIndex++;
|
||||||
}
|
}
|
||||||
if(insertionIndex == InsertionData.NO_INDEX) {
|
if(insertionIndex == InsertionData.NO_INDEX) {
|
||||||
return InsertionData.createEmptyInsertionData();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver);
|
||||||
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
|
deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart());
|
||||||
deliveryAct2Insert.setTheoreticalLatestOperationStartTime(bestTimeWindow.getEnd());
|
deliveryAct2Insert.setTheoreticalLatestOperationStartTime(bestTimeWindow.getEnd());
|
||||||
insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,deliveryAct2Insert,insertionIndex));
|
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, deliveryAct2Insert, insertionIndex));
|
||||||
insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime));
|
insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime));
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimeWindow getNextTimeWindow(double actArrTime, Collection<TimeWindow> timeWindows) {
|
private TimeWindow getNextTimeWindow(double actArrTime, Collection<TimeWindow> timeWindows) {
|
||||||
for(TimeWindow tw : timeWindows){
|
for(TimeWindow tw : timeWindows){
|
||||||
if(actArrTime >= tw.getStart() && actArrTime <= tw.getEnd()) return tw;
|
if(actArrTime >= tw.getStart() && actArrTime <= tw.getEnd()) return tw;
|
||||||
else if(actArrTime < tw.getStart()){
|
else if(actArrTime < tw.getStart()){
|
||||||
return tw;
|
return tw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,127 +45,125 @@ import java.util.List;
|
||||||
import java.util.PriorityQueue;
|
import java.util.PriorityQueue;
|
||||||
|
|
||||||
|
|
||||||
|
final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(ServiceInsertionOnRouteLevelCalculator.class);
|
||||||
|
|
||||||
|
private final VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
|
private final VehicleRoutingActivityCosts activityCosts;
|
||||||
|
|
||||||
|
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
||||||
|
|
||||||
|
private JobActivityFactory activityFactory;
|
||||||
|
|
||||||
|
private RouteAndActivityStateGetter stateManager;
|
||||||
|
|
||||||
|
private HardRouteConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
|
private HardActivityConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
|
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
|
||||||
|
|
||||||
|
private int nuOfActsForwardLooking = 0;
|
||||||
|
//
|
||||||
|
private int memorySize = 2;
|
||||||
|
|
||||||
|
private Start start;
|
||||||
|
|
||||||
|
private End end;
|
||||||
|
|
||||||
|
public void setJobActivityFactory(JobActivityFactory jobActivityFactory) {
|
||||||
|
this.activityFactory = jobActivityFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMemorySize(int memorySize) {
|
||||||
|
this.memorySize = memorySize;
|
||||||
|
logger.debug("set [solutionMemory={}]", memorySize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceInsertionOnRouteLevelCalculator(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteConstraint hardRouteLevelConstraint, HardActivityConstraint hardActivityLevelConstraint) {
|
||||||
|
super();
|
||||||
|
this.transportCosts = vehicleRoutingCosts;
|
||||||
|
this.activityCosts = costFunc;
|
||||||
|
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
|
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
||||||
|
this.hardActivityLevelConstraint = hardActivityLevelConstraint;
|
||||||
|
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts);
|
||||||
|
logger.debug("initialise {}", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator{
|
public void setStates(RouteAndActivityStateGetter stateManager) {
|
||||||
|
this.stateManager = stateManager;
|
||||||
|
}
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(ServiceInsertionOnRouteLevelCalculator.class);
|
void setNuOfActsForwardLooking(int nOfActsForwardLooking) {
|
||||||
|
this.nuOfActsForwardLooking = nOfActsForwardLooking;
|
||||||
|
logger.debug("set [forwardLooking={}]", nOfActsForwardLooking);
|
||||||
|
}
|
||||||
|
|
||||||
private final VehicleRoutingTransportCosts transportCosts;
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[name=calculatesServiceInsertionOnRouteLevel][solutionMemory=" + memorySize + "][forwardLooking=" + nuOfActsForwardLooking + "]";
|
||||||
|
}
|
||||||
|
|
||||||
private final VehicleRoutingActivityCosts activityCosts;
|
/**
|
||||||
|
* Calculates the insertion costs of job i on route level (which is based on the assumption that inserting job i does not only
|
||||||
|
* 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
|
||||||
|
* marginal insertion cost. In the second step, marginal cost of the best M positions are calculated exactly.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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 (newVehicle == null || newVehicle instanceof NoVehicle)
|
||||||
|
throw new IllegalStateException("no vehicle given. set para vehicle!");
|
||||||
|
|
||||||
private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
|
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
|
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
||||||
|
return InsertionData.createEmptyInsertionData();
|
||||||
|
}
|
||||||
|
|
||||||
private JobActivityFactory activityFactory;
|
/**
|
||||||
|
* map that memorizes the costs with newVehicle, which is a cost-snapshot at tour-activities.
|
||||||
private RouteAndActivityStateGetter stateManager;
|
*/
|
||||||
|
|
||||||
private HardRouteConstraint hardRouteLevelConstraint;
|
|
||||||
|
|
||||||
private HardActivityConstraint hardActivityLevelConstraint;
|
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
|
|
||||||
|
|
||||||
private int nuOfActsForwardLooking = 0;
|
|
||||||
//
|
|
||||||
private int memorySize = 2;
|
|
||||||
|
|
||||||
private Start start;
|
|
||||||
|
|
||||||
private End end;
|
|
||||||
|
|
||||||
public void setJobActivityFactory(JobActivityFactory jobActivityFactory){
|
|
||||||
this.activityFactory=jobActivityFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMemorySize(int memorySize) {
|
|
||||||
this.memorySize = memorySize;
|
|
||||||
logger.debug("set [solutionMemory="+memorySize+"]");
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServiceInsertionOnRouteLevelCalculator(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteConstraint hardRouteLevelConstraint, HardActivityConstraint hardActivityLevelConstraint) {
|
|
||||||
super();
|
|
||||||
this.transportCosts = vehicleRoutingCosts;
|
|
||||||
this.activityCosts = costFunc;
|
|
||||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
|
||||||
this.hardRouteLevelConstraint = hardRouteLevelConstraint;
|
|
||||||
this.hardActivityLevelConstraint = hardActivityLevelConstraint;
|
|
||||||
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(transportCosts, activityCosts);
|
|
||||||
logger.debug("initialise " + this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setStates(RouteAndActivityStateGetter stateManager){
|
|
||||||
this.stateManager = stateManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setNuOfActsForwardLooking(int nOfActsForwardLooking) {
|
|
||||||
this.nuOfActsForwardLooking = nOfActsForwardLooking;
|
|
||||||
logger.debug("set [forwardLooking="+nOfActsForwardLooking+"]");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[name=calculatesServiceInsertionOnRouteLevel][solutionMemory="+memorySize+"][forwardLooking="+nuOfActsForwardLooking+"]";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the insertion costs of job i on route level (which is based on the assumption that inserting job i does not only
|
|
||||||
* 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
|
|
||||||
* marginal insertion cost. In the second step, marginal cost of the best M positions are calculated exactly.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
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(newVehicle == null || newVehicle instanceof NoVehicle) throw new IllegalStateException("no vehicle given. set para vehicle!");
|
|
||||||
|
|
||||||
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
|
||||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
|
||||||
return InsertionData.createEmptyInsertionData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* map that memorizes the costs with newVehicle, which is a cost-snapshot at tour-activities.
|
|
||||||
*/
|
|
||||||
// Map<TourActivity,Double> activity2costWithNewVehicle = new HashMap<TourActivity,Double>();
|
// Map<TourActivity,Double> activity2costWithNewVehicle = new HashMap<TourActivity,Double>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* priority queue that stores insertion-data by insertion-costs in ascending order.
|
* priority queue that stores insertion-data by insertion-costs in ascending order.
|
||||||
*/
|
*/
|
||||||
PriorityQueue<InsertionData> bestInsertionsQueue = new PriorityQueue<InsertionData>(Math.max(2, currentRoute.getTourActivities().getActivities().size()), getComparator());
|
PriorityQueue<InsertionData> bestInsertionsQueue = new PriorityQueue<InsertionData>(Math.max(2, currentRoute.getTourActivities().getActivities().size()), getComparator());
|
||||||
|
|
||||||
TourActivities tour = currentRoute.getTourActivities();
|
TourActivities tour = currentRoute.getTourActivities();
|
||||||
double best_insertion_costs = best_known_insertion_costs;
|
double best_insertion_costs = best_known_insertion_costs;
|
||||||
Service service = (Service)jobToInsert;
|
Service service = (Service) jobToInsert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* some inis
|
* some inis
|
||||||
*/
|
*/
|
||||||
TourActivity serviceAct2Insert = activityFactory.createActivities(service).get(0);
|
TourActivity serviceAct2Insert = activityFactory.createActivities(service).get(0);
|
||||||
int best_insertion_index = InsertionData.NO_INDEX;
|
int best_insertion_index = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
TourActivity prevAct = start;
|
||||||
int actIndex = 0;
|
int actIndex = 0;
|
||||||
double sumOf_prevCosts_newVehicle = 0.0;
|
double sumOf_prevCosts_newVehicle = 0.0;
|
||||||
double prevActDepTime_newVehicle = start.getEndTime();
|
double prevActDepTime_newVehicle = start.getEndTime();
|
||||||
|
|
||||||
boolean loopBroken = false;
|
boolean loopBroken = false;
|
||||||
/**
|
/**
|
||||||
* inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1}
|
* inserting serviceAct2Insert in route r={0,1,...,i-1,i,j,j+1,...,n(r),n(r)+1}
|
||||||
* i=prevAct
|
* i=prevAct
|
||||||
* j=nextAct
|
* j=nextAct
|
||||||
* k=serviceAct2Insert
|
* k=serviceAct2Insert
|
||||||
*/
|
*/
|
||||||
for(TourActivity nextAct : tour.getActivities()){
|
for (TourActivity nextAct : tour.getActivities()) {
|
||||||
ConstraintsStatus hardActivityConstraintsStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle);
|
ConstraintsStatus hardActivityConstraintsStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle);
|
||||||
if(hardActivityConstraintsStatus.equals(ConstraintsStatus.FULFILLED)){
|
if (hardActivityConstraintsStatus.equals(ConstraintsStatus.FULFILLED)) {
|
||||||
/**
|
/**
|
||||||
* builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking}
|
* builds a path on this route forwardPath={i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking}
|
||||||
*/
|
*/
|
||||||
|
|
@ -174,16 +172,15 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
|
||||||
/**
|
/**
|
||||||
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
||||||
*/
|
*/
|
||||||
double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute,prevAct) + actInsertionCosts;
|
double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute, prevAct) + actInsertionCosts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memorize it in insertion-queue
|
* memorize it in insertion-queue
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
@ -192,148 +189,143 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
|
||||||
/**
|
/**
|
||||||
* calculate transport and activity costs with new vehicle (without inserting k)
|
* calculate transport and activity costs with new vehicle (without inserting k)
|
||||||
*/
|
*/
|
||||||
double transportCost_prevAct_nextAct_newVehicle = transportCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime_newVehicle, newDriver, newVehicle);
|
double transportCost_prevAct_nextAct_newVehicle = transportCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime_newVehicle, newDriver, newVehicle);
|
||||||
double transportTime_prevAct_nextAct_newVehicle = transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime_newVehicle, newDriver, newVehicle);
|
double transportTime_prevAct_nextAct_newVehicle = transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime_newVehicle, newDriver, newVehicle);
|
||||||
double arrTime_nextAct_newVehicle = prevActDepTime_newVehicle + transportTime_prevAct_nextAct_newVehicle;
|
double arrTime_nextAct_newVehicle = prevActDepTime_newVehicle + transportTime_prevAct_nextAct_newVehicle;
|
||||||
double activityCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct_newVehicle, newDriver, newVehicle);
|
double activityCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct_newVehicle, newDriver, newVehicle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memorize transport and activity costs with new vehicle without inserting k
|
* memorize transport and activity costs with new vehicle without inserting k
|
||||||
*/
|
*/
|
||||||
sumOf_prevCosts_newVehicle += transportCost_prevAct_nextAct_newVehicle + activityCost_nextAct;
|
sumOf_prevCosts_newVehicle += transportCost_prevAct_nextAct_newVehicle + activityCost_nextAct;
|
||||||
// activity2costWithNewVehicle.put(nextAct, sumOf_prevCosts_newVehicle);
|
// activity2costWithNewVehicle.put(nextAct, sumOf_prevCosts_newVehicle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* departure time at nextAct with new vehicle
|
* departure time at nextAct with new vehicle
|
||||||
*/
|
*/
|
||||||
double depTime_nextAct_newVehicle = Math.max(arrTime_nextAct_newVehicle, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime();
|
double depTime_nextAct_newVehicle = Math.max(arrTime_nextAct_newVehicle, nextAct.getTheoreticalEarliestOperationStartTime()) + nextAct.getOperationTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set previous to next
|
* set previous to next
|
||||||
*/
|
*/
|
||||||
prevAct = nextAct;
|
prevAct = nextAct;
|
||||||
prevActDepTime_newVehicle = depTime_nextAct_newVehicle;
|
prevActDepTime_newVehicle = depTime_nextAct_newVehicle;
|
||||||
|
|
||||||
actIndex++;
|
actIndex++;
|
||||||
}
|
}
|
||||||
if(!loopBroken){
|
if (!loopBroken) {
|
||||||
End nextAct = end;
|
End nextAct = end;
|
||||||
ConstraintsStatus hardActivityConstraintsStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle);
|
ConstraintsStatus hardActivityConstraintsStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, serviceAct2Insert, nextAct, prevActDepTime_newVehicle);
|
||||||
if(hardActivityConstraintsStatus.equals(ConstraintsStatus.FULFILLED)){
|
if (hardActivityConstraintsStatus.equals(ConstraintsStatus.FULFILLED)) {
|
||||||
double actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
|
double actInsertionCosts = activityInsertionCostsCalculator.getCosts(insertionContext, prevAct, nextAct, serviceAct2Insert, prevActDepTime_newVehicle);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
* insertion_cost_approximation = c({0,1,...,i},newVehicle) + c({i,k,j,j+1,j+2,...,j+nuOfActsForwardLooking},newVehicle) - c({0,1,...,i,j,j+1,...,j+nuOfActsForwardLooking},oldVehicle)
|
||||||
*/
|
*/
|
||||||
double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute,prevAct) + actInsertionCosts;
|
double insertion_cost_approximation = sumOf_prevCosts_newVehicle - sumOf_prevCosts_oldVehicle(currentRoute, prevAct) + actInsertionCosts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* memorize it in insertion-queue
|
* memorize it in insertion-queue
|
||||||
*/
|
*/
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the above calculations approximate insertion costs. now calculate the exact insertion costs for the most promising (according to the approximation)
|
* the above calculations approximate insertion costs. now calculate the exact insertion costs for the most promising (according to the approximation)
|
||||||
* insertion positions.
|
* insertion positions.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(memorySize==0){ // return bestInsertion
|
if (memorySize == 0) { // return bestInsertion
|
||||||
InsertionData insertion = bestInsertionsQueue.poll();
|
InsertionData insertion = bestInsertionsQueue.poll();
|
||||||
if(insertion != null){
|
if (insertion != null) {
|
||||||
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();
|
||||||
if(data == null){
|
if (data == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* build tour with new activity.
|
* build tour with new activity.
|
||||||
*/
|
*/
|
||||||
List<TourActivity> wholeTour = new ArrayList<TourActivity>();
|
List<TourActivity> wholeTour = new ArrayList<TourActivity>();
|
||||||
wholeTour.add(start);
|
wholeTour.add(start);
|
||||||
wholeTour.addAll(currentRoute.getTourActivities().getActivities());
|
wholeTour.addAll(currentRoute.getTourActivities().getActivities());
|
||||||
wholeTour.add(end);
|
wholeTour.add(end);
|
||||||
wholeTour.add(data.getDeliveryInsertionIndex()+1, serviceAct2Insert);
|
wholeTour.add(data.getDeliveryInsertionIndex() + 1, serviceAct2Insert);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* compute cost-diff of tour with and without new activity --> insertion_costs
|
* compute cost-diff of tour with and without new activity --> insertion_costs
|
||||||
*/
|
*/
|
||||||
Double currentRouteCosts = stateManager.getRouteState(currentRoute, InternalStates.COSTS, Double.class);
|
Double currentRouteCosts = stateManager.getRouteState(currentRoute, InternalStates.COSTS, Double.class);
|
||||||
if(currentRouteCosts == null) currentRouteCosts = 0.;
|
if (currentRouteCosts == null) currentRouteCosts = 0.;
|
||||||
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - currentRouteCosts;
|
double insertion_costs = auxilliaryPathCostCalculator.costOfPath(wholeTour, start.getEndTime(), newDriver, newVehicle) - currentRouteCosts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if better than best known, make it the best known
|
* if better than best known, make it the best known
|
||||||
*/
|
*/
|
||||||
if(insertion_costs < best_insertion_costs){
|
if (insertion_costs < best_insertion_costs) {
|
||||||
best_insertion_index = data.getDeliveryInsertionIndex();
|
best_insertion_index = data.getDeliveryInsertionIndex();
|
||||||
best_insertion_costs = insertion_costs;
|
best_insertion_costs = insertion_costs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(best_insertion_index == InsertionData.NO_INDEX) return InsertionData.createEmptyInsertionData();
|
if (best_insertion_index == InsertionData.NO_INDEX) return InsertionData.createEmptyInsertionData();
|
||||||
InsertionData insertionData = new InsertionData(best_insertion_costs, InsertionData.NO_INDEX, best_insertion_index, newVehicle, newDriver);
|
InsertionData insertionData = new InsertionData(best_insertion_costs, InsertionData.NO_INDEX, best_insertion_index, newVehicle, newDriver);
|
||||||
insertionData.setVehicleDepartureTime(start.getEndTime());
|
insertionData.setVehicleDepartureTime(start.getEndTime());
|
||||||
return insertionData;
|
return insertionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) {
|
private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) {
|
||||||
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);
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private double sumOf_prevCosts_oldVehicle(VehicleRoute vehicleRoute, TourActivity act) {
|
private double sumOf_prevCosts_oldVehicle(VehicleRoute vehicleRoute, TourActivity act) {
|
||||||
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;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private Comparator<InsertionData> getComparator() {
|
private Comparator<InsertionData> getComparator() {
|
||||||
return new Comparator<InsertionData>() {
|
return new Comparator<InsertionData>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
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,58 +37,55 @@ import org.apache.logging.log4j.Logger;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
|
private static final Logger logger = LogManager.getLogger(ShipmentInsertionCalculator.class);
|
||||||
|
|
||||||
final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
private HardRouteConstraint hardRouteLevelConstraint;
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger(ShipmentInsertionCalculator.class);
|
private HardActivityConstraint hardActivityLevelConstraint;
|
||||||
|
|
||||||
private HardRouteConstraint hardRouteLevelConstraint;
|
private SoftRouteConstraint softRouteConstraint;
|
||||||
|
|
||||||
private HardActivityConstraint hardActivityLevelConstraint;
|
private SoftActivityConstraint softActivityConstraint;
|
||||||
|
|
||||||
private SoftRouteConstraint softRouteConstraint;
|
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
|
||||||
|
|
||||||
private SoftActivityConstraint softActivityConstraint;
|
private VehicleRoutingTransportCosts transportCosts;
|
||||||
|
|
||||||
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
|
private JobActivityFactory activityFactory;
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts transportCosts;
|
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
||||||
|
|
||||||
private JobActivityFactory activityFactory;
|
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
|
||||||
|
super();
|
||||||
|
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
||||||
|
this.hardRouteLevelConstraint = constraintManager;
|
||||||
|
this.hardActivityLevelConstraint = constraintManager;
|
||||||
|
this.softActivityConstraint = constraintManager;
|
||||||
|
this.softRouteConstraint = constraintManager;
|
||||||
|
this.transportCosts = routingCosts;
|
||||||
|
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
|
||||||
|
logger.debug("initialise {}", this);
|
||||||
|
}
|
||||||
|
|
||||||
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
|
public void setJobActivityFactory(JobActivityFactory activityFactory) {
|
||||||
|
|
||||||
public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) {
|
|
||||||
super();
|
|
||||||
this.activityInsertionCostsCalculator = activityInsertionCostsCalculator;
|
|
||||||
this.hardRouteLevelConstraint = constraintManager;
|
|
||||||
this.hardActivityLevelConstraint = constraintManager;
|
|
||||||
this.softActivityConstraint = constraintManager;
|
|
||||||
this.softRouteConstraint = constraintManager;
|
|
||||||
this.transportCosts = routingCosts;
|
|
||||||
additionalAccessEgressCalculator = new AdditionalAccessEgressCalculator(routingCosts);
|
|
||||||
logger.debug("initialise " + this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJobActivityFactory(JobActivityFactory activityFactory){
|
|
||||||
this.activityFactory = activityFactory;
|
this.activityFactory = activityFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=calculatesServiceInsertion]";
|
return "[name=calculatesServiceInsertion]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
|
||||||
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
|
||||||
Shipment shipment = (Shipment)jobToInsert;
|
Shipment shipment = (Shipment) jobToInsert;
|
||||||
TourActivity pickupShipment = activityFactory.createActivities(shipment).get(0);
|
TourActivity pickupShipment = activityFactory.createActivities(shipment).get(0);
|
||||||
TourActivity deliverShipment = activityFactory.createActivities(shipment).get(1);
|
TourActivity deliverShipment = activityFactory.createActivities(shipment).get(1);
|
||||||
insertionContext.getAssociatedActivities().add(pickupShipment);
|
insertionContext.getAssociatedActivities().add(pickupShipment);
|
||||||
|
|
@ -97,9 +94,9 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
/*
|
/*
|
||||||
check hard route constraints
|
check hard route constraints
|
||||||
*/
|
*/
|
||||||
if(!hardRouteLevelConstraint.fulfilled(insertionContext)){
|
if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
|
||||||
return InsertionData.createEmptyInsertionData();
|
return InsertionData.createEmptyInsertionData();
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
check soft route constraints
|
check soft route constraints
|
||||||
*/
|
*/
|
||||||
|
|
@ -109,51 +106,49 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
|
additionalICostsAtRouteLevel += additionalAccessEgressCalculator.getCosts(insertionContext);
|
||||||
|
|
||||||
int pickupInsertionIndex = InsertionData.NO_INDEX;
|
int pickupInsertionIndex = InsertionData.NO_INDEX;
|
||||||
int deliveryInsertionIndex = InsertionData.NO_INDEX;
|
int deliveryInsertionIndex = InsertionData.NO_INDEX;
|
||||||
|
|
||||||
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
Start start = new Start(newVehicle.getStartLocation(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
|
||||||
start.setEndTime(newVehicleDepartureTime);
|
start.setEndTime(newVehicleDepartureTime);
|
||||||
|
|
||||||
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
|
End end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
|
||||||
|
|
||||||
ActivityContext pickupContext = new ActivityContext();
|
ActivityContext pickupContext = new ActivityContext();
|
||||||
|
|
||||||
TourActivity prevAct = start;
|
TourActivity prevAct = start;
|
||||||
double prevActEndTime = newVehicleDepartureTime;
|
double prevActEndTime = newVehicleDepartureTime;
|
||||||
|
|
||||||
//loops
|
//loops
|
||||||
int i = 0;
|
int i = 0;
|
||||||
boolean tourEnd = false;
|
boolean tourEnd = false;
|
||||||
//pickupShipmentLoop
|
//pickupShipmentLoop
|
||||||
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
List<TourActivity> activities = currentRoute.getTourActivities().getActivities();
|
||||||
|
|
||||||
while(!tourEnd){
|
while (!tourEnd) {
|
||||||
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: {}, act-size: {}", i, activities.size());
|
||||||
// logger.info("activity: " + i + ", act-size: " + 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);
|
prevActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
||||||
prevActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
prevAct = nextAct;
|
||||||
prevAct = nextAct;
|
i++;
|
||||||
i++;
|
continue;
|
||||||
continue;
|
} else if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
|
||||||
}
|
break;
|
||||||
else if(pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){
|
}
|
||||||
break;
|
double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
|
||||||
}
|
double pickupAIC = calculate(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
|
||||||
double additionalPickupICosts = softActivityConstraint.getCosts(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime);
|
|
||||||
double pickupAIC = calculate(insertionContext,prevAct,pickupShipment, nextAct,prevActEndTime);
|
|
||||||
|
|
||||||
TourActivity prevAct_deliveryLoop = pickupShipment;
|
TourActivity prevAct_deliveryLoop = pickupShipment;
|
||||||
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), pickupShipment.getLocation(), prevActEndTime, newDriver, newVehicle);
|
double shipmentPickupArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), pickupShipment.getLocation(), prevActEndTime, newDriver, newVehicle);
|
||||||
double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
double shipmentPickupEndTime = CalculationUtils.getActivityEndTime(shipmentPickupArrTime, pickupShipment);
|
||||||
|
|
||||||
pickupContext.setArrivalTime(shipmentPickupArrTime);
|
pickupContext.setArrivalTime(shipmentPickupArrTime);
|
||||||
pickupContext.setEndTime(shipmentPickupEndTime);
|
pickupContext.setEndTime(shipmentPickupEndTime);
|
||||||
|
|
@ -163,63 +158,61 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
|
||||||
double prevActEndTime_deliveryLoop = shipmentPickupEndTime;
|
double prevActEndTime_deliveryLoop = shipmentPickupEndTime;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
--------------------------------
|
--------------------------------
|
||||||
*/
|
*/
|
||||||
//deliverShipmentLoop
|
//deliverShipmentLoop
|
||||||
int j = i;
|
int j = i;
|
||||||
boolean tourEnd_deliveryLoop = false;
|
boolean tourEnd_deliveryLoop = false;
|
||||||
while(!tourEnd_deliveryLoop){
|
while (!tourEnd_deliveryLoop) {
|
||||||
|
|
||||||
// for(int j=i;j<activities.size();j++){
|
// for(int j=i;j<activities.size();j++){
|
||||||
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;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||||
if(deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)){
|
if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) {
|
||||||
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||||
double deliveryAIC = calculate(insertionContext,prevAct_deliveryLoop,deliverShipment, nextAct_deliveryLoop,prevActEndTime_deliveryLoop);
|
double deliveryAIC = calculate(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop);
|
||||||
double totalActivityInsertionCosts = pickupAIC + deliveryAIC
|
double totalActivityInsertionCosts = pickupAIC + deliveryAIC
|
||||||
+ additionalICostsAtRouteLevel + additionalPickupICosts + additionalDeliveryICosts;
|
+ additionalICostsAtRouteLevel + additionalPickupICosts + additionalDeliveryICosts;
|
||||||
if(totalActivityInsertionCosts < bestCost){
|
if (totalActivityInsertionCosts < bestCost) {
|
||||||
bestCost = totalActivityInsertionCosts;
|
bestCost = totalActivityInsertionCosts;
|
||||||
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
|
double nextActArrTime = prevActEndTime_deliveryLoop + transportCosts.getTransportTime(prevAct_deliveryLoop.getLocation(), nextAct_deliveryLoop.getLocation(), prevActEndTime_deliveryLoop, newDriver, newVehicle);
|
||||||
double nextActArrTime = prevActEndTime_deliveryLoop + transportCosts.getTransportTime(prevAct_deliveryLoop.getLocation(), nextAct_deliveryLoop.getLocation(), prevActEndTime_deliveryLoop, newDriver, newVehicle);
|
prevActEndTime_deliveryLoop = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct_deliveryLoop);
|
||||||
prevActEndTime_deliveryLoop = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct_deliveryLoop);
|
prevAct_deliveryLoop = nextAct_deliveryLoop;
|
||||||
prevAct_deliveryLoop = nextAct_deliveryLoop;
|
j++;
|
||||||
j++;
|
}
|
||||||
}
|
//update prevAct and endTime
|
||||||
//update prevAct and endTime
|
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActEndTime, newDriver, newVehicle);
|
||||||
double nextActArrTime = prevActEndTime + transportCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevActEndTime, newDriver, newVehicle);
|
prevActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
||||||
prevActEndTime = CalculationUtils.getActivityEndTime(nextActArrTime, nextAct);
|
prevAct = nextAct;
|
||||||
prevAct = nextAct;
|
i++;
|
||||||
i++;
|
}
|
||||||
}
|
if (pickupInsertionIndex == InsertionData.NO_INDEX) {
|
||||||
if(pickupInsertionIndex == InsertionData.NO_INDEX) {
|
return InsertionData.createEmptyInsertionData();
|
||||||
return InsertionData.createEmptyInsertionData();
|
}
|
||||||
}
|
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
||||||
InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver);
|
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
||||||
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
|
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, deliverShipment, deliveryInsertionIndex));
|
||||||
insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,deliverShipment,deliveryInsertionIndex));
|
insertionData.getEvents().add(new InsertActivity(currentRoute, newVehicle, pickupShipment, pickupInsertionIndex));
|
||||||
insertionData.getEvents().add(new InsertActivity(currentRoute,newVehicle,pickupShipment,pickupInsertionIndex));
|
insertionData.getEvents().add(new SwitchVehicle(currentRoute, newVehicle, newVehicleDepartureTime));
|
||||||
insertionData.getEvents().add(new SwitchVehicle(currentRoute,newVehicle,newVehicleDepartureTime));
|
return insertionData;
|
||||||
return insertionData;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private double calculate(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
|
private double calculate(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double departureTimeAtPrevAct) {
|
||||||
return activityInsertionCostsCalculator.getCosts(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
return activityInsertionCostsCalculator.getCosts(iFacts, prevAct, nextAct, newAct, departureTimeAtPrevAct);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
switchVehicle.getRoute().setVehicleAndDepartureTime(switchVehicle.getVehicle(),((SwitchVehicle) event).getDepartureTime());
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean vehiclesDifferent(SwitchVehicle event) {
|
||||||
|
return !event.getRoute().getVehicle().getId().equals(event.getVehicle().getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,43 +23,42 @@ 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.util.CalculationUtils;
|
import jsprit.core.util.CalculationUtils;
|
||||||
|
|
||||||
public class VariableTransportCostCalculator implements SoftActivityConstraint{
|
public class VariableTransportCostCalculator implements SoftActivityConstraint {
|
||||||
|
|
||||||
private VehicleRoutingTransportCosts routingCosts;
|
private VehicleRoutingTransportCosts routingCosts;
|
||||||
|
|
||||||
public VariableTransportCostCalculator(VehicleRoutingTransportCosts routingCosts) {
|
public VariableTransportCostCalculator(VehicleRoutingTransportCosts routingCosts) {
|
||||||
super();
|
super();
|
||||||
this.routingCosts = routingCosts;
|
this.routingCosts = routingCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double depTimeAtPrevAct) {
|
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double depTimeAtPrevAct) {
|
||||||
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
|
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(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 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);
|
||||||
|
|
||||||
//open routes
|
//open routes
|
||||||
if(nextAct instanceof End){
|
if (nextAct instanceof End) {
|
||||||
if(!iFacts.getNewVehicle().isReturnToDepot()){
|
if (!iFacts.getNewVehicle().isReturnToDepot()) {
|
||||||
return tp_costs_prevAct_newAct;
|
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 totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct;
|
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct;
|
||||||
|
|
||||||
double oldCosts;
|
double oldCosts;
|
||||||
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;
|
}
|
||||||
}
|
return totalCosts - oldCosts;
|
||||||
return totalCosts - oldCosts;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,18 @@ import jsprit.core.problem.vehicle.Vehicle;
|
||||||
import jsprit.core.problem.vehicle.VehicleFleetManager;
|
import jsprit.core.problem.vehicle.VehicleFleetManager;
|
||||||
|
|
||||||
|
|
||||||
public class VehicleSwitched implements VehicleSwitchedListener{
|
public class VehicleSwitched implements VehicleSwitchedListener {
|
||||||
|
|
||||||
private VehicleFleetManager fleetManager;
|
private VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
public VehicleSwitched(VehicleFleetManager fleetManager){
|
public VehicleSwitched(VehicleFleetManager fleetManager) {
|
||||||
this.fleetManager = fleetManager;
|
this.fleetManager = fleetManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle) {
|
public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle) {
|
||||||
fleetManager.unlock(oldVehicle);
|
fleetManager.unlock(oldVehicle);
|
||||||
fleetManager.lock(newVehicle);
|
fleetManager.lock(newVehicle);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,99 +33,104 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCostsCalculator{
|
final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCostsCalculator {
|
||||||
|
|
||||||
private Logger logger = LogManager.getLogger(VehicleTypeDependentJobInsertionCalculator.class);
|
private Logger logger = LogManager.getLogger(VehicleTypeDependentJobInsertionCalculator.class);
|
||||||
|
|
||||||
private final VehicleFleetManager fleetManager;
|
private final VehicleFleetManager fleetManager;
|
||||||
|
|
||||||
private final JobInsertionCostsCalculator insertionCalculator;
|
private final JobInsertionCostsCalculator insertionCalculator;
|
||||||
|
|
||||||
private final VehicleRoutingProblem vrp;
|
private final VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
private Set<String> initialVehicleIds = new HashSet<String>();
|
private Set<String> initialVehicleIds = new HashSet<String>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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;
|
|
||||||
|
|
||||||
public VehicleTypeDependentJobInsertionCalculator(final VehicleRoutingProblem vrp, final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) {
|
public VehicleTypeDependentJobInsertionCalculator(final VehicleRoutingProblem vrp, final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) {
|
||||||
this.fleetManager = fleetManager;
|
this.fleetManager = fleetManager;
|
||||||
this.insertionCalculator = jobInsertionCalc;
|
this.insertionCalculator = jobInsertionCalc;
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
getInitialVehicleIds();
|
getInitialVehicleIds();
|
||||||
logger.debug("initialise " + this);
|
logger.debug("initialise " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getInitialVehicleIds() {
|
private void getInitialVehicleIds() {
|
||||||
Collection<VehicleRoute> initialVehicleRoutes = vrp.getInitialVehicleRoutes();
|
Collection<VehicleRoute> initialVehicleRoutes = vrp.getInitialVehicleRoutes();
|
||||||
for(VehicleRoute initialRoute : initialVehicleRoutes){
|
for (VehicleRoute initialRoute : initialVehicleRoutes) {
|
||||||
initialVehicleIds.add(initialRoute.getVehicle().getId());
|
initialVehicleIds.add(initialRoute.getVehicle().getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[name=vehicleTypeDependentServiceInsertion]";
|
return "[name=vehicleTypeDependentServiceInsertion]";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the vehicleSwitchAllowed
|
* @return the vehicleSwitchAllowed
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
public boolean isVehicleSwitchAllowed() {
|
public boolean isVehicleSwitchAllowed() {
|
||||||
return vehicleSwitchAllowed;
|
return vehicleSwitchAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* default is true
|
* default is true
|
||||||
*
|
*
|
||||||
* @param vehicleSwitchAllowed the vehicleSwitchAllowed to set
|
* @param vehicleSwitchAllowed the vehicleSwitchAllowed to set
|
||||||
*/
|
*/
|
||||||
public void setVehicleSwitchAllowed(boolean vehicleSwitchAllowed) {
|
public void setVehicleSwitchAllowed(boolean vehicleSwitchAllowed) {
|
||||||
logger.debug("set vehicleSwitchAllowed to " + vehicleSwitchAllowed);
|
logger.debug("set vehicleSwitchAllowed to " + vehicleSwitchAllowed);
|
||||||
this.vehicleSwitchAllowed = vehicleSwitchAllowed;
|
this.vehicleSwitchAllowed = vehicleSwitchAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
Vehicle selectedVehicle = currentRoute.getVehicle();
|
if(vehicle != null){
|
||||||
Driver selectedDriver = currentRoute.getDriver();
|
return insertionCalculator.getInsertionData(currentRoute, jobToInsert, vehicle, newVehicleDepartureTime, driver, bestKnownCost);
|
||||||
InsertionData bestIData = InsertionData.createEmptyInsertionData();
|
}
|
||||||
double bestKnownCost_ = bestKnownCost;
|
Vehicle selectedVehicle = currentRoute.getVehicle();
|
||||||
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
Driver selectedDriver = currentRoute.getDriver();
|
||||||
if(!(selectedVehicle instanceof NoVehicle)) {
|
InsertionData bestIData = InsertionData.createEmptyInsertionData();
|
||||||
relevantVehicles.add(selectedVehicle);
|
double bestKnownCost_ = bestKnownCost;
|
||||||
if(vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)){
|
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
|
||||||
relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle));
|
if (!(selectedVehicle instanceof NoVehicle)) {
|
||||||
}
|
relevantVehicles.add(selectedVehicle);
|
||||||
}
|
if (vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)) {
|
||||||
else{ //if no vehicle has been assigned, i.e. it is an empty route
|
relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle));
|
||||||
relevantVehicles.addAll(fleetManager.getAvailableVehicles());
|
}
|
||||||
}
|
} else { //if no vehicle has been assigned, i.e. it is an empty route
|
||||||
for(Vehicle v : relevantVehicles){
|
relevantVehicles.addAll(fleetManager.getAvailableVehicles());
|
||||||
double depTime;
|
}
|
||||||
if(v == selectedVehicle) depTime = currentRoute.getDepartureTime();
|
for (Vehicle v : relevantVehicles) {
|
||||||
else depTime = v.getEarliestDeparture();
|
double depTime;
|
||||||
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
if (v == selectedVehicle) depTime = currentRoute.getDepartureTime();
|
||||||
if(iData instanceof NoInsertionFound) {
|
else depTime = v.getEarliestDeparture();
|
||||||
|
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
|
||||||
|
if (iData instanceof NoInsertionFound) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(iData.getInsertionCost() < bestKnownCost_){
|
if (iData.getInsertionCost() < bestKnownCost_) {
|
||||||
bestIData = iData;
|
bestIData = iData;
|
||||||
bestKnownCost_ = iData.getInsertionCost();
|
bestKnownCost_ = iData.getInsertionCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bestIData;
|
return bestIData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) {
|
VehicleFleetManager getFleetManager(){
|
||||||
return initialVehicleIds.contains(selectedVehicle.getId());
|
return fleetManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) {
|
||||||
|
return initialVehicleIds.contains(selectedVehicle.getId());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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