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

merge master

This commit is contained in:
oblonski 2015-09-23 17:42:42 +02:00
commit a55ea8f3cf
506 changed files with 73608 additions and 73610 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

@ -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>
<pluginManagement> <build>
<plugins> <pluginManagement>
<plugin> <plugins>
<groupId>org.eclipse.m2e</groupId> <plugin>
<artifactId>lifecycle-mapping</artifactId> <groupId>org.eclipse.m2e</groupId>
<version>1.0.0</version> <artifactId>lifecycle-mapping</artifactId>
<configuration> <version>1.0.0</version>
<lifecycleMappingMetadata> <configuration>
<pluginExecutions> <lifecycleMappingMetadata>
<pluginExecution> <pluginExecutions>
<pluginExecutionFilter> <pluginExecution>
<groupId>org.apache.maven.plugins</groupId> <pluginExecutionFilter>
<artifactId>maven-enforcer-plugin</artifactId> <groupId>org.apache.maven.plugins</groupId>
<versionRange>[1.0.0,)</versionRange> <artifactId>maven-enforcer-plugin</artifactId>
<goals> <versionRange>[1.0.0,)</versionRange>
<goal>enforce</goal> <goals>
</goals> <goal>enforce</goal>
</pluginExecutionFilter> </goals>
<action> </pluginExecutionFilter>
<ignore /> <action>
</action> <ignore/>
</pluginExecution> </action>
</pluginExecutions> </pluginExecution>
</lifecycleMappingMetadata> </pluginExecutions>
</configuration> </lifecycleMappingMetadata>
</plugin> </configuration>
</plugins> </plugin>
</pluginManagement> </plugins>
</build> </pluginManagement>
</build>
<dependencies>
<dependency> <dependencies>
<groupId>org.jfree</groupId> <dependency>
<artifactId>jfreechart</artifactId> <groupId>org.jfree</groupId>
<version>1.0.14</version> <artifactId>jfreechart</artifactId>
<scope>compile</scope> <version>1.0.19</version>
</dependency> <scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId> <dependency>
<artifactId>jsprit-core</artifactId> <groupId>${project.groupId}</groupId>
<version>${project.version}</version> <artifactId>jsprit-core</artifactId>
<type>jar</type> <version>${project.version}</version>
<scope>provided</scope> <type>jar</type>
</dependency> <scope>provided</scope>
</dependency>
<dependency>
<artifactId>gs-core</artifactId> <dependency>
<groupId>org.graphstream</groupId> <artifactId>gs-core</artifactId>
<version>1.3</version> <groupId>org.graphstream</groupId>
<optional>false</optional> <version>1.3</version>
</dependency> <optional>false</optional>
</dependency>
<dependency>
<artifactId>gs-ui</artifactId> <dependency>
<groupId>org.graphstream</groupId> <artifactId>gs-ui</artifactId>
<version>1.3</version> <groupId>org.graphstream</groupId>
<optional>false</optional> <version>1.3</version>
</dependency> <optional>false</optional>
</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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.analysis.toolbox; package jsprit.analysis.toolbox;
@ -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).
*
* @param pngFileName
*/
public AlgorithmSearchProgressChartListener(String pngFileName) {
super();
this.filename = pngFileName;
if(!this.filename.endsWith("png")){
this.filename += ".png";
}
}
@Override /**
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { * Constructs chart listener with target png-file (filename plus path).
log.info("create chart " + filename); *
XYLineChartBuilder.saveChartAsPNG(chartBuilder.build(), filename); * @param pngFileName
} */
public AlgorithmSearchProgressChartListener(String pngFileName) {
super();
this.filename = pngFileName;
if (!this.filename.endsWith("png")) {
this.filename += ".png";
}
}
@Override @Override
public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
double worst = 0.0; log.info("create chart " + filename);
double best = Double.MAX_VALUE; XYLineChartBuilder.saveChartAsPNG(chartBuilder.build(), filename);
double sum = 0.0; }
for(VehicleRoutingProblemSolution sol : solutions){
if(sol.getCost() > worst) worst = Math.min(sol.getCost(),Double.MAX_VALUE); @Override
if(sol.getCost() < best) best = sol.getCost(); public void informIterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
sum += Math.min(sol.getCost(),Double.MAX_VALUE); double worst = 0.0;
} double best = Double.MAX_VALUE;
chartBuilder.addData("best", i, best); double sum = 0.0;
chartBuilder.addData("worst", i, worst); for (VehicleRoutingProblemSolution sol : solutions) {
chartBuilder.addData("avg", i, sum/(double)solutions.size()); if (sol.getCost() > worst) worst = Math.min(sol.getCost(), Double.MAX_VALUE);
} if (sol.getCost() < best) best = sol.getCost();
sum += Math.min(sol.getCost(), Double.MAX_VALUE);
}
chartBuilder.addData("best", i, best);
chartBuilder.addData("worst", i, worst);
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

@ -1,18 +1,18 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
@ -33,433 +33,442 @@ 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 calculationEnds(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run, final Collection<VehicleRoutingProblemSolution> solutions);
}
public static interface LabStartsAndEndsListener extends LabListener { public void calculationStarts(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run);
public void labStarts(List<BenchmarkInstance> instances, int noAlgorithms, int runs); public void calculationEnds(final BenchmarkInstance p, final String algorithmName, final VehicleRoutingAlgorithm algorithm, final int run, final Collection<VehicleRoutingProblemSolution> solutions);
public void labEnds(); }
}
/**
* Collects whatever indicators you require by algorithmName, instanceName, run and indicator.
*
* @author schroeder
*
*/
public static class DataCollector {
public static class Key {
private String instanceName;
private String algorithmName;
private int run;
private String indicatorName;
public Key(String instanceName, String algorithmName, int run,String indicatorName) {
super();
this.instanceName = instanceName;
this.algorithmName = algorithmName;
this.run = run;
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
public String toString() {
return "[algorithm="+algorithmName+"][instance="+instanceName+"][run="+run+"][indicator="+indicatorName+"]";
}
}
private final static String SOLUTION_INDICATOR_NAME = "vehicle-routing-problem-solution";
private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>();
private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>();
/**
* 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){
Key key = new Key(instanceName,algorithmName,run,SOLUTION_INDICATOR_NAME);
solutions.put(key, solution);
}
/**
* Returns a collections of indicator values representing the calculated values of individual runs.
*
* @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){
return solutions.get(new Key(instanceName,algorithmName,run,"solution"));
}
/** public static interface LabStartsAndEndsListener extends LabListener {
* 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 String name;
private VehicleRoutingAlgorithmFactory factory;
public Algorithm(String name, VehicleRoutingAlgorithmFactory factory) { public void labStarts(List<BenchmarkInstance> instances, int noAlgorithms, int runs);
super();
this.name = name;
this.factory = factory;
}
}
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
private int runs = 1; public void labEnds();
}
private Collection<CalculationListener> listeners = new ArrayList<ComputationalLaboratory.CalculationListener>();
private Collection<LabStartsAndEndsListener> startsAndEndslisteners = new ArrayList<LabStartsAndEndsListener>(); /**
* Collects whatever indicators you require by algorithmName, instanceName, run and indicator.
private List<Algorithm> algorithms = new ArrayList<ComputationalLaboratory.Algorithm>(); *
* @author schroeder
private Set<String> algorithmNames = new HashSet<String>(); */
public static class DataCollector {
private Set<String> instanceNames = new HashSet<String>();
private int threads = 1;
public ComputationalLaboratory() {
} public static class Key {
private String instanceName;
/** private String algorithmName;
* Adds algorithmFactory by name. private int run;
* private String indicatorName;
* @param name
* @param factory
* @throws IllegalStateException if there is already an algorithmFactory with the same name
*/
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.");
algorithms.add(new Algorithm(name,factory));
algorithmNames.add(name);
}
public Collection<String> getAlgorithmNames() {
return algorithmNames;
}
public Collection<String> getInstanceNames(){
return instanceNames;
}
/** public Key(String instanceName, String algorithmName, int run, String indicatorName) {
* Adds instance by name. super();
* this.instanceName = instanceName;
* @param name this.algorithmName = algorithmName;
* @param problem this.run = run;
* @throws IllegalStateException if there is already an instance with the same name. this.indicatorName = indicatorName;
*/ }
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."); @Override
benchmarkInstances.add(new BenchmarkInstance(name,problem,null,null)); public int hashCode() {
instanceNames.add(name); final int prime = 31;
} int result = 1;
result = prime
/** * result
* Adds instance. + ((algorithmName == null) ? 0 : algorithmName
* .hashCode());
* @param instance the instance to be added result = prime
* @throws IllegalStateException if there is already an instance with the same name. * result
*/ + ((indicatorName == null) ? 0 : indicatorName
public void addInstance(BenchmarkInstance instance){ .hashCode());
if(benchmarkInstances.contains(instance.name)) throw new IllegalStateException("there is already an instance with the same name (instanceName="+instance.name+"). unique names are required."); result = prime
benchmarkInstances.add(instance); * result
instanceNames.add(instance.name); + ((instanceName == null) ? 0 : instanceName.hashCode());
} result = prime * result + run;
return result;
/** }
* Adds collection of instances.
* @Override
* @param instances collection of instances to be added public boolean equals(Object obj) {
* @throws IllegalStateException if there is already an instance with the same name. if (this == obj)
*/ return true;
public void addAllInstances(Collection<BenchmarkInstance> instances){ if (obj == null)
for(BenchmarkInstance i : instances){ return false;
addInstance(i); if (getClass() != obj.getClass())
} return false;
} Key other = (Key) obj;
if (algorithmName == null) {
/** if (other.algorithmName != null)
* Adds instance by name, and with best known results. return false;
* } else if (!algorithmName.equals(other.algorithmName))
* @param name return false;
* @param problem if (indicatorName == null) {
* @throws IllegalStateException if there is already an instance with the same name. if (other.indicatorName != null)
*/ return false;
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles){ } else if (!indicatorName.equals(other.indicatorName))
addInstance(new BenchmarkInstance(name,problem,bestKnownResult,bestKnownVehicles)); return false;
} if (instanceName == null) {
if (other.instanceName != null)
/** return false;
* Adds listener to listen computational experiments. } else if (!instanceName.equals(other.instanceName))
* return false;
* @param listener if (run != other.run)
*/ return false;
public void addListener(LabListener listener){ return true;
if(listener instanceof CalculationListener) { }
listeners.add((CalculationListener) listener);
} public String getInstanceName() {
if(listener instanceof LabStartsAndEndsListener){ return instanceName;
startsAndEndslisteners.add((LabStartsAndEndsListener) listener); }
}
} public String getAlgorithmName() {
return algorithmName;
/** }
* Sets nuOfRuns with same algorithm on same instance.
* <p>Default is 1 public int getRun() {
* return run;
* @param runs }
*/
public void setNuOfRuns(int runs){ public String getIndicatorName() {
this.runs = runs; return indicatorName;
} }
/** @Override
* Runs experiments. public String toString() {
* return "[algorithm=" + algorithmName + "][instance=" + instanceName + "][run=" + run + "][indicator=" + indicatorName + "]";
* <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.
* <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.
* <p>You can register whatever analysisTool you require by implementing and registering CalculationListener. Then your tool is informed just private final static String SOLUTION_INDICATOR_NAME = "vehicle-routing-problem-solution";
* before a calculation starts as well as just after a calculation has been finished.
* private ConcurrentHashMap<Key, Double> data = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, Double>();
* @see CalculationListener
* @throws IllegalStateException if either no algorithm or no instance has been specified private ConcurrentHashMap<Key, VehicleRoutingProblemSolution> solutions = new ConcurrentHashMap<ComputationalLaboratory.DataCollector.Key, VehicleRoutingProblemSolution>();
*/
public void run(){ /**
if(algorithms.isEmpty()){ * Adds a single date by instanceName, algorithmName, run and indicatorName.
throw new IllegalStateException("no algorithm specified. at least one algorithm needs to be specified."); * <p>If there is already an entry for this instance, algorithm, run and indicatorName, it is overwritten.
} *
if(benchmarkInstances.isEmpty()){ * @param instanceName
throw new IllegalStateException("no instance specified. at least one instance needs to be specified."); * @param algorithmName
} * @param run
informStart(); * @param indicatorName
System.out.println("start benchmarking [nuAlgorithms="+algorithms.size()+"][nuInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]"); * @param value
double startTime = System.currentTimeMillis(); */
ExecutorService executor = Executors.newFixedThreadPool(threads); public void addDate(String instanceName, String algorithmName, int run, String indicatorName, double value) {
for(final Algorithm algorithm : algorithms){ if (indicatorName.equals(SOLUTION_INDICATOR_NAME))
for(final BenchmarkInstance p : benchmarkInstances){ throw new IllegalArgumentException(indicatorName + " is already used internally. please choose another indicator-name.");
for(int run=0;run<runs;run++){ Key key = new Key(instanceName, algorithmName, run, indicatorName);
final int r = run; data.put(key, value);
}
public void addSolution(String instanceName, String algorithmName, int run, VehicleRoutingProblemSolution solution) {
Key key = new Key(instanceName, algorithmName, run, SOLUTION_INDICATOR_NAME);
solutions.put(key, solution);
}
/**
* Returns a collections of indicator values representing the calculated values of individual runs.
*
* @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) {
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 String name;
private VehicleRoutingAlgorithmFactory factory;
public Algorithm(String name, VehicleRoutingAlgorithmFactory factory) {
super();
this.name = name;
this.factory = factory;
}
}
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
private int runs = 1;
private Collection<CalculationListener> listeners = new ArrayList<ComputationalLaboratory.CalculationListener>();
private Collection<LabStartsAndEndsListener> startsAndEndslisteners = new ArrayList<LabStartsAndEndsListener>();
private List<Algorithm> algorithms = new ArrayList<ComputationalLaboratory.Algorithm>();
private Set<String> algorithmNames = new HashSet<String>();
private Set<String> instanceNames = new HashSet<String>();
private int threads = 1;
public ComputationalLaboratory() {
}
/**
* Adds algorithmFactory by name.
*
* @param name
* @param factory
* @throws IllegalStateException if there is already an algorithmFactory with the same name
*/
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.");
algorithms.add(new Algorithm(name, factory));
algorithmNames.add(name);
}
public Collection<String> getAlgorithmNames() {
return algorithmNames;
}
public Collection<String> getInstanceNames() {
return instanceNames;
}
/**
* Adds instance by name.
*
* @param name
* @param problem
* @throws IllegalStateException if there is already an instance with the same name.
*/
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.");
benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null));
instanceNames.add(name);
}
/**
* Adds instance.
*
* @param instance the instance to be added
* @throws IllegalStateException if there is already an instance with the same name.
*/
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.");
benchmarkInstances.add(instance);
instanceNames.add(instance.name);
}
/**
* Adds collection of instances.
*
* @param instances collection of instances to be added
* @throws IllegalStateException if there is already an instance with the same name.
*/
public void addAllInstances(Collection<BenchmarkInstance> instances) {
for (BenchmarkInstance i : instances) {
addInstance(i);
}
}
/**
* Adds instance by name, and with best known results.
*
* @param name
* @param problem
* @throws IllegalStateException if there is already an instance with the same name.
*/
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles) {
addInstance(new BenchmarkInstance(name, problem, bestKnownResult, bestKnownVehicles));
}
/**
* Adds listener to listen computational experiments.
*
* @param listener
*/
public void addListener(LabListener listener) {
if (listener instanceof CalculationListener) {
listeners.add((CalculationListener) listener);
}
if (listener instanceof LabStartsAndEndsListener) {
startsAndEndslisteners.add((LabStartsAndEndsListener) listener);
}
}
/**
* Sets nuOfRuns with same algorithm on same instance.
* <p>Default is 1
*
* @param runs
*/
public void setNuOfRuns(int runs) {
this.runs = runs;
}
/**
* Runs experiments.
* <p/>
* <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.
* <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.
* <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.
*
* @throws IllegalStateException if either no algorithm or no instance has been specified
* @see CalculationListener
*/
public void run() {
if (algorithms.isEmpty()) {
throw new IllegalStateException("no algorithm specified. at least one algorithm needs to be specified.");
}
if (benchmarkInstances.isEmpty()) {
throw new IllegalStateException("no instance specified. at least one instance needs to be specified.");
}
informStart();
System.out.println("start benchmarking [nuAlgorithms=" + algorithms.size() + "][nuInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
double startTime = System.currentTimeMillis();
ExecutorService executor = Executors.newFixedThreadPool(threads);
for (final Algorithm algorithm : algorithms) {
for (final BenchmarkInstance p : benchmarkInstances) {
for (int run = 0; run < runs; run++) {
final int r = run;
// runAlgorithm(p, algorithm, r+1); // runAlgorithm(p, algorithm, r+1);
executor.submit(new Runnable(){ executor.submit(new Runnable() {
@Override @Override
public void run() { public void run() {
runAlgorithm(p, algorithm, r+1); runAlgorithm(p, algorithm, r + 1);
} }
}); });
} }
} }
} }
try { try {
executor.shutdown(); executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES); executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("benchmarking done [time="+(System.currentTimeMillis()-startTime)/1000 + "sec]");
informEnd();
}
private void informEnd() { } catch (InterruptedException e) {
for(LabStartsAndEndsListener l : startsAndEndslisteners){ e.printStackTrace();
l.labEnds(); }
} System.out.println("benchmarking done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]");
} informEnd();
}
private void informStart() { private void informEnd() {
for(LabStartsAndEndsListener l : startsAndEndslisteners){ for (LabStartsAndEndsListener l : startsAndEndslisteners) {
l.labStarts(benchmarkInstances, algorithms.size(),runs); l.labEnds();
} }
} }
/** private void informStart() {
* Sets number of threads. for (LabStartsAndEndsListener l : startsAndEndslisteners) {
* <p>By default: <code>nuThreads = Runtime.getRuntime().availableProcessors()+1</code> l.labStarts(benchmarkInstances, algorithms.size(), runs);
* }
* @param threads }
*/
public void setThreads(int threads) {
this.threads = threads;
}
private void runAlgorithm(BenchmarkInstance p, Algorithm algorithm, int run) { /**
System.out.println("[algorithm=" + algorithm.name + "][instance="+p.name+"][run="+run+"][status=start]"); * Sets number of threads.
VehicleRoutingAlgorithm vra = algorithm.factory.createAlgorithm(p.vrp); * <p>By default: <code>nuThreads = Runtime.getRuntime().availableProcessors()+1</code>
informCalculationStarts(p, algorithm.name, vra, run); *
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions(); * @param threads
System.out.println("[algorithm=" + algorithm.name + "][instance="+p.name+"][run="+run+"][status=finished]"); */
informCalculationsEnds(p, algorithm.name, vra, run, solutions); public void setThreads(int threads) {
} this.threads = threads;
}
private void informCalculationStarts(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run) { private void runAlgorithm(BenchmarkInstance p, Algorithm algorithm, int run) {
for(CalculationListener l : listeners) l.calculationStarts(p, name, vra, run); System.out.println("[algorithm=" + algorithm.name + "][instance=" + p.name + "][run=" + run + "][status=start]");
} 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 informCalculationsEnds(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run, private void informCalculationStarts(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run) {
Collection<VehicleRoutingProblemSolution> solutions) { for (CalculationListener l : listeners) l.calculationStarts(p, name, vra, run);
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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.analysis.toolbox; package jsprit.analysis.toolbox;
@ -35,185 +35,185 @@ import java.util.concurrent.*;
public class ConcurrentBenchmarker { public class ConcurrentBenchmarker {
public static interface Cost {
public double getCost(VehicleRoutingProblemSolution sol);
}
private String algorithmConfig = null;
private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
private int runs = 1; public static interface Cost {
public double getCost(VehicleRoutingProblemSolution sol);
private Collection<BenchmarkWriter> writers = new ArrayList<BenchmarkWriter>(); }
private Collection<BenchmarkResult> results = new ArrayList<BenchmarkResult>();
private Cost cost = new Cost(){
@Override
public double getCost(VehicleRoutingProblemSolution sol) {
return sol.getCost();
}
};
private VehicleRoutingAlgorithmFactory algorithmFactory; private String algorithmConfig = null;
public void setCost(Cost cost){ this.cost = cost; } private List<BenchmarkInstance> benchmarkInstances = new ArrayList<BenchmarkInstance>();
public ConcurrentBenchmarker(String algorithmConfig) { private int runs = 1;
super();
this.algorithmConfig = algorithmConfig; private Collection<BenchmarkWriter> writers = new ArrayList<BenchmarkWriter>();
private Collection<BenchmarkResult> results = new ArrayList<BenchmarkResult>();
private Cost cost = new Cost() {
@Override
public double getCost(VehicleRoutingProblemSolution sol) {
return sol.getCost();
}
};
private VehicleRoutingAlgorithmFactory algorithmFactory;
public void setCost(Cost cost) {
this.cost = cost;
}
public ConcurrentBenchmarker(String algorithmConfig) {
super();
this.algorithmConfig = algorithmConfig;
// LogManager.getRootLogger().setLevel(Level.ERROR); // LogManager.getRootLogger().setLevel(Level.ERROR);
} }
public ConcurrentBenchmarker(VehicleRoutingAlgorithmFactory algorithmFactory){
this.algorithmFactory = algorithmFactory;
}
public void addBenchmarkWriter(BenchmarkWriter writer){
writers.add(writer);
}
public void addInstance(String name, VehicleRoutingProblem problem){ public ConcurrentBenchmarker(VehicleRoutingAlgorithmFactory algorithmFactory) {
benchmarkInstances.add(new BenchmarkInstance(name,problem,null,null)); this.algorithmFactory = algorithmFactory;
} }
public void addInstane(BenchmarkInstance instance){
benchmarkInstances.add(instance);
}
public void addAllInstances(Collection<BenchmarkInstance> instances){
benchmarkInstances.addAll(instances);
}
public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles){
benchmarkInstances.add(new BenchmarkInstance(name,problem,bestKnownResult,bestKnownVehicles));
}
/**
* Sets nuOfRuns with same algorithm on same instance.
* <p>Default is 1
*
* @param runs
*/
public void setNuOfRuns(int runs){
this.runs = runs;
}
public void run(){
System.out.println("start benchmarking [nuOfInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
double startTime = System.currentTimeMillis();
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()+1);
List<Future<BenchmarkResult>> futures = new ArrayList<Future<BenchmarkResult>>();
for(final BenchmarkInstance p : benchmarkInstances){
Future<BenchmarkResult> futureResult = executor.submit(new Callable<BenchmarkResult>(){
@Override public void addBenchmarkWriter(BenchmarkWriter writer) {
public BenchmarkResult call() throws Exception { writers.add(writer);
return runAlgoAndGetResult(p); }
}
}); public void addInstance(String name, VehicleRoutingProblem problem) {
futures.add(futureResult); benchmarkInstances.add(new BenchmarkInstance(name, problem, null, null));
}
}
try {
int count = 1;
for(Future<BenchmarkResult> f : futures){
BenchmarkResult r = f.get();
print(r,count);
results.add(f.get());
count++;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executor.shutdown();
print(results);
System.out.println("done [time="+(System.currentTimeMillis()-startTime)/1000 + "sec]");
}
private BenchmarkResult runAlgoAndGetResult(BenchmarkInstance p) { public void addInstane(BenchmarkInstance instance) {
double[] vehicles = new double[runs]; benchmarkInstances.add(instance);
double[] results = new double[runs]; }
double[] times = new double[runs];
for(int run=0;run<runs;run++){
VehicleRoutingAlgorithm vra = createAlgorithm(p);
StopWatch stopwatch = new StopWatch();
vra.getAlgorithmListeners().addListener(stopwatch,Priority.HIGH);
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
VehicleRoutingProblemSolution best = Solutions.bestOf(solutions);
vehicles[run] = best.getRoutes().size();
results[run] = cost.getCost(best);
times[run] = stopwatch.getCompTimeInSeconds();
}
return new BenchmarkResult(p, runs, results, times, vehicles);
}
private VehicleRoutingAlgorithm createAlgorithm(BenchmarkInstance p) { public void addAllInstances(Collection<BenchmarkInstance> instances) {
if(algorithmConfig != null){ benchmarkInstances.addAll(instances);
return VehicleRoutingAlgorithms.readAndCreateAlgorithm(p.vrp, algorithmConfig); }
}
else{
return algorithmFactory.createAlgorithm(p.vrp);
}
}
private void print(Collection<BenchmarkResult> results) { public void addInstance(String name, VehicleRoutingProblem problem, Double bestKnownResult, Double bestKnownVehicles) {
double sumTime=0.0; benchmarkInstances.add(new BenchmarkInstance(name, problem, bestKnownResult, bestKnownVehicles));
double sumResult=0.0; }
for(BenchmarkResult r : results){
sumTime+=r.getTimesStats().getMean(); /**
sumResult+=r.getResultStats().getMean(); * Sets nuOfRuns with same algorithm on same instance.
* <p>Default is 1
*
* @param runs
*/
public void setNuOfRuns(int runs) {
this.runs = runs;
}
public void run() {
System.out.println("start benchmarking [nuOfInstances=" + benchmarkInstances.size() + "][runsPerInstance=" + runs + "]");
double startTime = System.currentTimeMillis();
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);
List<Future<BenchmarkResult>> futures = new ArrayList<Future<BenchmarkResult>>();
for (final BenchmarkInstance p : benchmarkInstances) {
Future<BenchmarkResult> futureResult = executor.submit(new Callable<BenchmarkResult>() {
@Override
public BenchmarkResult call() throws Exception {
return runAlgoAndGetResult(p);
}
});
futures.add(futureResult);
}
try {
int count = 1;
for (Future<BenchmarkResult> f : futures) {
BenchmarkResult r = f.get();
print(r, count);
results.add(f.get());
count++;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executor.shutdown();
print(results);
System.out.println("done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]");
}
private BenchmarkResult runAlgoAndGetResult(BenchmarkInstance p) {
double[] vehicles = new double[runs];
double[] results = new double[runs];
double[] times = new double[runs];
for (int run = 0; run < runs; run++) {
VehicleRoutingAlgorithm vra = createAlgorithm(p);
StopWatch stopwatch = new StopWatch();
vra.getAlgorithmListeners().addListener(stopwatch, Priority.HIGH);
Collection<VehicleRoutingProblemSolution> solutions = vra.searchSolutions();
VehicleRoutingProblemSolution best = Solutions.bestOf(solutions);
vehicles[run] = best.getRoutes().size();
results[run] = cost.getCost(best);
times[run] = stopwatch.getCompTimeInSeconds();
}
return new BenchmarkResult(p, runs, results, times, vehicles);
}
private VehicleRoutingAlgorithm createAlgorithm(BenchmarkInstance p) {
if (algorithmConfig != null) {
return VehicleRoutingAlgorithms.readAndCreateAlgorithm(p.vrp, algorithmConfig);
} else {
return algorithmFactory.createAlgorithm(p.vrp);
}
}
private void print(Collection<BenchmarkResult> results) {
double sumTime = 0.0;
double sumResult = 0.0;
for (BenchmarkResult r : results) {
sumTime += r.getTimesStats().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) {
return "[best="+round(bestDelta,2)+"][avg="+round(avgDelta,2)+"][worst="+round(worstDelta,2)+"]";
}
private String getString(DescriptiveStatistics stats){ private String getString(Double bestDelta, Double avgDelta, Double worstDelta) {
return "[best="+round(stats.getMin(),2)+"][avg="+round(stats.getMean(),2)+"][worst="+round(stats.getMax(),2)+"][stdDev=" + round(stats.getStandardDeviation(),2)+"]"; return "[best=" + round(bestDelta, 2) + "][avg=" + round(avgDelta, 2) + "][worst=" + round(worstDelta, 2) + "]";
} }
private Double round(Double value, int i) { private String getString(DescriptiveStatistics stats) {
if(value==null) return null; return "[best=" + round(stats.getMin(), 2) + "][avg=" + round(stats.getMean(), 2) + "][worst=" + round(stats.getMax(), 2) + "][stdDev=" + round(stats.getStandardDeviation(), 2) + "]";
long roundedVal = Math.round(value*Math.pow(10, i)); }
return (double)roundedVal/(double)(Math.pow(10, i));
} private Double round(Double value, int i) {
if (value == null) return null;
long roundedVal = Math.round(value * 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 {" +
" fill-color: #333;" +
" arrow-size: 6px,3px;" +
"}" +
"edge.shipment {" +
" fill-color: #999;" +
" arrow-size: 6px,3px;" +
"}" ;
public static enum Label { "edge {" +
NO_LABEL, ID, JOB_NAME, ARRIVAL_TIME, DEPARTURE_TIME, ACTIVITY " fill-color: #333;" +
} " arrow-size: 6px,3px;" +
"}" +
private static class Center { "edge.shipment {" +
final double x; " fill-color: #999;" +
final double y; " arrow-size: 6px,3px;" +
"}";
public Center(double x, double y) {
super();
this.x = x;
this.y = y;
}
}
private Label label = Label.NO_LABEL; public static enum Label {
NO_LABEL, ID, JOB_NAME, ARRIVAL_TIME, DEPARTURE_TIME, ACTIVITY
}
private long renderDelay_in_ms = 0; private static class Center {
final double x;
final double y;
private boolean renderShipments = false; public Center(double x, double y) {
super();
private Center center; this.x = x;
this.y = y;
}
private VehicleRoutingProblem vrp; }
private VehicleRoutingProblemSolution solution; private Label label = Label.NO_LABEL;
private double zoomFactor; private long renderDelay_in_ms = 0;
private double scaling = 1.0; private boolean renderShipments = false;
private Center center;
private VehicleRoutingProblem vrp;
private VehicleRoutingProblemSolution solution;
private double zoomFactor;
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){
this.scaling=factor;
return this;
}
/** public GraphStreamViewer setGraphStreamFrameScalingFactor(double factor) {
* Sets the camera-view. Center describes the center-focus of the camera and zoomFactor its this.scaling = factor;
* zoomFactor. return this;
* }
* <p>a zoomFactor < 1 zooms in and > 1 out.
* /**
* @param centerX x coordinate of center * Sets the camera-view. Center describes the center-focus of the camera and zoomFactor its
* @param centerY y coordinate of center * zoomFactor.
* @param zoomFactor zoom factor * <p/>
* @return the viewer * <p>a zoomFactor < 1 zooms in and > 1 out.
*/ *
public GraphStreamViewer setCameraView(double centerX, double centerY, double zoomFactor){ * @param centerX x coordinate of center
center = new Center(centerX,centerY); * @param centerY y coordinate of center
this.zoomFactor = zoomFactor; * @param zoomFactor zoom factor
return this; * @return the viewer
} */
public GraphStreamViewer setCameraView(double centerX, double centerY, double zoomFactor) {
public void display(){ center = new Center(centerX, centerY);
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer"); this.zoomFactor = zoomFactor;
return this;
}
public void display() {
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,204 +414,202 @@ 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());
vehVal.setFont(font); vehVal.setFont(font);
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();
subpanel.add(jobs); subpanel.add(jobs);
subpanel.add(nJobs); subpanel.add(nJobs);
subpanel.add(emptyLabel1); subpanel.add(emptyLabel1);
subpanel.add(costs); subpanel.add(costs);
subpanel.add(costsVal); subpanel.add(costsVal);
JLabel emptyLabel2 = createEmptyLabel(); JLabel emptyLabel2 = createEmptyLabel();
subpanel.add(emptyLabel2); subpanel.add(emptyLabel2);
subpanel.add(vehicles); subpanel.add(vehicles);
subpanel.add(vehVal); subpanel.add(vehVal);
panel.add(subpanel); panel.add(subpanel);
return panel;
}
private Integer getNoRoutes() { return panel;
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())){
Node vehicleEnd = g.addNode(makeId(vehicle.getId(),vehicle.getEndLocation().getId()));
if(label.equals(Label.ID)) vehicleEnd.addAttribute("ui.label", "depot");
vehicleEnd.addAttribute("x", vehicle.getEndLocation().getCoordinate().getX());
vehicleEnd.addAttribute("y", vehicle.getEndLocation().getCoordinate().getY());
vehicleEnd.setAttribute("ui.class", "depot");
}
}
private void renderRoute(Graph g, VehicleRoute route, int routeId, long renderDelay_in_ms, Label label) { if (!vehicle.getStartLocation().getId().equals(vehicle.getEndLocation().getId())) {
int vehicle_edgeId = 1; Node vehicleEnd = g.addNode(makeId(vehicle.getId(), vehicle.getEndLocation().getId()));
String prevIdentifier = makeId(route.getVehicle().getId(),route.getVehicle().getStartLocation().getId()); if (label.equals(Label.ID)) vehicleEnd.addAttribute("ui.label", "depot");
if(label.equals(Label.ACTIVITY) || label.equals(Label.JOB_NAME)){ vehicleEnd.addAttribute("x", vehicle.getEndLocation().getCoordinate().getX());
Node n = g.getNode(prevIdentifier); vehicleEnd.addAttribute("y", vehicle.getEndLocation().getCoordinate().getY());
n.addAttribute("ui.label", "start"); vehicleEnd.setAttribute("ui.class", "depot");
}
for(TourActivity act : route.getActivities()){ }
}
private void renderRoute(Graph g, VehicleRoute route, int routeId, long renderDelay_in_ms, Label label) {
int vehicle_edgeId = 1;
String prevIdentifier = makeId(route.getVehicle().getId(), route.getVehicle().getStartLocation().getId());
if (label.equals(Label.ACTIVITY) || label.equals(Label.JOB_NAME)) {
Node n = g.getNode(prevIdentifier);
n.addAttribute("ui.label", "start");
}
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

@ -1,28 +1,28 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.analysis.toolbox; package jsprit.analysis.toolbox;
@ -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 double ran;
private double startTime;
@Override
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
reset();
start();
}
public double getCompTimeInSeconds(){
return (ran)/1000.0;
}
@Override private static Logger log = LogManager.getLogger(StopWatch.class);
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
stop(); private double ran;
log.info("computation time [in sec]: " + getCompTimeInSeconds());
} private double startTime;
public void stop(){
ran += System.currentTimeMillis() - startTime; @Override
} public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
reset();
public void start(){ start();
startTime = System.currentTimeMillis(); }
}
public double getCompTimeInSeconds() {
public void reset(){ return (ran) / 1000.0;
startTime = 0; }
ran = 0;
} @Override
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
@Override stop();
public String toString() { log.info("computation time [in sec]: " + getCompTimeInSeconds());
return "stopWatch: " + getCompTimeInSeconds() + " sec"; }
}
public void stop() {
ran += System.currentTimeMillis() - startTime;
}
public void start() {
startTime = System.currentTimeMillis();
}
public void reset() {
startTime = 0;
ran = 0;
}
@Override
public String toString() {
return "stopWatch: " + getCompTimeInSeconds() + " sec";
}
public double getCurrTimeInSeconds() {
return (System.currentTimeMillis() - startTime) / 1000.0;
}
public double getCurrTimeInSeconds() {
return (System.currentTimeMillis()-startTime)/1000.0;
}
} }

View file

@ -1,18 +1,18 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
@ -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(){ public JFreeChart build() {
XYSeriesCollection collection = new XYSeriesCollection(); XYSeriesCollection collection = new XYSeriesCollection();
for(XYSeries s : seriesMap.values()){ for (XYSeries s : seriesMap.values()) {
collection.addSeries(s); collection.addSeries(s);
} }
JFreeChart chart = ChartFactory.createXYLineChart(chartName, xDomain, yDomain, collection, PlotOrientation.VERTICAL, true, true, false); JFreeChart chart = ChartFactory.createXYLineChart(chartName, xDomain, yDomain, collection, PlotOrientation.VERTICAL, true, true, false);
XYPlot plot = chart.getXYPlot(); XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.WHITE); plot.setBackgroundPaint(Color.WHITE);
plot.setDomainGridlinePaint(Color.LIGHT_GRAY); plot.setDomainGridlinePaint(Color.LIGHT_GRAY);
plot.setRangeGridlinePaint(Color.LIGHT_GRAY); plot.setRangeGridlinePaint(Color.LIGHT_GRAY);
return chart; return chart;
} }
} }

View file

@ -1,25 +1,25 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
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

@ -1,259 +1,256 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
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) { }
this.filename = filename;
}
@Override @Override
public void write(Collection<BenchmarkResult> results) { public void write(Collection<BenchmarkResult> results) {
try {
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());
writer.write(openRow() + newline());
writer.write(head("") + newline());
writer.write(head("") + newline());
writer.write(head("") + newline());
writer.write(head("best") + newline());
writer.write(head("avg") + newline());
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_avg_time = 0.0;
double sum_best_result = 0.0;
double sum_avg_result = 0.0;
double sum_worst_result = 0.0;
double sum_dev_result = 0.0;
double sum_best_veh = 0.0;
double sum_avg_veh = 0.0;
double sum_worst_veh = 0.0;
double sum_dev_veh = 0.0;
Integer runs = null;
Double sum_res_star=null;
Double sum_veh_star=null;
for(BenchmarkResult result : results){
if(runs==null) runs=result.runs;
writer.write(openRow() + newline());
writer.write(date(result.instance.name) + newline());
writer.write(date(Integer.valueOf(result.runs).toString()) + newline());
Double avg_time = round(result.getTimesStats().getMean(),2);
writer.write(date(Double.valueOf(avg_time).toString()) + newline());
//bestRes
Double best_result = round(result.getResultStats().getMin(),2);
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());
sum_avg_time+=avg_time;
sum_best_result+=best_result;
sum_avg_result+=avg_result;
sum_worst_result+=worst_result;
sum_dev_result+=std_result;
sum_best_veh+=best_vehicle;
sum_avg_veh+=avg_vehicle;
sum_worst_veh+=worst_vehicle;
sum_dev_veh+=std_vehicle;
if(result.instance.bestKnownResult != null){
if(sum_res_star==null) sum_res_star=result.instance.bestKnownResult;
else sum_res_star+=result.instance.bestKnownResult;
}
if(result.instance.bestKnownVehicles != null){
if(sum_veh_star==null) sum_veh_star=result.instance.bestKnownVehicles;
else sum_veh_star+=result.instance.bestKnownVehicles;
}
}
writer.write(openRow() + newline());
writer.write(date("&Oslash;") + newline());
writer.write(date(""+runs) + newline());
Double average_time = round(sum_avg_time/(double)results.size(),2);
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(openTable() + 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(Double.valueOf(average_result).toString(),"align=\"right\"") + newline());
writer.write(date(Double.valueOf(average_vehicles).toString(),"align=\"right\"") + newline());
if(delta_res != null){
writer.write(date(Double.valueOf(round(delta_res,2)).toString(),"align=\"right\"") + newline());
}else writer.write(date("n.a.") + newline());
if(delta_veh != null){
writer.write(date(Double.valueOf(round(delta_veh,2)).toString(),"align=\"right\"") + newline());
}else writer.write(date("n.a.") + newline());
writer.write(closeRow() + newline());
writer.write(closeTable() + newline());
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String head(String string, int i) {
return "<th colspan=\""+i+"\">"+string+"</th>";
}
private Double round(Double value, int i) { try {
if(value==null) return null; BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filename)));
long roundedVal = Math.round(value*Math.pow(10, i)); writer.write(openTable() + newline());
return (double)roundedVal/(double)(Math.pow(10, i)); //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());
private String head(String head) { writer.write(openRow() + newline());
return "<th>"+head+"</th>"; writer.write(head("") + newline());
} writer.write(head("") + newline());
writer.write(head("") + newline());
writer.write(head("best") + newline());
writer.write(head("avg") + newline());
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());
private String closeTable() { //data
return "</table>"; double sum_avg_time = 0.0;
} double sum_best_result = 0.0;
double sum_avg_result = 0.0;
double sum_worst_result = 0.0;
double sum_dev_result = 0.0;
private String openTable() { double sum_best_veh = 0.0;
return "<table>"; double sum_avg_veh = 0.0;
} double sum_worst_veh = 0.0;
double sum_dev_veh = 0.0;
private String closeRow() { Integer runs = null;
return "</tr>"; Double sum_res_star = null;
} Double sum_veh_star = null;
private String date(String date) { for (BenchmarkResult result : results) {
return "<td>"+date+"</td>"; if (runs == null) runs = result.runs;
} writer.write(openRow() + newline());
writer.write(date(result.instance.name) + newline());
private String date(String date, String metaData) { writer.write(date(Integer.valueOf(result.runs).toString()) + newline());
return "<td " + metaData + ">"+date+"</td>";
}
private String newline() { Double avg_time = round(result.getTimesStats().getMean(), 2);
return "\n"; writer.write(date(Double.valueOf(avg_time).toString()) + newline());
} //bestRes
Double best_result = round(result.getResultStats().getMin(), 2);
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());
private String openRow() { sum_avg_time += avg_time;
return "<tr>"; sum_best_result += best_result;
} sum_avg_result += avg_result;
sum_worst_result += worst_result;
sum_dev_result += std_result;
sum_best_veh += best_vehicle;
sum_avg_veh += avg_vehicle;
sum_worst_veh += worst_vehicle;
sum_dev_veh += std_vehicle;
if (result.instance.bestKnownResult != null) {
if (sum_res_star == null) sum_res_star = result.instance.bestKnownResult;
else sum_res_star += result.instance.bestKnownResult;
}
if (result.instance.bestKnownVehicles != null) {
if (sum_veh_star == null) sum_veh_star = result.instance.bestKnownVehicles;
else sum_veh_star += result.instance.bestKnownVehicles;
}
}
writer.write(openRow() + newline());
writer.write(date("&Oslash;") + newline());
writer.write(date("" + runs) + newline());
Double average_time = round(sum_avg_time / (double) results.size(), 2);
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(openTable() + 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(Double.valueOf(average_result).toString(), "align=\"right\"") + newline());
writer.write(date(Double.valueOf(average_vehicles).toString(), "align=\"right\"") + newline());
if (delta_res != null) {
writer.write(date(Double.valueOf(round(delta_res, 2)).toString(), "align=\"right\"") + newline());
} else writer.write(date("n.a.") + newline());
if (delta_veh != null) {
writer.write(date(Double.valueOf(round(delta_veh, 2)).toString(), "align=\"right\"") + newline());
} else writer.write(date("n.a.") + newline());
writer.write(closeRow() + newline());
writer.write(closeTable() + newline());
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String head(String string, int i) {
return "<th colspan=\"" + i + "\">" + string + "</th>";
}
private Double round(Double value, int i) {
if (value == null) return null;
long roundedVal = Math.round(value * Math.pow(10, i));
return (double) roundedVal / (double) (Math.pow(10, i));
}
private String head(String head) {
return "<th>" + head + "</th>";
}
private String closeTable() {
return "</table>";
}
private String openTable() {
return "<table>";
}
private String closeRow() {
return "</tr>";
}
private String date(String date) {
return "<td>" + date + "</td>";
}
private String date(String date, String metaData) {
return "<td " + metaData + ">" + date + "</td>";
}
private String newline() {
return "\n";
}
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>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.9</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
<dependency> <dependencies>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId> <dependency>
<version>3.4</version> <groupId>org.apache.commons</groupId>
</dependency> <artifactId>commons-math</artifactId>
<version>2.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.9</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<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>
</dependencies>
</project> </project>

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
@ -36,29 +36,29 @@ 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) {
ArrayList<Job> jobs = new ArrayList<Job>(vrp.getJobs().values()); ArrayList<Job> jobs = new ArrayList<Job>(vrp.getJobs().values());

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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -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) {
super();
this.fleetManager = fleetManager;
}
@Override public RemoveEmptyVehicles(VehicleFleetManager fleetManager) {
public String toString() { super();
return "[name=removeEmptyVehicles]"; this.fleetManager = fleetManager;
} }
@Override @Override
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) { public String toString() {
List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes); return "[name=removeEmptyVehicles]";
for(VehicleRoute route : routes){ }
if(route.isEmpty()) {
fleetManager.unlock(route.getVehicle()); @Override
vehicleRoutes.remove(route); public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
} List<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
} for (VehicleRoute route : routes) {
} if (route.isEmpty()) {
fleetManager.unlock(route.getVehicle());
vehicleRoutes.remove(route);
}
}
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -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) {
super();
this.vehicleFleetManager = vehicleFleetManager;
}
@Override public ResetAndIniFleetManager(VehicleFleetManager vehicleFleetManager) {
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) { super();
vehicleFleetManager.unlockAll(); this.vehicleFleetManager = vehicleFleetManager;
Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes); }
for(VehicleRoute route : routes){
vehicleFleetManager.lock(route.getVehicle());
}
}
@Override @Override
public String toString() { public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
return "[name=resetAndIniFleetManager]"; vehicleFleetManager.unlockAll();
} Collection<VehicleRoute> routes = new ArrayList<VehicleRoute>(vehicleRoutes);
for (VehicleRoute route : routes) {
vehicleFleetManager.lock(route.getVehicle());
}
}
@Override
public String toString() {
return "[name=resetAndIniFleetManager]";
}
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -31,64 +31,66 @@ import java.util.Collections;
public class SearchStrategy { public class SearchStrategy {
public static class DiscoveredSolution {
private VehicleRoutingProblemSolution solution; public static class DiscoveredSolution {
private boolean accepted; private VehicleRoutingProblemSolution solution;
private String strategyId; private boolean accepted;
public DiscoveredSolution(VehicleRoutingProblemSolution solution, boolean accepted, String strategyId) {
super();
this.solution = solution;
this.accepted = accepted;
this.strategyId = strategyId;
}
public VehicleRoutingProblemSolution getSolution() { private String strategyId;
return solution;
}
public boolean isAccepted() { public DiscoveredSolution(VehicleRoutingProblemSolution solution, boolean accepted, String strategyId) {
return accepted; super();
} this.solution = solution;
this.accepted = accepted;
this.strategyId = strategyId;
}
@Deprecated public VehicleRoutingProblemSolution getSolution() {
return solution;
}
public boolean isAccepted() {
return accepted;
}
@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 final Collection<SearchStrategyModule> searchStrategyModules = new ArrayList<SearchStrategyModule>();
private final SolutionSelector solutionSelector;
private final SolutionCostCalculator solutionCostCalculator;
private final SolutionAcceptor solutionAcceptor; private static Logger logger = LogManager.getLogger(SearchStrategy.class);
private final Collection<SearchStrategyModule> searchStrategyModules = new ArrayList<SearchStrategyModule>();
private final SolutionSelector solutionSelector;
private final SolutionCostCalculator solutionCostCalculator;
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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -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<SearchStrategy> strategies = new ArrayList<SearchStrategy>();
private List<Double> weights = new ArrayList<Double>();
private Map<String, Integer> id2index = new HashMap<String,Integer>(); private List<SearchStrategyListener> searchStrategyListeners = new ArrayList<SearchStrategyListener>();
private Random random = RandomNumberGeneration.getRandom(); private List<SearchStrategy> strategies = new ArrayList<SearchStrategy>();
private double sumWeights = 0; private List<Double> weights = new ArrayList<Double>();
private Map<String, Integer> id2index = new HashMap<String, Integer>();
private Random random = RandomNumberGeneration.getRandom();
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){
searchStrategyListeners.add(strategyListener); public void addSearchStrategyListener(SearchStrategyListener strategyListener) {
} searchStrategyListeners.add(strategyListener);
}
public void addSearchStrategyModuleListener(SearchStrategyModuleListener moduleListener){
for(SearchStrategy s : strategies){ public void addSearchStrategyModuleListener(SearchStrategyModuleListener moduleListener) {
s.addModuleListener(moduleListener); for (SearchStrategy s : strategies) {
} s.addModuleListener(moduleListener);
} }
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -21,11 +21,11 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
public interface SearchStrategyModule { public interface SearchStrategyModule {
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution);
public String getName();
public void addModuleListener(SearchStrategyModuleListener moduleListener); public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution);
public String getName();
public void addModuleListener(SearchStrategyModuleListener moduleListener);
} }

View file

@ -1,18 +1,18 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
@ -29,39 +29,38 @@ import jsprit.core.problem.vehicle.Vehicle;
* Default objective function which is the sum of all fixed vehicle and variable * Default objective function which is the sum of all fixed vehicle and variable
* transportation costs, i.e. each is generated solution is evaluated according * transportation costs, i.e. each is generated solution is evaluated according
* this objective function. * this objective function.
*
* @author schroeder
* *
* @author schroeder
*/ */
public class VariablePlusFixedSolutionCostCalculatorFactory { public class VariablePlusFixedSolutionCostCalculatorFactory {
private RouteAndActivityStateGetter stateManager;
public VariablePlusFixedSolutionCostCalculatorFactory(RouteAndActivityStateGetter stateManager) {
super();
this.stateManager = stateManager;
}
public SolutionCostCalculator createCalculator(){ private RouteAndActivityStateGetter stateManager;
return new SolutionCostCalculator() {
@Override public VariablePlusFixedSolutionCostCalculatorFactory(RouteAndActivityStateGetter stateManager) {
public double getCosts(VehicleRoutingProblemSolution solution) { super();
double c = 0.0; this.stateManager = stateManager;
for(VehicleRoute r : solution.getRoutes()){ }
c += stateManager.getRouteState(r, InternalStates.COSTS, Double.class);
c += getFixedCosts(r.getVehicle()); public SolutionCostCalculator createCalculator() {
} return new SolutionCostCalculator() {
@Override
public double getCosts(VehicleRoutingProblemSolution solution) {
double c = 0.0;
for (VehicleRoute r : solution.getRoutes()) {
c += stateManager.getRouteState(r, InternalStates.COSTS, Double.class);
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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -34,9 +34,8 @@ 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 {
@ -44,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;
} }
} }
@ -60,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,63 +100,63 @@ public class VehicleRoutingAlgorithm {
private TerminationManager terminationManager = new TerminationManager(); private TerminationManager terminationManager = new TerminationManager();
private VehicleRoutingProblemSolution bestEver = null; private VehicleRoutingProblemSolution bestEver = null;
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, SearchStrategyManager searchStrategyManager) {
super();
this.problem = problem;
this.searchStrategyManager = searchStrategyManager;
initialSolutions = new ArrayList<VehicleRoutingProblemSolution>();
}
public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> initialSolutions, SearchStrategyManager searchStrategyManager) { public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, SearchStrategyManager searchStrategyManager) {
super(); super();
this.problem = problem; this.problem = problem;
this.searchStrategyManager = searchStrategyManager; this.searchStrategyManager = searchStrategyManager;
this.initialSolutions = initialSolutions; initialSolutions = new ArrayList<VehicleRoutingProblemSolution>();
} }
/** public VehicleRoutingAlgorithm(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> initialSolutions, SearchStrategyManager searchStrategyManager) {
* Adds solution to the collection of initial solutions. super();
* this.problem = problem;
* @param solution the solution to be added this.searchStrategyManager = searchStrategyManager;
*/ this.initialSolutions = initialSolutions;
public void addInitialSolution(VehicleRoutingProblemSolution solution){ }
/**
* Adds solution to the collection of initial solutions.
*
* @param solution the solution to be added
*/
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
@ -165,133 +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);
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 " + noIterationsThisAlgoIsRunning + " iterations");
addBestEver(solutions);
algorithmEnds(problem, solutions);
logger.info("took " + ((System.currentTimeMillis()-now)/1000.0) + " seconds");
return solutions;
}
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 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){
algoListeners.addListener(l);
if(l instanceof SearchStrategyListener) searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l);
if(l instanceof SearchStrategyModuleListener) searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l);
}
private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void addListener(VehicleRoutingAlgorithmListener l) {
algoListeners.iterationEnds(i,problem, solutions); algoListeners.addListener(l);
} if (l instanceof SearchStrategyListener)
searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l);
if (l instanceof SearchStrategyModuleListener)
searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l);
}
private void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { private void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
algoListeners.iterationStarts(i, problem, solutions); algoListeners.iterationEnds(i, problem, solutions);
} }
private void algorithmStarts(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { private void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
algoListeners.algorithmStarts(problem, this, solutions); algoListeners.iterationStarts(i, problem, solutions);
} }
private void algorithmStarts(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
algoListeners.algorithmStarts(problem, this, solutions);
}
/** /**
* Sets max number of iterations. * Sets max number of iterations.
@ -300,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

@ -27,153 +27,151 @@ 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 final VehicleRoutingProblem vrp;
private SolutionCostCalculator solutionCostCalculator; private AlgorithmConfig algorithmConfig;
private StateManager stateManager; private final VehicleRoutingProblem vrp;
private boolean addCoreConstraints = false;
private boolean addDefaultCostCalculators = false;
private ConstraintManager constraintManager; private SolutionCostCalculator solutionCostCalculator;
private int nuOfThreads=0; private StateManager stateManager;
/** private boolean addCoreConstraints = false;
* Constructs the builder with the problem and an algorithmConfigFile. Latter is to configure and specify the ruin-and-recreate meta-heuristic.
* private boolean addDefaultCostCalculators = false;
* @param problem to solve
* @param algorithmConfig config file of VehicleRoutingAlgorithm private ConstraintManager constraintManager;
*/
public VehicleRoutingAlgorithmBuilder(VehicleRoutingProblem problem, String algorithmConfig) { private int nuOfThreads = 0;
this.vrp=problem;
this.algorithmConfigFile=algorithmConfig; /**
this.algorithmConfig=null; * 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
/**
* 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.
*
* @param nuOfThreads to be operated
*/
public void setNuOfThreads(int nuOfThreads){
this.nuOfThreads=nuOfThreads;
}
/** /**
* Builds and returns the algorithm. * Sets state- and constraintManager.
* *
* <p>If algorithmConfigFile is set, it reads the configuration. * @param stateManager that memorizes your states
* * @param constraintManager that manages your constraints
* @return the algorithm * @see StateManager
*/ * @see ConstraintManager
public VehicleRoutingAlgorithm build() { */
if(stateManager == null) stateManager = new StateManager(vrp); public void setStateAndConstraintManager(StateManager stateManager, ConstraintManager constraintManager) {
if(constraintManager == null) constraintManager = new ConstraintManager(vrp,stateManager); this.stateManager = stateManager;
//add core updater this.constraintManager = constraintManager;
stateManager.addStateUpdater(new UpdateEndLocationIfRouteIsOpen()); }
/**
* Sets nuOfThreads.
*
* @param nuOfThreads to be operated
*/
public void setNuOfThreads(int nuOfThreads) {
this.nuOfThreads = nuOfThreads;
}
/**
* Builds and returns the algorithm.
* <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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm; package jsprit.core.algorithm;
@ -20,7 +20,7 @@ import jsprit.core.problem.VehicleRoutingProblem;
public interface VehicleRoutingAlgorithmFactory { public interface VehicleRoutingAlgorithmFactory {
public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp); public VehicleRoutingAlgorithm createAlgorithm(VehicleRoutingProblem vrp);
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.acceptor; package jsprit.core.algorithm.acceptor;
@ -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){
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]";
}
public AcceptNewRemoveFirst(int 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/>
* <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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.acceptor; package jsprit.core.algorithm.acceptor;
@ -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 int nOfTotalIterations = 1000;
private int currentIteration = 0;
private double initialThreshold = 0.0;
private final int nOfRandomWalks; private final double alpha;
private final int solutionMemory; private int nOfTotalIterations = 1000;
private int currentIteration = 0;
public ExperimentalSchrimpfAcceptance(int solutionMemory, double alpha, int nOfWarmupIterations) {
super(); private double initialThreshold = 0.0;
this.alpha = alpha;
this.nOfRandomWalks = nOfWarmupIterations; private final int nOfRandomWalks;
this.solutionMemory = solutionMemory;
logger.info("initialise " + this); private final int solutionMemory;
}
@Override public ExperimentalSchrimpfAcceptance(int solutionMemory, double alpha, int nOfWarmupIterations) {
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) { super();
boolean solutionAccepted = false; this.alpha = alpha;
if (solutions.size() < solutionMemory) { this.nOfRandomWalks = nOfWarmupIterations;
solutions.add(newSolution); this.solutionMemory = solutionMemory;
solutionAccepted = true; logger.info("initialise {}", this);
} 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
public String toString() {
return "[name=schrimpfAcceptanceFunction][alpha="+alpha+"][warmup=" + nOfRandomWalks + "]";
}
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 boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
reset(); boolean solutionAccepted = false;
logger.info("---------------------------------------------------------------------"); if (solutions.size() < solutionMemory) {
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold"); solutions.add(newSolution);
logger.info("start random-walk (see randomWalk.xml)"); solutionAccepted = true;
double now = System.currentTimeMillis(); } else {
this.nOfTotalIterations = algorithm.getMaxIterations(); 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
public String toString() {
return "[name=schrimpfAcceptanceFunction][alpha=" + alpha + "][warmup=" + nOfRandomWalks + "]";
}
private double getThreshold(int iteration) {
double scheduleVariable = (double) iteration / (double) nOfTotalIterations;
// logger.debug("iter={} totalIter={} scheduling={}", iteration, nOfTotalIterations, scheduleVariable);
double currentThreshold = initialThreshold * Math.exp(-Math.log(2) * scheduleVariable / alpha);
return currentThreshold;
}
@Override
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
reset();
logger.info("---------------------------------------------------------------------");
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
logger.info("start random-walk (see randomWalk.xml)");
double now = System.currentTimeMillis();
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");
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
vra.setMaxIterations(nOfRandomWalks);
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
@Override
public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
double result = Solutions.bestOf(solutions).getCost();
// logger.info("result="+result);
results[iteration-1] = result;
}
});
vra.searchSolutions();
StandardDeviation dev = new StandardDeviation();
double standardDeviation = dev.evaluate(results);
initialThreshold = standardDeviation / 2;
logger.info("warmup done");
logger.info("total time: " + ((System.currentTimeMillis()-now)/1000.0) + "s");
logger.info("initial threshold: " + initialThreshold);
logger.info("---------------------------------------------------------------------");
}
private void reset() { URL resource = Resource.getAsURL("randomWalk.xml");
currentIteration = 0; AlgorithmConfig algorithmConfig = new AlgorithmConfig();
} new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
vra.setMaxIterations(nOfRandomWalks);
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
@Override @Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
currentIteration = i; double result = Solutions.bestOf(solutions).getCost();
} // logger.info("result={}", result);
results[iteration - 1] = result;
}
});
vra.searchSolutions();
StandardDeviation dev = new StandardDeviation();
double standardDeviation = dev.evaluate(results);
initialThreshold = standardDeviation / 2;
logger.info("warmup done");
logger.info("total time: {}s", ((System.currentTimeMillis() - now) / 1000.0));
logger.info("initial threshold: {}", initialThreshold);
logger.info("---------------------------------------------------------------------");
}
private void reset() {
currentIteration = 0;
}
@Override
public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
currentIteration = i;
}
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.acceptor; package jsprit.core.algorithm.acceptor;
@ -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){
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]";
}
public GreedyAcceptance(int 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/>
* <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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.acceptor; package jsprit.core.algorithm.acceptor;
@ -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){
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]";
}
public GreedyAcceptance_minVehFirst(int 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/>
* <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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.acceptor; package jsprit.core.algorithm.acceptor;
@ -29,24 +29,24 @@ 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
* (just copy and paste it into Wolfram's console: <a href="https://www.wolframalpha.com/">www.wolframalpha.com</a>): * (just copy and paste it into Wolfram's console: <a href="https://www.wolframalpha.com/">www.wolframalpha.com</a>):
* <p>100. * exp(-log(2)* (x/1000) / 0.1) (x from 0 to 1000) (y from 0 to 100) * <p>100. * exp(-log(2)* (x/1000) / 0.1) (x from 0 to 1000) (y from 0 to 100)
* <p>with <br> * <p>with <br>
@ -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 int maxIterations = 1000;
private int currentIteration = 0;
private double initialThreshold = 0.0;
private final int solutionMemory;
private final double alpha;
public SchrimpfAcceptance(int solutionMemory, double alpha){
this.alpha = alpha;
this.solutionMemory = solutionMemory;
logger.debug("initialise " + this);
}
@Override private int maxIterations = 1000;
public boolean acceptSolution(Collection<VehicleRoutingProblemSolution> solutions, VehicleRoutingProblemSolution newSolution) {
boolean solutionAccepted = false; private int currentIteration = 0;
if (solutions.size() < solutionMemory) {
solutions.add(newSolution); private double initialThreshold = 0.0;
solutionAccepted = true;
} else { private final int solutionMemory;
VehicleRoutingProblemSolution worst = null;
double threshold = getThreshold(currentIteration);
for(VehicleRoutingProblemSolution solutionInMemory : solutions){ public SchrimpfAcceptance(int solutionMemory, double alpha) {
if(worst == null) worst = solutionInMemory; this.alpha = alpha;
else if(solutionInMemory.getCost() > worst.getCost()) worst = solutionInMemory; this.solutionMemory = solutionMemory;
} logger.debug("initialise {}", this);
if(worst == null){ }
@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 (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;
} @Override
} public String toString() {
return solutionAccepted; return "[name=SchrimpfAcceptance][alpha=" + alpha + "]";
} }
@Override private double getThreshold(int iteration) {
public String toString() { double scheduleVariable = (double) iteration / (double) maxIterations;
return "[name=SchrimpfAcceptance][alpha="+alpha+"]"; return initialThreshold * Math.exp(-1. * Math.log(2) * scheduleVariable / alpha);
} }
private double getThreshold(int iteration) {
double scheduleVariable = (double) iteration / (double) maxIterations;
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.
* <p>Note that if initial threshold has been set, automatic generation of initial threshold is disabled.
*
* @param initialThreshold the initialThreshold to set
*/
public void setInitialThreshold(double initialThreshold) {
this.initialThreshold = initialThreshold;
}
@Override /**
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) { * Sets initial threshold.
* <p>Note that if initial threshold has been set, automatic generation of initial threshold is disabled.
*
* @param initialThreshold the initialThreshold to set
*/
public void setInitialThreshold(double initialThreshold) {
this.initialThreshold = initialThreshold;
}
@Override
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

@ -34,55 +34,55 @@ import java.net.URL;
import java.util.Collection; import java.util.Collection;
public class SchrimpfInitialThresholdGenerator implements AlgorithmStartsListener { public class SchrimpfInitialThresholdGenerator implements AlgorithmStartsListener {
private static Logger logger = LogManager.getLogger(SchrimpfInitialThresholdGenerator.class.getName());
private SchrimpfAcceptance schrimpfAcceptance;
private int nOfRandomWalks;
public SchrimpfInitialThresholdGenerator(SchrimpfAcceptance schrimpfAcceptance, int nOfRandomWalks) {
super();
this.schrimpfAcceptance = schrimpfAcceptance;
this.nOfRandomWalks = nOfRandomWalks;
}
@Override private static Logger logger = LogManager.getLogger(SchrimpfInitialThresholdGenerator.class.getName());
public void informAlgorithmStarts(VehicleRoutingProblem problem,VehicleRoutingAlgorithm algorithm,Collection<VehicleRoutingProblemSolution> solutions) {
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold"); private SchrimpfAcceptance schrimpfAcceptance;
double now = System.currentTimeMillis();
private int nOfRandomWalks;
public SchrimpfInitialThresholdGenerator(SchrimpfAcceptance schrimpfAcceptance, int nOfRandomWalks) {
super();
this.schrimpfAcceptance = schrimpfAcceptance;
this.nOfRandomWalks = nOfRandomWalks;
}
@Override
public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) {
logger.info("prepare schrimpfAcceptanceFunction, i.e. determine initial threshold");
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");
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
vra.setMaxIterations(nOfRandomWalks);
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
@Override
public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
double result = Solutions.bestOf(solutions).getCost();
// logger.info("result="+result);
results[iteration-1] = result;
}
});
vra.searchSolutions();
StandardDeviation dev = new StandardDeviation();
double standardDeviation = dev.evaluate(results);
double initialThreshold = standardDeviation / 2;
schrimpfAcceptance.setInitialThreshold(initialThreshold);
logger.info("took " + ((System.currentTimeMillis()-now)/1000.0) + " seconds"); URL resource = Resource.getAsURL("randomWalk.xml");
logger.debug("initial threshold: " + initialThreshold); AlgorithmConfig algorithmConfig = new AlgorithmConfig();
logger.info("---------------------------------------------------------------------"); new AlgorithmConfigXmlReader(algorithmConfig).read(resource);
} VehicleRoutingAlgorithm vra = VehicleRoutingAlgorithms.createAlgorithm(problem, algorithmConfig);
vra.setMaxIterations(nOfRandomWalks);
vra.getAlgorithmListeners().addListener(new IterationEndsListener() {
@Override
public void informIterationEnds(int iteration, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
double result = Solutions.bestOf(solutions).getCost();
// logger.info("result={}", result);
results[iteration - 1] = result;
}
});
vra.searchSolutions();
StandardDeviation dev = new StandardDeviation();
double standardDeviation = dev.evaluate(results);
double initialThreshold = standardDeviation / 2;
schrimpfAcceptance.setInitialThreshold(initialThreshold);
logger.info("took {} seconds", ((System.currentTimeMillis() - now) / 1000.0));
logger.debug("initial threshold: {}", initialThreshold);
logger.info("---------------------------------------------------------------------");
}
} }

View file

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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.box; package jsprit.core.algorithm.box;
@ -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

@ -18,8 +18,8 @@ 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;
@ -44,12 +44,12 @@ class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsList
//@ToDo refactor determining max costs to allow skipping this //@ToDo refactor determining max costs to allow skipping this
private void determineMaxCosts(VehicleRoutingProblem vrp) { private void determineMaxCosts(VehicleRoutingProblem vrp) {
double max = 0.; double max = 0.;
for(Job i : vrp.getJobs().values()){ for (Job i : vrp.getJobs().values()) {
List<Location> fromLocations = getLocations(i); List<Location> fromLocations = getLocations(i);
for(Job j : vrp.getJobs().values()){ for (Job j : vrp.getJobs().values()) {
List<Location> toLocations = getLocations(j); List<Location> toLocations = getLocations(j);
for(Location iLoc : fromLocations){ for (Location iLoc : fromLocations) {
for(Location jLoc : toLocations) { for (Location jLoc : toLocations) {
max = Math.max(max, vrp.getTransportCosts().getTransportCost(iLoc, jLoc, 0, null, vrp.getVehicles().iterator().next())); max = Math.max(max, vrp.getTransportCosts().getTransportCost(iLoc, jLoc, 0, null, vrp.getVehicles().iterator().next()));
} }
} }
@ -60,10 +60,9 @@ class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsList
private List<Location> getLocations(Job j) { private List<Location> getLocations(Job j) {
List<Location> locs = new ArrayList<Location>(); List<Location> locs = new ArrayList<Location>();
if(j instanceof Service) { if (j instanceof Service) {
locs.add(((Service) j).getLocation()); locs.add(((Service) j).getLocation());
} } else if (j instanceof Shipment) {
else if(j instanceof Shipment){
locs.add(((Shipment) j).getPickupLocation()); locs.add(((Shipment) j).getPickupLocation());
locs.add(((Shipment) j).getDeliveryLocation()); locs.add(((Shipment) j).getDeliveryLocation());
} }
@ -72,15 +71,14 @@ class InsertionNoiseMaker implements SoftActivityConstraint, IterationStartsList
@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;

View file

@ -40,11 +40,11 @@ public class Jsprit {
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 +63,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 +75,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"),
@ -97,17 +97,17 @@ public class Jsprit {
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 +131,53 @@ public class Jsprit {
private Random random = RandomNumberGeneration.newInstance(); private Random random = RandomNumberGeneration.newInstance();
public static Builder newInstance(VehicleRoutingProblem vrp){ 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.CONSTRUCTION.toString(), Construction.REGRET_INSERTION.toString());
return defaults; return defaults;
} }
@ -188,23 +188,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 +224,7 @@ public class Jsprit {
return this; return this;
} }
public VehicleRoutingAlgorithm buildAlgorithm(){ public VehicleRoutingAlgorithm buildAlgorithm() {
return new Jsprit(this).create(vrp); return new Jsprit(this).create(vrp);
} }
@ -245,13 +245,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;
@ -293,18 +295,17 @@ public class Jsprit {
this.random = builder.random; this.random = builder.random;
} }
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 fm = new FiniteFleetManagerFactory(vrp.getVehicles()).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);
} }
double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString())); double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString()));
@ -316,36 +317,36 @@ public class Jsprit {
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); 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,52 +354,50 @@ 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(); * noiseMaker.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 RegretInsertion.DefaultScorer scorer;
if(noThreads == null){ if (noThreads == null) {
noThreads = toInteger(getProperty(Parameter.THREADS.toString())); noThreads = toInteger(getProperty(Parameter.THREADS.toString()));
} }
if(noThreads > 1){ if (noThreads > 1) {
if(es == null){ if (es == null) {
setupExecutorInternally = true; setupExecutorInternally = true;
es = Executors.newFixedThreadPool(noThreads); es = Executors.newFixedThreadPool(noThreads);
} }
} }
if(es != null) { 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())))
.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) 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())))
.build(); .build();
scorer = getRegretScorer(vrp); scorer = getRegretScorer(vrp);
regretInsertion.setScoringFunction(scorer); regretInsertion.setScoringFunction(scorer);
regret = regretInsertion; regret = regretInsertion;
@ -406,30 +405,29 @@ public class Jsprit {
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(); .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(); .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);
} }
@ -437,48 +435,47 @@ public class Jsprit {
}; };
SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, noiseMaker.maxCosts); SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp, noiseMaker.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);
} }
@ -504,7 +501,7 @@ public class Jsprit {
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 +511,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 +523,7 @@ public class Jsprit {
} }
} }
String getProperty(String key){ String getProperty(String key) {
return properties.getProperty(key); return properties.getProperty(key);
} }
@ -543,21 +540,21 @@ 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;
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()); 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()); 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());
} }
costs += solution.getUnassignedJobs().size() * maxCosts * 2; costs += solution.getUnassignedJobs().size() * maxCosts * 2;
return costs; return costs;

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.box; package jsprit.core.algorithm.box;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.io; package jsprit.core.algorithm.io;
@ -19,15 +19,15 @@ package jsprit.core.algorithm.io;
import org.apache.commons.configuration.XMLConfiguration; import org.apache.commons.configuration.XMLConfiguration;
public class AlgorithmConfig { public class AlgorithmConfig {
private XMLConfiguration xmlConfig;
public AlgorithmConfig(){
xmlConfig = new XMLConfiguration();
}
public XMLConfiguration getXMLConfiguration(){ private XMLConfiguration xmlConfig;
return xmlConfig;
} public AlgorithmConfig() {
xmlConfig = new XMLConfiguration();
}
public XMLConfiguration getXMLConfiguration() {
return xmlConfig;
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.io; package jsprit.core.algorithm.io;
@ -30,65 +30,64 @@ import java.net.URL;
public class AlgorithmConfigXmlReader { public class AlgorithmConfigXmlReader {
private static Logger log = LogManager.getLogger(AlgorithmConfigXmlReader.class.getName());
private AlgorithmConfig algorithmConfig;
private boolean schemaValidation = true;
/**
* @param schemaValidation the schemaValidation to set
*/
public AlgorithmConfigXmlReader setSchemaValidation(boolean schemaValidation) {
this.schemaValidation = schemaValidation;
return this;
}
public AlgorithmConfigXmlReader(AlgorithmConfig algorithmConfig){ private static Logger log = LogManager.getLogger(AlgorithmConfigXmlReader.class.getName());
this.algorithmConfig = algorithmConfig;
}
public void read(URL url){
log.debug("read algorithm: " + url);
algorithmConfig.getXMLConfiguration().setURL(url);
algorithmConfig.getXMLConfiguration().setAttributeSplittingDisabled(true);
algorithmConfig.getXMLConfiguration().setDelimiterParsingDisabled(true);
if(schemaValidation){
final InputStream resource = Resource.getAsInputStream("algorithm_schema.xsd");
if(resource != null) {
EntityResolver resolver = new EntityResolver() {
@Override private AlgorithmConfig algorithmConfig;
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
{ private boolean schemaValidation = true;
InputSource is = new InputSource(resource);
return is; /**
} * @param schemaValidation the schemaValidation to set
} */
}; public AlgorithmConfigXmlReader setSchemaValidation(boolean schemaValidation) {
algorithmConfig.getXMLConfiguration().setEntityResolver(resolver); this.schemaValidation = schemaValidation;
algorithmConfig.getXMLConfiguration().setSchemaValidation(true); return this;
} }
else{
log.warn("cannot find schema-xsd file (algorithm_xml_schema.xsd). try to read xml without xml-file-validation."); public AlgorithmConfigXmlReader(AlgorithmConfig algorithmConfig) {
} this.algorithmConfig = algorithmConfig;
} }
try {
algorithmConfig.getXMLConfiguration().load(); public void read(URL url) {
} catch (ConfigurationException e) { log.debug("read algorithm: " + url);
log.error(e); algorithmConfig.getXMLConfiguration().setURL(url);
e.printStackTrace(); algorithmConfig.getXMLConfiguration().setAttributeSplittingDisabled(true);
System.exit(1); algorithmConfig.getXMLConfiguration().setDelimiterParsingDisabled(true);
}
} if (schemaValidation) {
final InputStream resource = Resource.getAsInputStream("algorithm_schema.xsd");
if (resource != null) {
public void read(String filename){ EntityResolver resolver = new EntityResolver() {
log.debug("read algorithm-config from file " + filename);
URL url = Resource.getAsURL(filename); @Override
read(url); public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
} {
InputSource is = new InputSource(resource);
return is;
}
}
};
algorithmConfig.getXMLConfiguration().setEntityResolver(resolver);
algorithmConfig.getXMLConfiguration().setSchemaValidation(true);
} else {
log.warn("cannot find schema-xsd file (algorithm_xml_schema.xsd). try to read xml without xml-file-validation.");
}
}
try {
algorithmConfig.getXMLConfiguration().load();
} catch (ConfigurationException e) {
log.error(e);
e.printStackTrace();
System.exit(1);
}
}
public void read(String filename) {
log.debug("read algorithm-config from file " + filename);
URL url = Resource.getAsURL(filename);
read(url);
}
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.io; package jsprit.core.algorithm.io;
@ -32,85 +32,83 @@ import java.util.concurrent.ExecutorService;
class InsertionFactory { class InsertionFactory {
private static Logger log = LogManager.getLogger(InsertionFactory.class.getName());
@SuppressWarnings("deprecation")
public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
VehicleFleetManager vehicleFleetManager, StateManager stateManager, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators){
if(config.containsKey("[@name]")){ private static Logger log = LogManager.getLogger(InsertionFactory.class.getName());
String insertionName = config.getString("[@name]");
if(!insertionName.equals("bestInsertion") && !insertionName.equals("regretInsertion")){ @SuppressWarnings("deprecation")
throw new IllegalStateException(insertionName + " is not supported. use either \"bestInsertion\" or \"regretInsertion\""); public static InsertionStrategy createInsertion(VehicleRoutingProblem vrp, HierarchicalConfiguration config,
} VehicleFleetManager vehicleFleetManager, StateManager stateManager, List<PrioritizedVRAListener> algorithmListeners, ExecutorService executorService, int nuOfThreads, ConstraintManager constraintManager, boolean addDefaultCostCalculators) {
if (config.containsKey("[@name]")) {
String insertionName = config.getString("[@name]");
if (!insertionName.equals("bestInsertion") && !insertionName.equals("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")){
} if (config.containsKey("level")) {
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>. " + String level = config.getString("level");
"if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file"); if (level.equals("local")) {
} iBuilder.setLocalLevel(addDefaultCostCalculators);
} } else if (level.equals("route")) {
String timeSliceString = config.getString("experimental[@timeSlice]"); int forwardLooking = 0;
String neighbors = config.getString("experimental[@neighboringSlices]"); int memory = 1;
if(timeSliceString != null && neighbors != null){ String forward = config.getString("level[@forwardLooking]");
iBuilder.experimentalTimeScheduler(Double.parseDouble(timeSliceString),Integer.parseInt(neighbors)); String mem = config.getString("level[@memory]");
} if (forward != null) forwardLooking = Integer.parseInt(forward);
String allowVehicleSwitch = config.getString("allowVehicleSwitch"); else
if(allowVehicleSwitch != null){ log.warn("parameter route[@forwardLooking] is missing. by default it is 0 which equals to local level");
iBuilder.setAllowVehicleSwitch(Boolean.parseBoolean(allowVehicleSwitch)); 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(insertionName.equals("regretInsertion")){ 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); iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET);
} }
return iBuilder.build(); return iBuilder.build();
} } else throw new IllegalStateException("cannot create insertionStrategy, since it has no name.");
else throw new IllegalStateException("cannot create insertionStrategy, since it has no name."); }
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
@ -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

@ -1,21 +1,21 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
public interface SearchStrategyListener extends VehicleRoutingAlgorithmListener{ public interface SearchStrategyListener extends VehicleRoutingAlgorithmListener {
} }

View file

@ -1,21 +1,21 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
public interface SearchStrategyModuleListener extends VehicleRoutingAlgorithmListener{ public interface SearchStrategyModuleListener extends VehicleRoutingAlgorithmListener {
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.listener; package jsprit.core.algorithm.listener;
@ -24,26 +24,27 @@ import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import java.util.*; import java.util.*;
public class VehicleRoutingAlgorithmListeners { public class VehicleRoutingAlgorithmListeners {
public static class PrioritizedVRAListener { public static class PrioritizedVRAListener {
Priority priority; Priority priority;
VehicleRoutingAlgorithmListener l; VehicleRoutingAlgorithmListener l;
public PrioritizedVRAListener(Priority priority, VehicleRoutingAlgorithmListener l) {
super(); public PrioritizedVRAListener(Priority priority, VehicleRoutingAlgorithmListener l) {
this.priority = priority; super();
this.l = l; this.priority = priority;
} this.l = l;
public Priority getPriority() { }
return priority;
} public Priority getPriority() {
public VehicleRoutingAlgorithmListener getListener() { return priority;
return l; }
}
public VehicleRoutingAlgorithmListener getListener() {
return l;
}
// @Override // @Override
// public int hashCode() { // public int hashCode() {
// final int prime = 31; // final int prime = 31;
@ -74,109 +75,106 @@ public class VehicleRoutingAlgorithmListeners {
// return false; // return false;
// return true; // return true;
// } // }
}
public enum Priority {
HIGH, MEDIUM, LOW
}
private TreeSet<PrioritizedVRAListener> algorithmListeners = new TreeSet<PrioritizedVRAListener>(new Comparator<PrioritizedVRAListener>() {
@Override }
public int compare(PrioritizedVRAListener o1, PrioritizedVRAListener o2) {
if(o1 == o2) return 0;
if(o1.getPriority() == Priority.HIGH && o2.getPriority() != Priority.HIGH){
return -1;
}
else if(o2.getPriority() == Priority.HIGH && o1.getPriority() != Priority.HIGH){
return 1;
}
else if(o1.getPriority() == Priority.MEDIUM && o2.getPriority() != Priority.MEDIUM){
return -1;
}
else if(o2.getPriority() == Priority.MEDIUM && o1.getPriority() != Priority.MEDIUM){
return 1;
}
return 1;
}
});
public Collection<VehicleRoutingAlgorithmListener> getAlgorithmListeners() {
List<VehicleRoutingAlgorithmListener> list = new ArrayList<VehicleRoutingAlgorithmListener>();
for(PrioritizedVRAListener l : algorithmListeners){
list.add(l.getListener());
}
return Collections.unmodifiableCollection(list);
}
public void remove(PrioritizedVRAListener listener){
boolean removed = algorithmListeners.remove(listener);
if(!removed){ throw new IllegalStateException("cannot remove listener"); }
}
public void addListener(VehicleRoutingAlgorithmListener listener, Priority priority){ public enum Priority {
algorithmListeners.add(new PrioritizedVRAListener(priority, listener)); HIGH, MEDIUM, LOW
} }
public void addListener(VehicleRoutingAlgorithmListener listener){
addListener(listener, Priority.LOW);
}
public void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
for(PrioritizedVRAListener l : algorithmListeners){
if(l.getListener() instanceof AlgorithmEndsListener){
((AlgorithmEndsListener)l.getListener()).informAlgorithmEnds(problem, solutions);
}
}
}
public void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
for(PrioritizedVRAListener l : algorithmListeners){
if(l.getListener() instanceof IterationEndsListener){
((IterationEndsListener)l.getListener()).informIterationEnds(i,problem, solutions);
}
}
}
private TreeSet<PrioritizedVRAListener> algorithmListeners = new TreeSet<PrioritizedVRAListener>(new Comparator<PrioritizedVRAListener>() {
public void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { @Override
for(PrioritizedVRAListener l : algorithmListeners){ public int compare(PrioritizedVRAListener o1, PrioritizedVRAListener o2) {
if(l.getListener() instanceof IterationStartsListener){ if (o1 == o2) return 0;
((IterationStartsListener)l.getListener()).informIterationStarts(i,problem, solutions); if (o1.getPriority() == Priority.HIGH && o2.getPriority() != Priority.HIGH) {
} return -1;
} } else if (o2.getPriority() == Priority.HIGH && o1.getPriority() != Priority.HIGH) {
} return 1;
} else if (o1.getPriority() == Priority.MEDIUM && o2.getPriority() != Priority.MEDIUM) {
return -1;
} else if (o2.getPriority() == Priority.MEDIUM && o1.getPriority() != Priority.MEDIUM) {
return 1;
}
return 1;
}
});
public void algorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection<VehicleRoutingProblemSolution> solutions) { public Collection<VehicleRoutingAlgorithmListener> getAlgorithmListeners() {
for(PrioritizedVRAListener l : algorithmListeners){ List<VehicleRoutingAlgorithmListener> list = new ArrayList<VehicleRoutingAlgorithmListener>();
if(l.getListener() instanceof AlgorithmStartsListener){ for (PrioritizedVRAListener l : algorithmListeners) {
((AlgorithmStartsListener)l.getListener()).informAlgorithmStarts(problem, algorithm, solutions); list.add(l.getListener());
} }
} return Collections.unmodifiableCollection(list);
} }
public void add(PrioritizedVRAListener l){ public void remove(PrioritizedVRAListener listener) {
algorithmListeners.add(l); boolean removed = algorithmListeners.remove(listener);
} if (!removed) {
throw new IllegalStateException("cannot remove listener");
public void addAll(Collection<PrioritizedVRAListener> algorithmListeners) { }
for(PrioritizedVRAListener l : algorithmListeners){ }
this.algorithmListeners.add(l);
}
}
public void selectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) { public void addListener(VehicleRoutingAlgorithmListener listener, Priority priority) {
for(PrioritizedVRAListener l : algorithmListeners){ algorithmListeners.add(new PrioritizedVRAListener(priority, listener));
if(l.getListener() instanceof StrategySelectedListener){ }
((StrategySelectedListener)l.getListener()).informSelectedStrategy(discoveredSolution, problem, solutions);
} public void addListener(VehicleRoutingAlgorithmListener listener) {
} addListener(listener, Priority.LOW);
} }
public void algorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
for (PrioritizedVRAListener l : algorithmListeners) {
if (l.getListener() instanceof AlgorithmEndsListener) {
((AlgorithmEndsListener) l.getListener()).informAlgorithmEnds(problem, solutions);
}
}
}
public void iterationEnds(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
for (PrioritizedVRAListener l : algorithmListeners) {
if (l.getListener() instanceof IterationEndsListener) {
((IterationEndsListener) l.getListener()).informIterationEnds(i, problem, solutions);
}
}
}
public void iterationStarts(int i, VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
for (PrioritizedVRAListener l : algorithmListeners) {
if (l.getListener() instanceof IterationStartsListener) {
((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 add(PrioritizedVRAListener l) {
algorithmListeners.add(l);
}
public void addAll(Collection<PrioritizedVRAListener> algorithmListeners) {
for (PrioritizedVRAListener l : algorithmListeners) {
this.algorithmListeners.add(l);
}
}
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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.module; package jsprit.core.algorithm.module;
@ -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 String moduleName;
public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) {
super();
this.insertion = insertion;
this.ruin = ruin;
this.moduleName = moduleName;
}
@Override private RuinStrategy ruin;
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
Collection<Job> ruinedJobs = ruin.ruin(vrpSolution.getRoutes()); private String moduleName;
public RuinAndRecreateModule(String moduleName, InsertionStrategy insertion, RuinStrategy ruin) {
super();
this.insertion = insertion;
this.ruin = ruin;
this.moduleName = moduleName;
}
@Override
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
Collection<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() { }
return insertion;
}
public RuinStrategy getRuin() { public InsertionStrategy getInsertion() {
return ruin; return insertion;
} }
public RuinStrategy getRuin() {
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
* *
@ -22,33 +21,35 @@ import jsprit.core.problem.misc.JobInsertionContext;
import jsprit.core.problem.solution.route.activity.TourActivity; import jsprit.core.problem.solution.route.activity.TourActivity;
public interface ActivityInsertionCostsCalculator { public interface ActivityInsertionCostsCalculator {
public class ActivityInsertionCosts {
private double additionalCosts;
private double additionalTime;
public ActivityInsertionCosts(double additionalCosts, double additionalTime) {
super();
this.additionalCosts = additionalCosts;
this.additionalTime = additionalTime;
}
/**
* @return the additionalCosts
*/
public double getAdditionalCosts() {
return additionalCosts;
}
/**
* @return the additionalTime
*/
public double getAdditionalTime() {
return additionalTime;
}
} public class ActivityInsertionCosts {
public double getCosts(JobInsertionContext iContext, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct); private double additionalCosts;
private double additionalTime;
public ActivityInsertionCosts(double additionalCosts, double additionalTime) {
super();
this.additionalCosts = additionalCosts;
this.additionalTime = additionalTime;
}
/**
* @return the additionalCosts
*/
public double getAdditionalCosts() {
return additionalCosts;
}
/**
* @return the additionalTime
*/
public double getAdditionalTime() {
return additionalTime;
}
}
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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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 VehicleRoutingActivityCosts activityCosts;
public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts actCosts) { private final VehicleRoutingTransportCosts routingCosts;
super();
this.routingCosts = routingCosts; private final VehicleRoutingActivityCosts activityCosts;
this.activityCosts = actCosts;
} public AuxilliaryCostCalculator(final VehicleRoutingTransportCosts routingCosts, final VehicleRoutingActivityCosts actCosts) {
super();
this.routingCosts = routingCosts;
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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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 boolean local = true;
private ConstraintManager constraintManager;
private VehicleFleetManager fleetManager; private StateManager stateManager;
private double weightOfFixedCosts; private boolean local = true;
private boolean considerFixedCosts = false; private ConstraintManager constraintManager;
private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null; private VehicleFleetManager fleetManager;
private int forwaredLooking; private double weightOfFixedCosts;
private int memory; private boolean considerFixedCosts = false;
private ExecutorService executor; private ActivityInsertionCostsCalculator actInsertionCostsCalculator = null;
private int nuOfThreads; private int forwaredLooking;
private double timeSlice; private int memory;
private int nNeighbors; private ExecutorService executor;
private boolean timeScheduling=false; private int nuOfThreads;
private boolean allowVehicleSwitch=true; private double timeSlice;
private boolean addDefaultCostCalc=true; private int nNeighbors;
public BestInsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) { private boolean timeScheduling = false;
super();
this.vrp = vrp; private boolean allowVehicleSwitch = true;
this.stateManager = stateManager;
this.constraintManager = constraintManager; private boolean addDefaultCostCalc = true;
this.fleetManager = vehicleFleetManager;
} public BestInsertionBuilder(VehicleRoutingProblem vrp, VehicleFleetManager vehicleFleetManager, StateManager stateManager, ConstraintManager constraintManager) {
super();
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory){ this.vrp = vrp;
local = false; this.stateManager = stateManager;
this.forwaredLooking = forwardLooking; this.constraintManager = constraintManager;
this.memory = memory; this.fleetManager = vehicleFleetManager;
return this; }
};
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory) {
public BestInsertionBuilder setRouteLevel(int forwardLooking, int memory, boolean addDefaultMarginalCostCalculation){ local = false;
local = false; this.forwaredLooking = forwardLooking;
this.forwaredLooking = forwardLooking; this.memory = memory;
this.memory = memory; return this;
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() {
*/ local = true;
public BestInsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation){ return this;
local = true; }
addDefaultCostCalc = addDefaultMarginalCostCalculation;
return this; ;
}
/**
public BestInsertionBuilder considerFixedCosts(double weightOfFixedCosts){ * If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
this.weightOfFixedCosts = weightOfFixedCosts; * is controlled by your custom soft constraints.
this.considerFixedCosts = true; *
return this; * @param addDefaultMarginalCostCalculation
} * @return
*/
public BestInsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){ public BestInsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation) {
this.actInsertionCostsCalculator = activityInsertionCostsCalculator; local = true;
return this; addDefaultCostCalc = addDefaultMarginalCostCalculation;
}; return this;
}
public BestInsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads){
this.executor = executor; public BestInsertionBuilder considerFixedCosts(double weightOfFixedCosts) {
this.nuOfThreads = nuOfThreads; this.weightOfFixedCosts = weightOfFixedCosts;
return this; this.considerFixedCosts = true;
} return this;
}
public InsertionStrategy build() { public BestInsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
List<InsertionListener> iListeners = new ArrayList<InsertionListener>(); this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>(); return this;
JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners); }
if(local){
calcBuilder.setLocalLevel(addDefaultCostCalc); ;
}
else { public BestInsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) {
calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc); this.executor = executor;
} this.nuOfThreads = nuOfThreads;
calcBuilder.setConstraintManager(constraintManager); return this;
calcBuilder.setStateManager(stateManager); }
calcBuilder.setVehicleRoutingProblem(vrp);
calcBuilder.setVehicleFleetManager(fleetManager);
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator); public InsertionStrategy build() {
if(considerFixedCosts) { List<InsertionListener> iListeners = new ArrayList<InsertionListener>();
calcBuilder.considerFixedCosts(weightOfFixedCosts); List<PrioritizedVRAListener> algorithmListeners = new ArrayList<PrioritizedVRAListener>();
} JobInsertionCostsCalculatorBuilder calcBuilder = new JobInsertionCostsCalculatorBuilder(iListeners, algorithmListeners);
if(timeScheduling){ if (local) {
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors); calcBuilder.setLocalLevel(addDefaultCostCalc);
} } else {
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch); calcBuilder.setRouteLevel(forwaredLooking, memory, addDefaultCostCalc);
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);
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);
return bestInsertion;
}
/** /**
* @deprecated this is experimental and can disappear. * @param timeSlice the time slice
* @param timeSlice the time slice * @param nNeighbors number of neighbors
* @param nNeighbors number of neighbors * @deprecated this is experimental and can disappear.
*/ */
@Deprecated @Deprecated
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) { public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
this.timeSlice=timeSlice; this.timeSlice = timeSlice;
this.nNeighbors=nNeighbors; this.nNeighbors = nNeighbors;
timeScheduling=true; timeScheduling = true;
} }
public void setAllowVehicleSwitch(boolean allowVehicleSwitch) { public void setAllowVehicleSwitch(boolean allowVehicleSwitch) {
this.allowVehicleSwitch = allowVehicleSwitch; this.allowVehicleSwitch = allowVehicleSwitch;
} }
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -30,171 +30,165 @@ 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 {
List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
}
class Insertion {
private final VehicleRoute route;
private final InsertionData insertionData;
public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) { static class Batch {
super(); List<VehicleRoute> routes = new ArrayList<VehicleRoute>();
this.route = vehicleRoute;
this.insertionData = insertionData;
}
public VehicleRoute getRoute() { }
return route;
}
public InsertionData getInsertionData() {
return insertionData;
}
}
private static Logger logger = LogManager.getLogger(BestInsertionConcurrent.class);
private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345;
private final static Vehicle NO_NEW_VEHICLE_YET = null;
private final static Driver NO_NEW_DRIVER_YET = null;
private InsertionListeners insertionsListeners;
private JobInsertionCostsCalculator bestInsertionCostCalculator;
private int nuOfBatches; class Insertion {
private ExecutorCompletionService<Insertion> completionService; private final VehicleRoute route;
@Deprecated private final InsertionData insertionData;
public void setRandom(Random random) {
super.random = random;
}
public BestInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, ExecutorService executorService, int nuOfBatches, VehicleRoutingProblem vehicleRoutingProblem) {
super(vehicleRoutingProblem);
this.insertionsListeners = new InsertionListeners();
this.nuOfBatches = nuOfBatches;
bestInsertionCostCalculator = jobInsertionCalculator;
completionService = new ExecutorCompletionService<Insertion>(executorService);
logger.debug("initialise " + this);
}
@Override public Insertion(VehicleRoute vehicleRoute, InsertionData insertionData) {
public String toString() { super();
return "[name=bestInsertion]"; this.route = vehicleRoute;
} this.insertionData = insertionData;
}
@Override public VehicleRoute getRoute() {
public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) { return route;
List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size()); }
List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
Collections.shuffle(unassignedJobList, random);
List<Batch> batches = distributeRoutes(vehicleRoutes,nuOfBatches);
for(final Job unassignedJob : unassignedJobList){
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
for(final Batch batch : batches){
completionService.submit(new Callable<Insertion>() {
@Override public InsertionData getInsertionData() {
public Insertion call() throws Exception { return insertionData;
return getBestInsertion(batch,unassignedJob); }
}
}); }
}
try { private static Logger logger = LogManager.getLogger(BestInsertionConcurrent.class);
for (int i = 0; i < batches.size(); i++) {
Future<Insertion> futureIData = completionService.take(); private final static double NO_NEW_DEPARTURE_TIME_YET = -12345.12345;
Insertion insertion = futureIData.get();
if (insertion == null) continue; private final static Vehicle NO_NEW_VEHICLE_YET = null;
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
bestInsertion = insertion; private final static Driver NO_NEW_DRIVER_YET = null;
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
} private InsertionListeners insertionsListeners;
}
} catch(InterruptedException e){ private JobInsertionCostsCalculator bestInsertionCostCalculator;
Thread.currentThread().interrupt();
} private int nuOfBatches;
catch (ExecutionException e) {
e.printStackTrace(); private ExecutorCompletionService<Insertion> completionService;
logger.error(e.getCause().toString());
System.exit(1); @Deprecated
} public void setRandom(Random random) {
VehicleRoute newRoute = VehicleRoute.emptyRoute(); super.random = random;
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost); }
if(newIData.getInsertionCost() < bestInsertionCost){
bestInsertion = new Insertion(newRoute,newIData); public BestInsertionConcurrent(JobInsertionCostsCalculator jobInsertionCalculator, ExecutorService executorService, int nuOfBatches, VehicleRoutingProblem vehicleRoutingProblem) {
vehicleRoutes.add(newRoute); super(vehicleRoutingProblem);
batches.get(random.nextInt(batches.size())).routes.add(newRoute); this.insertionsListeners = new InsertionListeners();
} this.nuOfBatches = nuOfBatches;
if(bestInsertion == null) badJobs.add(unassignedJob); bestInsertionCostCalculator = jobInsertionCalculator;
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); completionService = new ExecutorCompletionService<Insertion>(executorService);
} logger.debug("initialise {}", this);
return badJobs; }
}
@Override
private Insertion getBestInsertion(Batch batch, Job unassignedJob) { public String toString() {
Insertion bestInsertion = null; return "[name=bestInsertion]";
double bestInsertionCost = Double.MAX_VALUE; }
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); @Override
if(iData instanceof NoInsertionFound) { public Collection<Job> insertUnassignedJobs(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
continue; List<Job> badJobs = new ArrayList<Job>(unassignedJobs.size());
} List<Job> unassignedJobList = new ArrayList<Job>(unassignedJobs);
if(iData.getInsertionCost() < bestInsertionCost){ Collections.shuffle(unassignedJobList, random);
bestInsertion = new Insertion(vehicleRoute,iData); List<Batch> batches = distributeRoutes(vehicleRoutes, nuOfBatches);
bestInsertionCost = iData.getInsertionCost(); for (final Job unassignedJob : unassignedJobList) {
} Insertion bestInsertion = null;
} double bestInsertionCost = Double.MAX_VALUE;
return bestInsertion; for (final Batch batch : batches) {
} completionService.submit(new Callable<Insertion>() {
private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) { @Override
List<Batch> batches = new ArrayList<Batch>(); public Insertion call() throws Exception {
for(int i=0;i<nuOfBatches;i++) batches.add(new Batch()); return getBestInsertion(batch, unassignedJob);
/* }
* if route.size < nuOfBatches add as much routes as empty batches are available
});
}
try {
for (int i = 0; i < batches.size(); i++) {
Future<Insertion> futureIData = completionService.take();
Insertion insertion = futureIData.get();
if (insertion == null) continue;
if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) {
bestInsertion = insertion;
bestInsertionCost = insertion.getInsertionData().getInsertionCost();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
e.printStackTrace();
logger.error("Exception", e);
System.exit(1);
}
VehicleRoute newRoute = VehicleRoute.emptyRoute();
InsertionData newIData = bestInsertionCostCalculator.getInsertionData(newRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost);
if (newIData.getInsertionCost() < bestInsertionCost) {
bestInsertion = new Insertion(newRoute, newIData);
vehicleRoutes.add(newRoute);
batches.get(random.nextInt(batches.size())).routes.add(newRoute);
}
if (bestInsertion == null) badJobs.add(unassignedJob);
else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute());
}
return badJobs;
}
private Insertion getBestInsertion(Batch batch, Job unassignedJob) {
Insertion bestInsertion = null;
double bestInsertionCost = Double.MAX_VALUE;
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);
if (iData instanceof NoInsertionFound) {
continue;
}
if (iData.getInsertionCost() < bestInsertionCost) {
bestInsertion = new Insertion(vehicleRoute, iData);
bestInsertionCost = iData.getInsertionCost();
}
}
return bestInsertion;
}
private List<Batch> distributeRoutes(Collection<VehicleRoute> vehicleRoutes, int nuOfBatches) {
List<Batch> batches = new ArrayList<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
* 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

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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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 int nOfDepartureTimes = 3; private JobInsertionCostsCalculator jic;
private double timeSlice = 900.0;
public CalculatesServiceInsertionWithTimeSchedulingInSlices(JobInsertionCostsCalculator jic, double timeSlice, int neighbors) {
super();
this.jic = jic;
this.timeSlice = timeSlice;
this.nOfDepartureTimes = neighbors;
log.debug("initialise " + this);
}
@Override
public String toString() {
return "[name="+this.getClass().toString()+"][timeSlice="+timeSlice+"][#timeSlice="+nOfDepartureTimes+"]";
}
@Override private int nOfDepartureTimes = 3;
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
List<Double> vehicleDepartureTimes = new ArrayList<Double>(); private double timeSlice = 900.0;
double currentStart;
if(currentRoute.getStart() == null){ public CalculatesServiceInsertionWithTimeSchedulingInSlices(JobInsertionCostsCalculator jic, double timeSlice, int neighbors) {
currentStart = newVehicleDepartureTime; super();
} this.jic = jic;
else currentStart = currentRoute.getStart().getEndTime(); this.timeSlice = timeSlice;
this.nOfDepartureTimes = neighbors;
vehicleDepartureTimes.add(currentStart); log.debug("initialise " + this);
}
@Override
public String toString() {
return "[name=" + this.getClass().toString() + "][timeSlice=" + timeSlice + "][#timeSlice=" + nOfDepartureTimes + "]";
}
@Override
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
List<Double> vehicleDepartureTimes = new ArrayList<Double>();
double currentStart;
if (currentRoute.getStart() == null) {
currentStart = newVehicleDepartureTime;
} else currentStart = currentRoute.getStart().getEndTime();
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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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;
private int nuOfJobsToRecreate;
public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) { JobInsertionConsideringFixCostsCalculator calcConsideringFix;
super();
this.vrp = vrp;
this.calcConsideringFix = calcConsideringFix;
}
@Override
public String toString() {
return "[name=configureFixCostCalculator]";
}
@Override private int nuOfJobsToRecreate;
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size(); public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) {
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)vrp.getJobs().values().size())); super();
calcConsideringFix.setSolutionCompletenessRatio(completenessRatio); this.vrp = vrp;
this.calcConsideringFix = calcConsideringFix;
}
@Override
public String toString() {
return "[name=configureFixCostCalculator]";
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size()));
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

@ -27,14 +27,14 @@ public class ConfigureLocalActivityInsertionCalculator implements InsertionStart
@Override @Override
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) { public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, 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()));
localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5,completenessRatio)); localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5, 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()));
localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5,completenessRatio)); localActivityInsertionCostsCalculator.setSolutionCompletenessRatio(Math.max(0.5, completenessRatio));
} }
} }

View file

@ -1,18 +1,18 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
@ -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 int nuOfJobs;
public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
super();
this.nuOfJobs=nuOfJobs;
calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
}
@Override private final JobInsertionConsideringFixCostsCalculator calculator;
public double getCosts(JobInsertionContext insertionContext) {
return calculator.getCosts(insertionContext);
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)nuOfJobs));
calculator.setSolutionCompletenessRatio(completenessRatio);
}
@Override private final int nuOfJobs;
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
nuOfJobsToRecreate--; public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) {
double completenessRatio = (1-((double)nuOfJobsToRecreate/(double)nuOfJobs)); super();
calculator.setSolutionCompletenessRatio(completenessRatio); this.nuOfJobs = nuOfJobs;
System.out.println(completenessRatio); calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter);
} }
@Override
public double getCosts(JobInsertionContext insertionContext) {
return calculator.getCosts(insertionContext);
}
@Override
public void informInsertionStarts(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
this.nuOfJobsToRecreate = unassignedJobs.size();
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
calculator.setSolutionCompletenessRatio(completenessRatio);
}
@Override
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
nuOfJobsToRecreate--;
double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs));
calculator.setSolutionCompletenessRatio(completenessRatio);
System.out.println(completenessRatio);
}
} }

View file

@ -16,8 +16,8 @@ class EventListeners {
listeners.add(new InsertBreakListener()); 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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -29,34 +29,34 @@ import jsprit.core.problem.solution.route.activity.*;
import java.util.List; import java.util.List;
class Inserter { class Inserter {
interface JobInsertionHandler {
void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route); interface JobInsertionHandler {
void setNextHandler(JobInsertionHandler handler);
} void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route);
class JobExceptionHandler implements JobInsertionHandler{
@Override void setNextHandler(JobInsertionHandler handler);
public void handleJobInsertion(Job job, InsertionData iData,VehicleRoute route) {
throw new IllegalStateException("job insertion is not supported. Do not know job type.");
}
@Override }
public void setNextHandler(JobInsertionHandler handler) {
} class JobExceptionHandler implements JobInsertionHandler {
}
class ServiceInsertionHandler implements JobInsertionHandler{
private TourActivityFactory activityFactory = new DefaultTourActivityFactory(); @Override
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
private JobInsertionHandler delegator = new JobExceptionHandler(); throw new IllegalStateException("job insertion is not supported. Do not know job type.");
}
@Override
public void setNextHandler(JobInsertionHandler handler) {
}
}
class ServiceInsertionHandler implements JobInsertionHandler {
private TourActivityFactory activityFactory = new DefaultTourActivityFactory();
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) {
route.getEnd().setLocation(shipment.getDeliveryLocation());
}
public void setNextHandler(JobInsertionHandler jobInsertionHandler){ private void setEndLocation(VehicleRoute route, Shipment shipment) {
this.delegator = jobInsertionHandler; route.getEnd().setLocation(shipment.getDeliveryLocation());
} }
}
private InsertionListeners insertionListeners; public void setNextHandler(JobInsertionHandler jobInsertionHandler) {
this.delegator = jobInsertionHandler;
private JobInsertionHandler jobInsertionHandler; }
}
private InsertionListeners insertionListeners;
private JobInsertionHandler jobInsertionHandler;
private VehicleRoutingProblem vehicleRoutingProblem; private VehicleRoutingProblem vehicleRoutingProblem;
public Inserter(InsertionListeners insertionListeners, VehicleRoutingProblem vehicleRoutingProblem) {
this.insertionListeners = insertionListeners;
new DefaultTourActivityFactory();
jobInsertionHandler = new ServiceInsertionHandler(vehicleRoutingProblem);
jobInsertionHandler.setNextHandler(new ShipmentInsertionHandler(vehicleRoutingProblem));
}
public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute){ public Inserter(InsertionListeners insertionListeners, VehicleRoutingProblem vehicleRoutingProblem) {
insertionListeners.informBeforeJobInsertion(job, insertionData, vehicleRoute); this.insertionListeners = insertionListeners;
new DefaultTourActivityFactory();
if(insertionData == null || (insertionData instanceof NoInsertionFound)) throw new IllegalStateException("insertionData null. cannot insert job."); jobInsertionHandler = new ServiceInsertionHandler(vehicleRoutingProblem);
if(job == null) throw new IllegalStateException("cannot insert null-job"); jobInsertionHandler.setNextHandler(new ShipmentInsertionHandler(vehicleRoutingProblem));
if(!(vehicleRoute.getVehicle().getId().equals(insertionData.getSelectedVehicle().getId()))){ }
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime()); public void insertJob(Job job, InsertionData insertionData, VehicleRoute vehicleRoute) {
} insertionListeners.informBeforeJobInsertion(job, insertionData, vehicleRoute);
if (insertionData == null || (insertionData instanceof NoInsertionFound))
throw new IllegalStateException("insertionData null. cannot insert job.");
if (job == null) throw new IllegalStateException("cannot insert null-job");
if (!(vehicleRoute.getVehicle().getId().equals(insertionData.getSelectedVehicle().getId()))) {
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());
}
} }

View file

@ -34,169 +34,163 @@ public class InsertionBuilder {
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) { public InsertionBuilder(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 InsertionBuilder setInsertionStrategy(Strategy strategy){ 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 setLocalLevel() {
local = true; local = true;
return this; return this;
} }
/** /**
* If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation * If addDefaulMarginalCostCalculation is false, no calculator is set which implicitly assumes that marginal cost calculation
* is controlled by your custom soft constraints. * is controlled by your custom soft constraints.
* *
* @param addDefaultMarginalCostCalculation * @param addDefaultMarginalCostCalculation
* @return * @return
*/ */
public InsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation){ public InsertionBuilder setLocalLevel(boolean addDefaultMarginalCostCalculation) {
local = true; local = true;
addDefaultCostCalc = addDefaultMarginalCostCalculation; addDefaultCostCalc = addDefaultMarginalCostCalculation;
return this; return this;
} }
public InsertionBuilder considerFixedCosts(double weightOfFixedCosts){ public InsertionBuilder considerFixedCosts(double weightOfFixedCosts) {
this.weightOfFixedCosts = weightOfFixedCosts; this.weightOfFixedCosts = weightOfFixedCosts;
this.considerFixedCosts = true; this.considerFixedCosts = true;
return this; return this;
} }
public InsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){ public InsertionBuilder setActivityInsertionCostCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator) {
this.actInsertionCostsCalculator = activityInsertionCostsCalculator; this.actInsertionCostsCalculator = activityInsertionCostsCalculator;
return this; return this;
} }
public InsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads){ public InsertionBuilder setConcurrentMode(ExecutorService executor, int nuOfThreads) {
this.executor = executor; this.executor = executor;
this.nuOfThreads = nuOfThreads; this.nuOfThreads = nuOfThreads;
return this; 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.setConstraintManager(constraintManager); calcBuilder.setStateManager(stateManager);
calcBuilder.setStateManager(stateManager); calcBuilder.setVehicleRoutingProblem(vrp);
calcBuilder.setVehicleRoutingProblem(vrp); calcBuilder.setVehicleFleetManager(fleetManager);
calcBuilder.setVehicleFleetManager(fleetManager); calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator);
calcBuilder.setActivityInsertionCostsCalculator(actInsertionCostsCalculator); if (considerFixedCosts) {
if(considerFixedCosts) { calcBuilder.considerFixedCosts(weightOfFixedCosts);
calcBuilder.considerFixedCosts(weightOfFixedCosts); }
} if (timeScheduling) {
if(timeScheduling){ calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors);
calcBuilder.experimentalTimeScheduler(timeSlice, nNeighbors); }
} calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch);
calcBuilder.setAllowVehicleSwitch(allowVehicleSwitch); JobInsertionCostsCalculator costCalculator = calcBuilder.build();
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); insertion = new RegretInsertion(costCalculator, vrp);
} else {
insertion = new RegretInsertionConcurrent(costCalculator, vrp, executor);
} }
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 timeSlice the time slice * @param nNeighbors number of neighbors
* @param nNeighbors number of neighbors * @deprecated this is experimental and can disappear.
*/ */
@Deprecated @Deprecated
public void experimentalTimeScheduler(double timeSlice, int nNeighbors) { public void experimentalTimeScheduler(double timeSlice, int nNeighbors) {
this.timeSlice=timeSlice; this.timeSlice = timeSlice;
this.nNeighbors=nNeighbors; this.nNeighbors = nNeighbors;
timeScheduling=true; timeScheduling = true;
} }
public InsertionBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) { public InsertionBuilder setAllowVehicleSwitch(boolean allowVehicleSwitch) {
this.allowVehicleSwitch = allowVehicleSwitch; this.allowVehicleSwitch = allowVehicleSwitch;
return this; return this;
} }
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -25,142 +25,140 @@ import java.util.List;
/** /**
* Data object that collects insertion information. It collects insertionCosts, insertionIndeces, vehicle and driver to be employed * Data object that collects insertion information. It collects insertionCosts, insertionIndeces, vehicle and driver to be employed
* 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 NoInsertionFound() {
super(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);
}
} public static class NoInsertionFound extends InsertionData {
private static InsertionData noInsertion = new NoInsertionFound();
/**
* 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>
* <code>new InsertionData(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);</code><br>
* where NO_INDEX=-1.
*
* @return
*/
public static InsertionData createEmptyInsertionData(){
return noInsertion;
}
static int NO_INDEX = -1;
private final double insertionCost; public NoInsertionFound() {
super(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);
private final int pickupInsertionIndex; }
private final int deliveryInsertionIndex;
private final Vehicle selectedVehicle;
private final Driver selectedDriver;
private double departureTime;
private double additionalTime;
private List<Event> events = new ArrayList<Event>(); }
List<Event> getEvents(){ private static InsertionData noInsertion = new NoInsertionFound();
return events;
}
/** /**
* @return the additionalTime * 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>
public double getAdditionalTime() { * <code>new InsertionData(Double.MAX_VALUE, NO_INDEX, NO_INDEX, null, null);</code><br>
return additionalTime; * where NO_INDEX=-1.
} *
* @return
*/
public static InsertionData createEmptyInsertionData() {
return noInsertion;
}
/** static int NO_INDEX = -1;
* @param additionalTime the additionalTime to set
*/
public void setAdditionalTime(double additionalTime) {
this.additionalTime = additionalTime;
}
public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver){ private final double insertionCost;
this.insertionCost = insertionCost;
this.pickupInsertionIndex = pickupInsertionIndex;
this.deliveryInsertionIndex = deliveryInsertionIndex;
this.selectedVehicle = vehicle;
this.selectedDriver = driver;
}
@Override
public String toString() {
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).
*
* @return
*/
public int getDeliveryInsertionIndex(){
return deliveryInsertionIndex;
}
/**
* Returns insertionIndex of pickkupActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
*
* @return
*/
public int getPickupInsertionIndex(){
return pickupInsertionIndex;
}
/**
* Returns insertion costs (which might be the additional costs of inserting the corresponding job).
*
* @return
*/
public double getInsertionCost() {
return insertionCost;
}
/** private final int pickupInsertionIndex;
* Returns the vehicle to be employed.
* private final int deliveryInsertionIndex;
* @return
*/ private final Vehicle selectedVehicle;
public Vehicle getSelectedVehicle() {
return selectedVehicle; private final Driver selectedDriver;
}
private double departureTime;
/**
* Returns the vehicle to be employed. private double additionalTime;
*
* @return private List<Event> events = new ArrayList<Event>();
*/
public Driver getSelectedDriver(){ List<Event> getEvents() {
return selectedDriver; return events;
} }
/**
* @return the additionalTime
*/
public double getAdditionalTime() {
return additionalTime;
}
/**
* @param additionalTime the additionalTime to set
*/
public void setAdditionalTime(double additionalTime) {
this.additionalTime = additionalTime;
}
public InsertionData(double insertionCost, int pickupInsertionIndex, int deliveryInsertionIndex, Vehicle vehicle, Driver driver) {
this.insertionCost = insertionCost;
this.pickupInsertionIndex = pickupInsertionIndex;
this.deliveryInsertionIndex = deliveryInsertionIndex;
this.selectedVehicle = vehicle;
this.selectedDriver = driver;
}
@Override
public String toString() {
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).
*
* @return
*/
public int getDeliveryInsertionIndex() {
return deliveryInsertionIndex;
}
/**
* Returns insertionIndex of pickkupActivity. If no insertionPosition is found, it returns NO_INDEX (=-1).
*
* @return
*/
public int getPickupInsertionIndex() {
return pickupInsertionIndex;
}
/**
* Returns insertion costs (which might be the additional costs of inserting the corresponding job).
*
* @return
*/
public double getInsertionCost() {
return insertionCost;
}
/**
* Returns the vehicle to be employed.
*
* @return
*/
public Vehicle getSelectedVehicle() {
return selectedVehicle;
}
/**
* Returns the vehicle to be employed.
*
* @return
*/
public Driver getSelectedDriver() {
return selectedDriver;
}
/**
* @return the departureTime
*/
public double getVehicleDepartureTime() {
return departureTime;
}
/**
* @param departureTime the departureTime to set
*/
public void setVehicleDepartureTime(double departureTime) {
this.departureTime = departureTime;
}
/**
* @return the departureTime
*/
public double getVehicleDepartureTime() {
return departureTime;
}
/**
* @param departureTime the departureTime to set
*/
public void setVehicleDepartureTime(double departureTime) {
this.departureTime = departureTime;
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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

@ -1,18 +1,18 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
@ -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>();
void put(Class<? extends Job> jobClass, JobInsertionCostsCalculator jic) {
calcMap.put(jobClass, jic);
}
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore) {
JobInsertionCostsCalculator jic = calcMap.get(jobToInsert.getClass());
if (jic == null) throw new IllegalStateException("cannot find calculator for " + jobToInsert.getClass());
return jic.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownScore);
}
private Map<Class<? extends Job>,JobInsertionCostsCalculator> calcMap = new HashMap<Class<? extends Job>, JobInsertionCostsCalculator>();
void put(Class<? extends Job> jobClass, JobInsertionCostsCalculator jic){
calcMap.put(jobClass, jic);
}
public InsertionData getInsertionData(VehicleRoute currentRoute, Job jobToInsert, Vehicle newVehicle, double newVehicleDepartureTime, Driver newDriver, double bestKnownScore){
JobInsertionCostsCalculator jic = calcMap.get(jobToInsert.getClass());
if(jic==null) throw new IllegalStateException("cannot find calculator for " + jobToInsert.getClass());
return jic.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownScore);
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -30,107 +30,107 @@ 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 double weight_deltaFixCost = 0.5;
private double solution_completeness_ratio = 0.5;
private RouteAndActivityStateGetter stateGetter;
public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) { private final JobInsertionCostsCalculator standardServiceInsertion;
super();
this.standardServiceInsertion = standardInsertionCalculator;
this.stateGetter = stateGetter;
logger.debug("inialise " + this);
}
@Override private double weight_deltaFixCost = 0.5;
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);
if(fixcost_contribution > bestKnownPrice){
return InsertionData.createEmptyInsertionData();
}
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
if(iData instanceof NoInsertionFound){
return iData;
}
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
insertionData.getEvents().addAll(iData.getEvents());
return insertionData;
}
private double getFixCostContribution(final VehicleRoute currentRoute, private double solution_completeness_ratio = 0.5;
final Job jobToInsert, final Vehicle newVehicle) {
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert);
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert);
double deltaFixCost = (1-solution_completeness_ratio)*relFixCost + solution_completeness_ratio*absFixCost;
double fixcost_contribution = weight_deltaFixCost*solution_completeness_ratio*deltaFixCost;
return fixcost_contribution;
}
public void setWeightOfFixCost(double weight){
weight_deltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to " + weight);
}
@Override
public String toString() {
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings="+weight_deltaFixCost+"]";
}
public void setSolutionCompletenessRatio(double ratio){ private RouteAndActivityStateGetter stateGetter;
solution_completeness_ratio = ratio;
}
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) { public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) {
Capacity load = Capacity.addup(getCurrentMaxLoadInRoute(route), job.getSize()); super();
this.standardServiceInsertion = standardInsertionCalculator;
this.stateGetter = stateGetter;
logger.debug("inialise {}", this);
}
@Override
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);
if (fixcost_contribution > bestKnownPrice) {
return InsertionData.createEmptyInsertionData();
}
InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice);
if (iData instanceof NoInsertionFound) {
return iData;
}
double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution;
InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver);
insertionData.setVehicleDepartureTime(newVehicleDepartureTime);
insertionData.getEvents().addAll(iData.getEvents());
return insertionData;
}
private double getFixCostContribution(final VehicleRoute currentRoute,
final Job jobToInsert, final Vehicle newVehicle) {
double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert);
double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert);
double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost;
double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost;
return fixcost_contribution;
}
public void setWeightOfFixCost(double weight) {
weight_deltaFixCost = weight;
logger.debug("set weightOfFixCostSaving to {}", weight);
}
@Override
public String toString() {
return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weight_deltaFixCost + "]";
}
public void setSolutionCompletenessRatio(double ratio) {
solution_completeness_ratio = ratio;
}
private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job) {
Capacity load = Capacity.addup(getCurrentMaxLoadInRoute(route), job.getSize());
// double load = getCurrentMaxLoadInRoute(route) + job.getCapacityDemand(); // 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 = getCurrentMaxLoadInRoute(route); Capacity currentLoad = getCurrentMaxLoadInRoute(route);
// int currentLoad = getCurrentMaxLoadInRoute(route); // int currentLoad = getCurrentMaxLoadInRoute(route);
Capacity load = Capacity.addup(currentLoad, job.getSize()); Capacity load = Capacity.addup(currentLoad, job.getSize());
// double load = currentLoad + job.getCapacityDemand(); // double load = currentLoad + job.getCapacityDemand();
double currentRelFix = 0.0; double currentRelFix = 0.0;
if(route.getVehicle() != null){ if (route.getVehicle() != null) {
if(!(route.getVehicle() instanceof NoVehicle)){ if (!(route.getVehicle() instanceof NoVehicle)) {
currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions()); currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions());
} }
} }
if(!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)){ if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) {
return Double.MAX_VALUE; return Double.MAX_VALUE;
} }
double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix* (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix; double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix;
return relativeFixCost; 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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -86,9 +86,9 @@ public class JobInsertionCostsCalculatorBuilder {
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;
@ -97,10 +97,10 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Constructs the builder. * Constructs the builder.
* *
* <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
*/ */
@ -113,7 +113,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets activityStates. MUST be set. * Sets activityStates. MUST be set.
* @param stateManager * @param stateManager
* *
* @return * @return
*/ */
public JobInsertionCostsCalculatorBuilder setStateManager(RouteAndActivityStateGetter stateManager){ public JobInsertionCostsCalculatorBuilder setStateManager(RouteAndActivityStateGetter stateManager){
@ -123,7 +123,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets routingProblem. MUST be set. * Sets routingProblem. MUST be set.
* *
* @param vehicleRoutingProblem * @param vehicleRoutingProblem
* @return * @return
*/ */
@ -134,7 +134,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets fleetManager. MUST be set. * Sets fleetManager. MUST be set.
* *
* @param fleetManager * @param fleetManager
* @return * @return
*/ */
@ -145,7 +145,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets a flag to build a calculator based on local calculations. * Sets a flag to build a calculator based on local calculations.
* *
* <p>Insertion of a job and job-activity is evaluated based on the previous and next activity. * <p>Insertion of a job and job-activity is evaluated based on the previous and next activity.
* @param addDefaultCostCalc * @param addDefaultCostCalc
*/ */
@ -154,7 +154,7 @@ public class JobInsertionCostsCalculatorBuilder {
this.addDefaultCostCalc = addDefaultCostCalc; this.addDefaultCostCalc = addDefaultCostCalc;
return this; return this;
} }
public JobInsertionCostsCalculatorBuilder setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){ public JobInsertionCostsCalculatorBuilder setActivityInsertionCostsCalculator(ActivityInsertionCostsCalculator activityInsertionCostsCalculator){
this.activityInsertionCostCalculator = activityInsertionCostsCalculator; this.activityInsertionCostCalculator = activityInsertionCostsCalculator;
return this; return this;
@ -162,7 +162,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Sets a flag to build a calculator that evaluates job insertion on route-level. * Sets a flag to build a calculator that evaluates job insertion on route-level.
* *
* @param forwardLooking * @param forwardLooking
* @param memory * @param memory
* @param addDefaultMarginalCostCalc * @param addDefaultMarginalCostCalc
@ -177,7 +177,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* 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 consider also fixed-cost when evaluating the insertion of a job. The weight of the fixed-cost can be determined by setting
* weightofFixedCosts. * weightofFixedCosts.
* *
* @param weightOfFixedCosts * @param weightOfFixedCosts
*/ */
public JobInsertionCostsCalculatorBuilder considerFixedCosts(double weightOfFixedCosts){ public JobInsertionCostsCalculatorBuilder considerFixedCosts(double weightOfFixedCosts){
@ -185,7 +185,7 @@ public class JobInsertionCostsCalculatorBuilder {
this.weightOfFixedCost = weightOfFixedCosts; this.weightOfFixedCost = weightOfFixedCosts;
return this; return this;
} }
public JobInsertionCostsCalculatorBuilder experimentalTimeScheduler(double timeSlice, int neighbors){ public JobInsertionCostsCalculatorBuilder experimentalTimeScheduler(double timeSlice, int neighbors){
timeScheduling = true; timeScheduling = true;
this.timeSlice = timeSlice; this.timeSlice = timeSlice;
@ -195,7 +195,7 @@ public class JobInsertionCostsCalculatorBuilder {
/** /**
* Builds the jobInsertionCalculator. * Builds the jobInsertionCalculator.
* *
* @return jobInsertionCalculator. * @return jobInsertionCalculator.
* @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null. * @throws IllegalStateException if vrp == null or activityStates == null or fleetManager == null.
*/ */
@ -240,7 +240,7 @@ public class JobInsertionCostsCalculatorBuilder {
+ "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) {
@ -272,7 +272,7 @@ public class JobInsertionCostsCalculatorBuilder {
double depTimeAtPrevAct) { double depTimeAtPrevAct) {
return 0.; return 0.;
} }
}; };
} }
else{ else{
@ -328,13 +328,13 @@ public class JobInsertionCostsCalculatorBuilder {
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{

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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

@ -32,16 +32,16 @@ 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>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.; private double activityCostsWeight = 1.;
@ -66,7 +66,6 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct); double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct);
double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); double act_costs_newAct = activityCosts.getActivityCost(newAct, newAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
// if(newAct instanceof BreakActivity) act_costs_newAct = 0.;
if(isEnd(nextAct) && !toDepot(iFacts.getNewVehicle())) return tp_costs_prevAct_newAct; if(isEnd(nextAct) && !toDepot(iFacts.getNewVehicle())) return tp_costs_prevAct_newAct;
@ -75,10 +74,9 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct; double nextAct_arrTime = newAct_endTime + tp_time_newAct_nextAct;
double endTime_nextAct_new = CalculationUtils.getActivityEndTime(nextAct_arrTime, nextAct); double endTime_nextAct_new = CalculationUtils.getActivityEndTime(nextAct_arrTime, nextAct);
double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); double act_costs_nextAct = activityCosts.getActivityCost(nextAct, nextAct_arrTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
// if(nextAct instanceof BreakActivity) act_costs_nextAct = 0;
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + solutionCompletenessRatio * activityCostsWeight * (act_costs_newAct + act_costs_nextAct); double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct + solutionCompletenessRatio * activityCostsWeight * (act_costs_newAct + act_costs_nextAct);
double oldCosts = 0.; double oldCosts = 0.;
if(iFacts.getRoute().isEmpty()){ if(iFacts.getRoute().isEmpty()){
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
@ -89,7 +87,6 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal
double arrTime_nextAct = depTimeAtPrevAct + routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); double arrTime_nextAct = depTimeAtPrevAct + routingCosts.getTransportTime(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
double endTime_nextAct_old = CalculationUtils.getActivityEndTime(arrTime_nextAct,nextAct); double endTime_nextAct_old = CalculationUtils.getActivityEndTime(arrTime_nextAct,nextAct);
double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); double actCost_nextAct = activityCosts.getActivityCost(nextAct, arrTime_nextAct, iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
// if(nextAct instanceof BreakActivity) actCost_nextAct = 0;
double endTimeDelay_nextAct = Math.max(0, endTime_nextAct_new - endTime_nextAct_old); 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); Double futureWaiting = stateManager.getActivityState(nextAct, iFacts.getRoute().getVehicle(), InternalStates.FUTURE_WAITING, Double.class);

View file

@ -1,32 +1,32 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2014 Stefan Schroeder. * Copyright (c) 2014 Stefan Schroeder.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * 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. * 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 * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* *
* Contributors: * Contributors:
* Stefan Schroeder - initial API and implementation * Stefan Schroeder - initial API and implementation
******************************************************************************/ ******************************************************************************/
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

@ -207,8 +207,8 @@ public class RegretInsertion extends AbstractInsertionStrategy {
this.scoringFunction = new DefaultScorer(vehicleRoutingProblem); this.scoringFunction = new DefaultScorer(vehicleRoutingProblem);
this.insertionCostsCalculator = jobInsertionCalculator; this.insertionCostsCalculator = jobInsertionCalculator;
this.vrp = vehicleRoutingProblem; this.vrp = vehicleRoutingProblem;
logger.debug("initialise " + this); logger.debug("initialise {}", this);
} }
@Override @Override
public String toString() { public String toString() {

View file

@ -32,61 +32,61 @@ 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(RegretInsertionConcurrent.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); List<Job> jobs = new ArrayList<Job>(unassignedJobs);
@ -94,14 +94,14 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy {
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 +123,28 @@ 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 RegretInsertion.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;
} }
} }
} } 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;
} }
} }

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 RouteAndActivityStateGetter stateManager;
private int nuOfActivities2LookForward = 0;
public RouteLevelActivityInsertionCostsEstimator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) {
super();
this.activityCosts = actCosts;
this.stateManager = stateManager;
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(routingCosts, activityCosts);
}
@Override private AuxilliaryCostCalculator auxilliaryPathCostCalculator;
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
List<TourActivity> path = new ArrayList<TourActivity>(); private RouteAndActivityStateGetter stateManager;
path.add(prevAct); path.add(newAct); path.add(nextAct);
int actIndex; private int nuOfActivities2LookForward = 0;
if(prevAct instanceof Start) actIndex = 0;
else actIndex = iFacts.getRoute().getTourActivities().getActivities().indexOf(nextAct); public RouteLevelActivityInsertionCostsEstimator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts actCosts, RouteAndActivityStateGetter stateManager) {
if(nuOfActivities2LookForward > 0 && !(nextAct instanceof End)){ path.addAll(getForwardLookingPath(iFacts.getRoute(),actIndex)); } super();
this.activityCosts = actCosts;
this.stateManager = stateManager;
auxilliaryPathCostCalculator = new AuxilliaryCostCalculator(routingCosts, activityCosts);
}
@Override
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct, TourActivity nextAct, TourActivity newAct, double depTimeAtPrevAct) {
List<TourActivity> path = new ArrayList<TourActivity>();
path.add(prevAct);
path.add(newAct);
path.add(nextAct);
int 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

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -37,125 +37,122 @@ 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 HardRouteConstraint hardRouteLevelConstraint; private static final Logger logger = LogManager.getLogger(ServiceInsertionCalculator.class);
private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint;
private VehicleRoutingTransportCosts transportCosts;
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
private JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) { private HardRouteConstraint hardRouteLevelConstraint;
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){ private HardActivityConstraint hardActivityLevelConstraint;
private SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint;
private VehicleRoutingTransportCosts transportCosts;
private ActivityInsertionCostsCalculator additionalTransportCostsCalculator;
private JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
public ServiceInsertionCalculator(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; 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);
/* /*
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;
} }
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;
} }
} } else if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) {
else if(status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)){ 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); 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; }
}
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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); }
private final VehicleRoutingTransportCosts transportCosts;
private final VehicleRoutingActivityCosts activityCosts;
private AuxilliaryCostCalculator auxilliaryPathCostCalculator; void setNuOfActsForwardLooking(int nOfActsForwardLooking) {
this.nuOfActsForwardLooking = nOfActsForwardLooking;
private JobActivityFactory activityFactory; logger.debug("set [forwardLooking={}]", nOfActsForwardLooking);
}
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){ @Override
this.activityFactory=jobActivityFactory; public String toString() {
} return "[name=calculatesServiceInsertionOnRouteLevel][solutionMemory=" + memorySize + "][forwardLooking=" + nuOfActsForwardLooking + "]";
}
public void setMemorySize(int memorySize) { /**
this.memorySize = memorySize; * Calculates the insertion costs of job i on route level (which is based on the assumption that inserting job i does not only
logger.debug("set [solutionMemory="+memorySize+"]"); * 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!");
public ServiceInsertionOnRouteLevelCalculator(VehicleRoutingTransportCosts vehicleRoutingCosts, VehicleRoutingActivityCosts costFunc, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, HardRouteConstraint hardRouteLevelConstraint, HardActivityConstraint hardActivityLevelConstraint) { JobInsertionContext insertionContext = new JobInsertionContext(currentRoute, jobToInsert, newVehicle, newDriver, newVehicleDepartureTime);
super(); if (!hardRouteLevelConstraint.fulfilled(insertionContext)) {
this.transportCosts = vehicleRoutingCosts; return InsertionData.createEmptyInsertionData();
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){ * map that memorizes the costs with newVehicle, which is a cost-snapshot at tour-activities.
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.
*/
PriorityQueue<InsertionData> bestInsertionsQueue = new PriorityQueue<InsertionData>(Math.max(2, currentRoute.getTourActivities().getActivities().size()), getComparator());
TourActivities tour = currentRoute.getTourActivities();
double best_insertion_costs = best_known_insertion_costs;
Service service = (Service)jobToInsert;
/**
/** * priority queue that stores insertion-data by insertion-costs in ascending order.
* some inis */
*/ PriorityQueue<InsertionData> bestInsertionsQueue = new PriorityQueue<InsertionData>(Math.max(2, currentRoute.getTourActivities().getActivities().size()), getComparator());
TourActivity serviceAct2Insert = activityFactory.createActivities(service).get(0);
int best_insertion_index = InsertionData.NO_INDEX; TourActivities tour = currentRoute.getTourActivities();
double best_insertion_costs = best_known_insertion_costs;
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime); Service service = (Service) jobToInsert;
TourActivity prevAct = start;
int actIndex = 0; /**
double sumOf_prevCosts_newVehicle = 0.0; * some inis
double prevActDepTime_newVehicle = start.getEndTime(); */
TourActivity serviceAct2Insert = activityFactory.createActivities(service).get(0);
int best_insertion_index = InsertionData.NO_INDEX;
initialiseStartAndEnd(newVehicle, newVehicleDepartureTime);
TourActivity prevAct = start;
int actIndex = 0;
double sumOf_prevCosts_newVehicle = 0.0;
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)
* insertion positions.
*
*/
if(memorySize==0){ // return bestInsertion
InsertionData insertion = bestInsertionsQueue.poll();
if(insertion != null){
best_insertion_index = insertion.getDeliveryInsertionIndex();
best_insertion_costs = insertion.getInsertionCost();
}
}
else{
for(int i=0;i<memorySize;i++){
InsertionData data = bestInsertionsQueue.poll();
if(data == null){
continue;
}
/**
* build tour with new activity.
*/
List<TourActivity> wholeTour = new ArrayList<TourActivity>();
wholeTour.add(start);
wholeTour.addAll(currentRoute.getTourActivities().getActivities());
wholeTour.add(end);
wholeTour.add(data.getDeliveryInsertionIndex()+1, serviceAct2Insert);
/** /**
* compute cost-diff of tour with and without new activity --> insertion_costs * the above calculations approximate insertion costs. now calculate the exact insertion costs for the most promising (according to the approximation)
*/ * insertion positions.
*
*/
if (memorySize == 0) { // return bestInsertion
InsertionData insertion = bestInsertionsQueue.poll();
if (insertion != null) {
best_insertion_index = insertion.getDeliveryInsertionIndex();
best_insertion_costs = insertion.getInsertionCost();
}
} else {
for (int i = 0; i < memorySize; i++) {
InsertionData data = bestInsertionsQueue.poll();
if (data == null) {
continue;
}
/**
* build tour with new activity.
*/
List<TourActivity> wholeTour = new ArrayList<TourActivity>();
wholeTour.add(start);
wholeTour.addAll(currentRoute.getTourActivities().getActivities());
wholeTour.add(end);
wholeTour.add(data.getDeliveryInsertionIndex() + 1, serviceAct2Insert);
/**
* 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){
end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
}
else{
end.setLocation(Location.newInstance(newVehicle.getEndLocation().getId()));
end.setTheoreticalEarliestOperationStartTime(0.0);
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
}
}
private double sumOf_prevCosts_oldVehicle(VehicleRoute vehicleRoute, TourActivity act) { if (end == null) {
Double prevCost; end = new End(newVehicle.getEndLocation(), 0.0, newVehicle.getLatestArrival());
if(act instanceof End){ } else {
prevCost = stateManager.getRouteState(vehicleRoute, InternalStates.COSTS,Double.class); end.setLocation(Location.newInstance(newVehicle.getEndLocation().getId()));
} end.setTheoreticalEarliestOperationStartTime(0.0);
else prevCost = stateManager.getActivityState(act, InternalStates.COSTS,Double.class); end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
if(prevCost == null) prevCost = 0.; }
return prevCost; }
}
private Comparator<InsertionData> getComparator() { private double sumOf_prevCosts_oldVehicle(VehicleRoute vehicleRoute, TourActivity act) {
return new Comparator<InsertionData>() { Double prevCost;
if (act instanceof End) {
prevCost = stateManager.getRouteState(vehicleRoute, InternalStates.COSTS, Double.class);
} else prevCost = stateManager.getActivityState(act, InternalStates.COSTS, Double.class);
if (prevCost == null) prevCost = 0.;
return prevCost;
}
@Override private Comparator<InsertionData> getComparator() {
public int compare(InsertionData o1, InsertionData o2) { return new Comparator<InsertionData>() {
if(o1.getInsertionCost() < o2.getInsertionCost()){
return -1;
}
else {
return 1;
}
} @Override
}; public int compare(InsertionData o1, InsertionData o2) {
} if (o1.getInsertionCost() < o2.getInsertionCost()) {
return -1;
} else {
return 1;
}
}
};
}
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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 SoftRouteConstraint softRouteConstraint;
private SoftActivityConstraint softActivityConstraint;
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
private VehicleRoutingTransportCosts transportCosts;
private JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
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){ private SoftActivityConstraint softActivityConstraint;
private ActivityInsertionCostsCalculator activityInsertionCostsCalculator;
private VehicleRoutingTransportCosts transportCosts;
private JobActivityFactory activityFactory;
private AdditionalAccessEgressCalculator additionalAccessEgressCalculator;
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

@ -7,13 +7,13 @@ 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(); private static final Logger logger = LogManager.getLogger();
@Override @Override
public void inform(Event event) { public void inform(Event event) {
if(event instanceof SwitchVehicle){ if (event instanceof SwitchVehicle) {
SwitchVehicle switchVehicle = (SwitchVehicle) event; SwitchVehicle switchVehicle = (SwitchVehicle) event;
if(vehiclesDifferent((SwitchVehicle) event)) { if(vehiclesDifferent((SwitchVehicle) event)) {
logger.trace("switch vehicle (" + ((SwitchVehicle) event).getRoute().getVehicle().getId() + " to " + ((SwitchVehicle) event).getVehicle().getId() + ")"); logger.trace("switch vehicle (" + ((SwitchVehicle) event).getRoute().getVehicle().getId() + " to " + ((SwitchVehicle) 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) {
super();
this.routingCosts = routingCosts;
}
@Override public VariableTransportCostCalculator(VehicleRoutingTransportCosts routingCosts) {
public double getCosts(JobInsertionContext iFacts, TourActivity prevAct,TourActivity newAct, TourActivity nextAct, double depTimeAtPrevAct) { super();
double tp_costs_prevAct_newAct = routingCosts.getTransportCost(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); this.routingCosts = routingCosts;
double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); }
double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct; @Override
double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct); 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());
//open routes double tp_time_prevAct_newAct = routingCosts.getTransportTime(prevAct.getLocation(), newAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
if(nextAct instanceof End){
if(!iFacts.getNewVehicle().isReturnToDepot()){ double newAct_arrTime = depTimeAtPrevAct + tp_time_prevAct_newAct;
return tp_costs_prevAct_newAct; double newAct_endTime = CalculationUtils.getActivityEndTime(newAct_arrTime, newAct);
}
} //open routes
if (nextAct instanceof End) {
double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle()); if (!iFacts.getNewVehicle().isReturnToDepot()) {
double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct; return tp_costs_prevAct_newAct;
}
double oldCosts; }
if(iFacts.getRoute().isEmpty()){
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); double tp_costs_newAct_nextAct = routingCosts.getTransportCost(newAct.getLocation(), nextAct.getLocation(), newAct_endTime, iFacts.getNewDriver(), iFacts.getNewVehicle());
oldCosts = tp_costs_prevAct_nextAct; double totalCosts = tp_costs_prevAct_newAct + tp_costs_newAct_nextAct;
}
else{ double oldCosts;
double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); if (iFacts.getRoute().isEmpty()) {
oldCosts = tp_costs_prevAct_nextAct; double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle());
} oldCosts = tp_costs_prevAct_nextAct;
return totalCosts - oldCosts; } else {
} double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle());
oldCosts = tp_costs_prevAct_nextAct;
}
return totalCosts - oldCosts;
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -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

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate; package jsprit.core.algorithm.recreate;
@ -33,99 +33,97 @@ 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 JobInsertionCostsCalculator insertionCalculator;
private final VehicleRoutingProblem vrp;
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
*
* <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.
* bigger vehicles can take over the route that was previously served by a small vehicle.
*
*/
private boolean vehicleSwitchAllowed = false;
public VehicleTypeDependentJobInsertionCalculator(final VehicleRoutingProblem vrp, final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) { private final VehicleFleetManager fleetManager;
this.fleetManager = fleetManager;
this.insertionCalculator = jobInsertionCalc;
this.vrp = vrp;
getInitialVehicleIds();
logger.debug("initialise " + this);
}
private void getInitialVehicleIds() { private final JobInsertionCostsCalculator insertionCalculator;
private final VehicleRoutingProblem vrp;
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
* <p/>
* <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.
* bigger vehicles can take over the route that was previously served by a small vehicle.
*/
private boolean vehicleSwitchAllowed = false;
public VehicleTypeDependentJobInsertionCalculator(final VehicleRoutingProblem vrp, final VehicleFleetManager fleetManager, final JobInsertionCostsCalculator jobInsertionCalc) {
this.fleetManager = fleetManager;
this.insertionCalculator = jobInsertionCalc;
this.vrp = vrp;
getInitialVehicleIds();
logger.debug("initialise " + this);
}
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(); Vehicle selectedVehicle = currentRoute.getVehicle();
Driver selectedDriver = currentRoute.getDriver(); Driver selectedDriver = currentRoute.getDriver();
InsertionData bestIData = InsertionData.createEmptyInsertionData(); InsertionData bestIData = InsertionData.createEmptyInsertionData();
double bestKnownCost_ = bestKnownCost; double bestKnownCost_ = bestKnownCost;
Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>(); Collection<Vehicle> relevantVehicles = new ArrayList<Vehicle>();
if(!(selectedVehicle instanceof NoVehicle)) { if (!(selectedVehicle instanceof NoVehicle)) {
relevantVehicles.add(selectedVehicle); relevantVehicles.add(selectedVehicle);
if(vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)){ if (vehicleSwitchAllowed && !isVehicleWithInitialRoute(selectedVehicle)) {
relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle)); relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle));
} }
} } else { //if no vehicle has been assigned, i.e. it is an empty route
else{ //if no vehicle has been assigned, i.e. it is an empty route relevantVehicles.addAll(fleetManager.getAvailableVehicles());
relevantVehicles.addAll(fleetManager.getAvailableVehicles()); }
} for (Vehicle v : relevantVehicles) {
for(Vehicle v : relevantVehicles){ double depTime;
double depTime = v.getEarliestDeparture(); if (v == selectedVehicle) depTime = currentRoute.getDepartureTime();
// if(v == selectedVehicle) depTime = currentRoute.getDepartureTime(); else depTime = v.getEarliestDeparture();
// else depTime = v.getEarliestDeparture(); InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_);
InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_); if (iData instanceof NoInsertionFound) {
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) { private boolean isVehicleWithInitialRoute(Vehicle selectedVehicle) {
return initialVehicleIds.contains(selectedVehicle.getId()); return initialVehicleIds.contains(selectedVehicle.getId());
} }
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -20,8 +20,8 @@ import jsprit.core.algorithm.recreate.InsertionData;
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;
public interface BeforeJobInsertionListener extends InsertionListener{ public interface BeforeJobInsertionListener extends InsertionListener {
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route); public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route);
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -21,8 +21,7 @@ import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection; import java.util.Collection;
public interface InsertionEndsListener extends InsertionListener { public interface InsertionEndsListener extends InsertionListener {
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes); public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes);
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -19,11 +19,7 @@ package jsprit.core.algorithm.recreate.listener;
import jsprit.core.algorithm.listener.SearchStrategyModuleListener; import jsprit.core.algorithm.listener.SearchStrategyModuleListener;
public interface InsertionListener extends SearchStrategyModuleListener {
public interface InsertionListener extends SearchStrategyModuleListener{
} }

View file

@ -11,7 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -26,63 +26,63 @@ import java.util.Collection;
public class InsertionListeners { public class InsertionListeners {
private Collection<InsertionListener> listeners = new ArrayList<InsertionListener>();
public Collection<InsertionListener> getListeners(){
return listeners;
}
public void informJobInserted(Job insertedJob, VehicleRoute inRoute, double additionalCosts, double additionalTime){
for(InsertionListener l : listeners){
if(l instanceof JobInsertedListener){
((JobInsertedListener)l).informJobInserted(insertedJob, inRoute, additionalCosts, additionalTime);
}
}
}
public void informVehicleSwitched(VehicleRoute route, Vehicle oldVehicle, Vehicle newVehicle){
for(InsertionListener l : listeners){
if(l instanceof VehicleSwitchedListener){
((VehicleSwitchedListener) l).vehicleSwitched(route, oldVehicle, newVehicle);
}
}
}
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route){
for(InsertionListener l : listeners){
if(l instanceof BeforeJobInsertionListener){
((BeforeJobInsertionListener)l).informBeforeJobInsertion(job, data, route);
}
}
}
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs){
for(InsertionListener l : listeners){
if(l instanceof InsertionStartsListener){
((InsertionStartsListener)l).informInsertionStarts(vehicleRoutes, unassignedJobs);
}
}
}
public void informInsertionEndsListeners(Collection<VehicleRoute> vehicleRoutes) {
for(InsertionListener l : listeners){
if(l instanceof InsertionEndsListener){
((InsertionEndsListener)l).informInsertionEnds(vehicleRoutes);
}
}
}
public void addListener(InsertionListener insertionListener){
listeners.add(insertionListener);
}
public void removeListener(InsertionListener insertionListener){
listeners.remove(insertionListener);
}
public void addAllListeners(Collection<InsertionListener> listeners) { private Collection<InsertionListener> listeners = new ArrayList<InsertionListener>();
for(InsertionListener l : listeners) addListener(l);
} public Collection<InsertionListener> getListeners() {
return listeners;
}
public void informJobInserted(Job insertedJob, VehicleRoute inRoute, double additionalCosts, double additionalTime) {
for (InsertionListener l : listeners) {
if (l instanceof JobInsertedListener) {
((JobInsertedListener) l).informJobInserted(insertedJob, inRoute, additionalCosts, additionalTime);
}
}
}
public void informVehicleSwitched(VehicleRoute route, Vehicle oldVehicle, Vehicle newVehicle) {
for (InsertionListener l : listeners) {
if (l instanceof VehicleSwitchedListener) {
((VehicleSwitchedListener) l).vehicleSwitched(route, oldVehicle, newVehicle);
}
}
}
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
for (InsertionListener l : listeners) {
if (l instanceof BeforeJobInsertionListener) {
((BeforeJobInsertionListener) l).informBeforeJobInsertion(job, data, route);
}
}
}
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs) {
for (InsertionListener l : listeners) {
if (l instanceof InsertionStartsListener) {
((InsertionStartsListener) l).informInsertionStarts(vehicleRoutes, unassignedJobs);
}
}
}
public void informInsertionEndsListeners(Collection<VehicleRoute> vehicleRoutes) {
for (InsertionListener l : listeners) {
if (l instanceof InsertionEndsListener) {
((InsertionEndsListener) l).informInsertionEnds(vehicleRoutes);
}
}
}
public void addListener(InsertionListener insertionListener) {
listeners.add(insertionListener);
}
public void removeListener(InsertionListener insertionListener) {
listeners.remove(insertionListener);
}
public void addAllListeners(Collection<InsertionListener> listeners) {
for (InsertionListener l : listeners) addListener(l);
}
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -22,9 +22,8 @@ import jsprit.core.problem.solution.route.VehicleRoute;
import java.util.Collection; import java.util.Collection;
public interface InsertionStartsListener extends InsertionListener { public interface InsertionStartsListener extends InsertionListener {
public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs); public void informInsertionStarts(Collection<VehicleRoute> vehicleRoutes, Collection<Job> unassignedJobs);
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -20,11 +20,7 @@ import jsprit.core.problem.job.Job;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
public interface JobInsertedListener extends InsertionListener {
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime);
public interface JobInsertedListener extends InsertionListener{
public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime);
} }

View file

@ -1,17 +1,17 @@
/******************************************************************************* /*******************************************************************************
* Copyright (C) 2013 Stefan Schroeder * Copyright (C) 2013 Stefan Schroeder
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version. * 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, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/ ******************************************************************************/
package jsprit.core.algorithm.recreate.listener; package jsprit.core.algorithm.recreate.listener;
@ -19,8 +19,8 @@ package jsprit.core.algorithm.recreate.listener;
import jsprit.core.problem.solution.route.VehicleRoute; import jsprit.core.problem.solution.route.VehicleRoute;
import jsprit.core.problem.vehicle.Vehicle; import jsprit.core.problem.vehicle.Vehicle;
public interface VehicleSwitchedListener extends InsertionListener{ public interface VehicleSwitchedListener extends InsertionListener {
public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle); public void vehicleSwitched(VehicleRoute vehicleRoute, Vehicle oldVehicle, Vehicle newVehicle);
} }

View file

@ -30,7 +30,7 @@ import org.apache.logging.log4j.Logger;
import java.util.Collection; import java.util.Collection;
import java.util.Random; import java.util.Random;
public abstract class AbstractRuinStrategy implements RuinStrategy{ public abstract class AbstractRuinStrategy implements RuinStrategy {
private final static Logger logger = LogManager.getLogger(); private final static Logger logger = LogManager.getLogger();
@ -46,11 +46,11 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
protected RuinShareFactory ruinShareFactory; protected RuinShareFactory ruinShareFactory;
public void setRuinShareFactory(RuinShareFactory ruinShareFactory){ public void setRuinShareFactory(RuinShareFactory ruinShareFactory) {
this.ruinShareFactory = ruinShareFactory; this.ruinShareFactory = ruinShareFactory;
} }
public RuinShareFactory getRuinShareFactory(){ public RuinShareFactory getRuinShareFactory() {
return ruinShareFactory; return ruinShareFactory;
} }
@ -60,11 +60,11 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
} }
@Override @Override
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes){ public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes) {
ruinListeners.ruinStarts(vehicleRoutes); ruinListeners.ruinStarts(vehicleRoutes);
Collection<Job> unassigned = ruinRoutes(vehicleRoutes); Collection<Job> unassigned = ruinRoutes(vehicleRoutes);
logger.trace("ruin: " + "[ruined=" + unassigned.size() + "]"); logger.trace("ruin: [ruined={}]", unassigned.size());
ruinListeners.ruinEnds(vehicleRoutes,unassigned); ruinListeners.ruinEnds(vehicleRoutes, unassigned);
return unassigned; return unassigned;
} }
@ -73,10 +73,10 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
@Override @Override
@Deprecated @Deprecated
public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved){ public Collection<Job> ruin(Collection<VehicleRoute> vehicleRoutes, Job targetJob, int nOfJobs2BeRemoved) {
ruinListeners.ruinStarts(vehicleRoutes); ruinListeners.ruinStarts(vehicleRoutes);
Collection<Job> unassigned = ruinRoutes(vehicleRoutes, targetJob, nOfJobs2BeRemoved); Collection<Job> unassigned = ruinRoutes(vehicleRoutes, targetJob, nOfJobs2BeRemoved);
ruinListeners.ruinEnds(vehicleRoutes,unassigned); ruinListeners.ruinEnds(vehicleRoutes, unassigned);
return unassigned; return unassigned;
} }
@ -99,7 +99,7 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
} }
protected boolean removeJob(Job job, Collection<VehicleRoute> vehicleRoutes) { protected boolean removeJob(Job job, Collection<VehicleRoute> vehicleRoutes) {
if(jobIsInitial(job)) return false; if (jobIsInitial(job)) return false;
for (VehicleRoute route : vehicleRoutes) { for (VehicleRoute route : vehicleRoutes) {
if (removeJob(job, route)) { if (removeJob(job, route)) {
return true; return true;
@ -108,16 +108,16 @@ public abstract class AbstractRuinStrategy implements RuinStrategy{
return false; return false;
} }
private boolean jobIsInitial(Job job){ private boolean jobIsInitial(Job job) {
return !vrp.getJobs().containsKey(job.getId()); //for initial jobs (being not contained in problem return !vrp.getJobs().containsKey(job.getId()); //for initial jobs (being not contained in problem
} }
protected boolean removeJob(Job job, VehicleRoute route) { protected boolean removeJob(Job job, VehicleRoute route) {
if(jobIsInitial(job)) return false; if (jobIsInitial(job)) return false;
boolean removed = route.getTourActivities().removeJob(job); boolean removed = route.getTourActivities().removeJob(job);
if (removed) { if (removed) {
logger.trace("ruin: " + job.getId()); logger.trace("ruin: {}", job.getId());
ruinListeners.removed(job,route); ruinListeners.removed(job, route);
return true; return true;
} }
return false; return false;

View file

@ -5,8 +5,8 @@ import jsprit.core.problem.job.Job;
import java.util.Iterator; import java.util.Iterator;
/** /**
* Created by schroeder on 07/01/15. * Created by schroeder on 07/01/15.
*/ */
public interface JobNeighborhoods { public interface JobNeighborhoods {
public Iterator<Job> getNearestNeighborsIterator(int nNeighbors, Job neighborTo); public Iterator<Job> getNearestNeighborsIterator(int nNeighbors, Job neighborTo);

View file

@ -8,12 +8,12 @@ import jsprit.core.problem.VehicleRoutingProblem;
*/ */
public class JobNeighborhoodsFactory { public class JobNeighborhoodsFactory {
public JobNeighborhoods createNeighborhoods(VehicleRoutingProblem vrp, JobDistance jobDistance){ public JobNeighborhoods createNeighborhoods(VehicleRoutingProblem vrp, JobDistance jobDistance) {
return new JobNeighborhoodsImpl(vrp,jobDistance); return new JobNeighborhoodsImpl(vrp, jobDistance);
} }
public JobNeighborhoods createNeighborhoods(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity){ public JobNeighborhoods createNeighborhoods(VehicleRoutingProblem vrp, JobDistance jobDistance, int capacity) {
return new JobNeighborhoodsImplWithCapRestriction(vrp,jobDistance,capacity); return new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, capacity);
} }
} }

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