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

merged master into multiple tw branch

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

13
.editorconfig Normal file
View file

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

View file

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

View file

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

View file

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

View file

@ -1,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>

View file

@ -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);
} }
} }

View file

@ -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);

View file

@ -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");
} }
} }

View file

@ -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);
}
} }

View file

@ -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));
} }
} }

View file

@ -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){
// //
// } // }
} }

View file

@ -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;
} }

View file

@ -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;
} }
} }

View file

@ -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;
}
} }

View file

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

View file

@ -16,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("&Oslash; 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("&Oslash; 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("&Oslash;") + 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("&Oslash;") + 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>";
}
} }

View file

@ -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>

View file

@ -25,6 +25,7 @@ import jsprit.core.problem.solution.InitialSolutionFactory;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.Vehicle;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -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;
}
} }

View file

@ -25,6 +25,7 @@ import jsprit.core.algorithm.recreate.VehicleSwitched;
import jsprit.core.algorithm.state.*; import jsprit.core.algorithm.state.*;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.constraint.ConstraintManager; import jsprit.core.problem.constraint.ConstraintManager;
import jsprit.core.problem.constraint.SwitchNotFeasible;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
@ -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;
} }

View file

@ -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);
} }
} }
} }
} }

View file

@ -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]";
} }
} }

View file

@ -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);
} }
} }
} }

View file

@ -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);
} }
} }
} }

View file

@ -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);
} }

View file

@ -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;
} }
}; };
} }
} }

View file

@ -20,6 +20,7 @@ import jsprit.core.algorithm.SearchStrategy.DiscoveredSolution;
import jsprit.core.algorithm.listener.*; import jsprit.core.algorithm.listener.*;
import jsprit.core.algorithm.termination.PrematureAlgorithmTermination; import jsprit.core.algorithm.termination.PrematureAlgorithmTermination;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
@ -35,7 +36,6 @@ import java.util.Collection;
* Algorithm that solves a {@link VehicleRoutingProblem}. * Algorithm that solves a {@link VehicleRoutingProblem}.
* *
* @author stefan schroeder * @author stefan schroeder
*
*/ */
public class VehicleRoutingAlgorithm { public class VehicleRoutingAlgorithm {
@ -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);
} }
/** /**

View file

@ -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);
} }
} }

View file

@ -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);
} }

View file

@ -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]";
}
} }

View file

@ -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;
} }
} }

View file

@ -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]";
}
} }

View file

@ -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]";
}
} }

View file

@ -29,21 +29,21 @@ import java.util.Collection;
/** /**
* ThresholdAcceptance-Function defined by Schrimpf et al. (2000). * ThresholdAcceptance-Function defined by Schrimpf et al. (2000).
* * <p/>
* <p>The <b>idea</b> can be described as follows: Most problems do not only have one unique minimum (maximum) but * <p>The <b>idea</b> can be described as follows: Most problems do not only have one unique minimum (maximum) but
* a number of local minima (maxima). To avoid to get stuck in a local minimum at the beginning of a search * a number of local minima (maxima). To avoid to get stuck in a local minimum at the beginning of a search
* this threshold-acceptance function accepts also worse solution at the beginning (in contrary to a greedy * this threshold-acceptance function accepts also worse solution at the beginning (in contrary to a greedy
* approach which only accepts better solutions), and converges to a greedy approach at the end. <br> * approach which only accepts better solutions), and converges to a greedy approach at the end. <br>
* The difficulty is to define (i) an appropriate initial threshold and (ii) a corresponding function describing * The difficulty is to define (i) an appropriate initial threshold and (ii) a corresponding function describing
* how the threshold converges to zero, i.e. the greedy threshold. * how the threshold converges to zero, i.e. the greedy threshold.
* * <p/>
* <p>ad i) The initial threshold is determined by a random walk through the search space. * <p>ad i) The initial threshold is determined by a random walk through the search space.
* The random walk currently runs with the following algorithm: src/main/resources/randomWalk.xml. It runs * The random walk currently runs with the following algorithm: src/main/resources/randomWalk.xml. It runs
* as long as it is specified in nuOfWarmupIterations. In the first iteration or walk respectively the algorithm generates a solution. * as long as it is specified in nuOfWarmupIterations. In the first iteration or walk respectively the algorithm generates a solution.
* This solution in turn is the basis of the next walk yielding to another solution value ... and so on. * This solution in turn is the basis of the next walk yielding to another solution value ... and so on.
* Each solution value is memorized since the initial threshold is essentially a function of the standard deviation of these solution values. * Each solution value is memorized since the initial threshold is essentially a function of the standard deviation of these solution values.
* To be more precise: initial threshold = stddev(solution values) / 2. * To be more precise: initial threshold = stddev(solution values) / 2.
* * <p/>
* <p>ad ii) The threshold of iteration i is determined as follows: * <p>ad ii) The threshold of iteration i is determined as follows:
* threshold(i) = initialThreshold * Math.exp(-Math.log(2) * (i / nuOfTotalIterations) / alpha) * threshold(i) = initialThreshold * Math.exp(-Math.log(2) * (i / nuOfTotalIterations) / alpha)
* To get a better understanding of the threshold-function go to Wolfram Alpha and plot the following line * To get a better understanding of the threshold-function go to Wolfram Alpha and plot the following line
@ -55,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;
} }
} }

View file

@ -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("---------------------------------------------------------------------");
} }
} }

View file

@ -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);
} }

View file

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

View file

@ -26,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);
} }
} }

View file

@ -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;
} }

View file

@ -17,6 +17,7 @@ import jsprit.core.problem.constraint.ConstraintManager;
import jsprit.core.problem.solution.SolutionCostCalculator; import jsprit.core.problem.solution.SolutionCostCalculator;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution; import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.solution.route.activity.BreakActivity;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
import jsprit.core.problem.vehicle.FiniteFleetManagerFactory; import jsprit.core.problem.vehicle.FiniteFleetManagerFactory;
import jsprit.core.problem.vehicle.InfiniteFleetManagerFactory; import jsprit.core.problem.vehicle.InfiniteFleetManagerFactory;
@ -34,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;
} }
} }

View file

@ -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);
} }
} }

View file

@ -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;
} }
} }

View file

@ -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);
} }
} }

View file

@ -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.");
}
} }

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -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);
} }

View file

@ -16,6 +16,6 @@
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
public interface SearchStrategyListener extends VehicleRoutingAlgorithmListener{ public interface SearchStrategyListener extends VehicleRoutingAlgorithmListener {
} }

View file

@ -16,6 +16,6 @@
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
public interface SearchStrategyModuleListener extends VehicleRoutingAlgorithmListener{ public interface SearchStrategyModuleListener extends VehicleRoutingAlgorithmListener {
} }

View file

@ -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);
} }

View file

@ -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);
}
}
}
} }

View file

@ -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;
} }
} }

View file

@ -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());

View file

@ -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);
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }

View file

@ -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;
}
} }

View file

@ -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;
} }
} }

View file

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

View file

@ -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;
} }
} }

View file

@ -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;
} }
} }

View file

@ -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);
} }
} }

View file

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

View file

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

View file

@ -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);
} }
} }

View file

@ -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);
} }
} }

View file

@ -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());
} }
} }

View file

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

View file

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

View file

@ -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());
} }
} }

View file

@ -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;
}
} }

View file

@ -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;
}
} }

View file

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

View file

@ -23,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();
} }

View file

@ -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);
} }

View file

@ -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);
} }
} }

View file

@ -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());
} }
} }

View file

@ -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);
} }

View file

@ -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;
} }
} }

View file

@ -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);
} }

View file

@ -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);
} }
}; };

View file

@ -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;
}
} }

View file

@ -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;
} }

View file

@ -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;
} }

View file

@ -17,10 +17,8 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.algorithm.recreate.RegretInsertion.DefaultScorer;
import jsprit.core.algorithm.recreate.RegretInsertion.ScoredJob;
import jsprit.core.algorithm.recreate.RegretInsertion.ScoringFunction;
import jsprit.core.problem.VehicleRoutingProblem; import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.job.Break;
import jsprit.core.problem.job.Job; import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@ -28,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;
}
} }

View file

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

View file

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

View file

@ -1,4 +1,3 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2014 Stefan Schroeder * Copyright (C) 2014 Stefan Schroeder
* *
@ -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;

View file

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

View file

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

View file

@ -41,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;
} }
} }

View file

@ -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; }
}
} }
}; };
} }
} }

View file

@ -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);
} }
} }

View file

@ -1,15 +1,33 @@
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
import jsprit.core.problem.job.Break;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /**
* Created by schroeder on 19/05/15. * Created by schroeder on 19/05/15.
*/ */
class SwitchVehicleListener implements EventListener{ class SwitchVehicleListener implements EventListener {
private static final Logger logger = LogManager.getLogger();
@Override @Override
public void inform(Event event) { public void inform(Event event) {
if(event instanceof SwitchVehicle){ if (event instanceof SwitchVehicle) {
SwitchVehicle switchVehicle = (SwitchVehicle) event; SwitchVehicle switchVehicle = (SwitchVehicle) event;
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());
}
} }

View file

@ -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; }
}
} }

View file

@ -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);
} }
} }

View file

@ -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