From e2c9c59568b1d68587d877d22ebf2711077d86d7 Mon Sep 17 00:00:00 2001 From: braktar Date: Wed, 7 Sep 2016 12:54:07 +0200 Subject: [PATCH 001/106] breakId fix & custom --- .../com/graphhopper/jsprit/io/problem/VrpXMLReader.java | 3 ++- .../com/graphhopper/jsprit/io/problem/VrpXMLWriter.java | 6 +++--- jsprit-io/src/main/resources/vrp_xml_schema.xsd | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLReader.java b/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLReader.java index 0b5148c3..504d39c4 100644 --- a/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLReader.java +++ b/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLReader.java @@ -701,7 +701,8 @@ public class VrpXMLReader { List breakTWConfigs = vehicleConfig.configurationsAt("breaks.timeWindows.timeWindow"); if (!breakTWConfigs.isEmpty()) { String breakDurationString = vehicleConfig.getString("breaks.duration"); - Break.Builder current_break = Break.Builder.newInstance(vehicleId); + String id = vehicleConfig.getString("breaks.id"); + Break.Builder current_break = Break.Builder.newInstance(id); current_break.setServiceTime(Double.parseDouble(breakDurationString)); for (HierarchicalConfiguration twConfig : breakTWConfigs) { current_break.addTimeWindow(TimeWindow.newInstance(twConfig.getDouble("start"), twConfig.getDouble("end"))); diff --git a/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java b/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java index 15dd7913..024d4958 100644 --- a/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java +++ b/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java @@ -203,12 +203,12 @@ public class VrpXMLWriter { xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ")[@type]", act.getName()); if (act instanceof TourActivity.JobActivity) { Job job = ((TourActivity.JobActivity) act).getJob(); - if (job instanceof Service) { + if (job instanceof Break) { + xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").breakId", job.getId()); + } else if (job instanceof Service) { xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").serviceId", job.getId()); } else if (job instanceof Shipment) { xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").shipmentId", job.getId()); - } else if (job instanceof Break) { - xmlConfig.setProperty(solutionPath + "(" + counter + ").routes.route(" + routeCounter + ").act(" + actCounter + ").breakId", job.getId()); } else { throw new IllegalStateException("cannot write solution correctly since job-type is not know. make sure you use either service or shipment, or another writer"); } diff --git a/jsprit-io/src/main/resources/vrp_xml_schema.xsd b/jsprit-io/src/main/resources/vrp_xml_schema.xsd index 9d67a9d9..04a36b26 100644 --- a/jsprit-io/src/main/resources/vrp_xml_schema.xsd +++ b/jsprit-io/src/main/resources/vrp_xml_schema.xsd @@ -395,6 +395,7 @@ + From d795cf368037f977960e11e1d623a21f02d43a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Fri, 23 Sep 2016 16:28:59 +0200 Subject: [PATCH 002/106] add md so files can be located --- docs/More-Examples.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/More-Examples.md b/docs/More-Examples.md index e855bb89..6fb6ed0d 100644 --- a/docs/More-Examples.md +++ b/docs/More-Examples.md @@ -1,9 +1,9 @@ -#### [Multiple Depot VRP](Multiple-Depot-VRP) +#### [Multiple Depot VRP](Multiple-Depot-VRP.md) - setting up a VRP with Multiple Depots - defining depots, vehicles and their types - dealing with finite fleet size -#### [VRP with time windows](VRP-with-time-windows-example) +#### [VRP with time windows](VRP-with-time-windows-example.md) - defining and creating vehicles and their types - defining services with time-windows and service times - defining a problem with infinite fleet-size @@ -13,13 +13,13 @@ - defining and creating pickup and deliveries - defining backhaul constraint -#### [VRP with backhauls (with mixed pickup and deliveries)](VRP-with-depot-bounded-pickups-and-deliveries) +#### [VRP with backhauls (with mixed pickup and deliveries)](VRP-with-depot-bounded-pickups-and-deliveries.md) - defining and creating depot-bounded pickups and deliveries -#### [VRP with pickup and delivieries](VRP-with-pickups-and-deliveries) +#### [VRP with pickup and delivieries](VRP-with-pickups-and-deliveries.md) - defining and creating pickups and deliveries -#### [VRP with heterogeneous fleet](Heterogeneous-Fleet) +#### [VRP with heterogeneous fleet](Heterogeneous-Fleet.md) - illustrating different problem types, - specifying heterogeneous fleet with its vehicles and vehicle-types, - specifying the algorithm, From a0542722e2b4c184995b1abee3e8251161019edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Fri, 23 Sep 2016 16:29:51 +0200 Subject: [PATCH 003/106] add md so files can be located --- docs/More-Examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/More-Examples.md b/docs/More-Examples.md index 6fb6ed0d..e5173c48 100644 --- a/docs/More-Examples.md +++ b/docs/More-Examples.md @@ -9,7 +9,7 @@ - defining a problem with infinite fleet-size - reading, creating and running an algorithm -#### [VRP with backhauls](VRP-with-backhauls-example) +#### [VRP with backhauls](VRP-with-backhauls-example.md) - defining and creating pickup and deliveries - defining backhaul constraint From ce3d37d91cc76c3bff8fad9e4e63a6f3a3f9a4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Fri, 23 Sep 2016 16:32:26 +0200 Subject: [PATCH 004/106] add md so files can be located --- docs/More-Examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/More-Examples.md b/docs/More-Examples.md index e5173c48..dd8b6147 100644 --- a/docs/More-Examples.md +++ b/docs/More-Examples.md @@ -16,7 +16,7 @@ #### [VRP with backhauls (with mixed pickup and deliveries)](VRP-with-depot-bounded-pickups-and-deliveries.md) - defining and creating depot-bounded pickups and deliveries -#### [VRP with pickup and delivieries](VRP-with-pickups-and-deliveries.md) +#### [VRP with pickup and delivieries](Vrp-with-pickups-and-deliveries.md) - defining and creating pickups and deliveries #### [VRP with heterogeneous fleet](Heterogeneous-Fleet.md) From c1a5f82ba1e4cd4c55a91e2c07d31b51e54d4552 Mon Sep 17 00:00:00 2001 From: muzuro Date: Wed, 28 Sep 2016 12:06:01 +0300 Subject: [PATCH 005/106] fix memory leak --- .../graphhopper/jsprit/core/algorithm/box/Jsprit.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 818767f2..0ada8a96 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -629,13 +629,21 @@ public class Jsprit { }); } if (es != null) { - Runtime.getRuntime().addShutdownHook(new Thread() { + final Thread hook = new Thread() { public void run() { if (!es.isShutdown()) { System.err.println("shutdowHook shuts down executorService"); es.shutdown(); } } + }; + Runtime.getRuntime().addShutdownHook(hook); + vra.addListener(new AlgorithmEndsListener() { + @Override + public void informAlgorithmEnds(VehicleRoutingProblem aProblem, + Collection aSolutions) { + Runtime.getRuntime().removeShutdownHook(hook); + } }); } } From 5ef8ba12e971d922230df41893c571e0d46ca4ed Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 29 Sep 2016 12:52:10 +0200 Subject: [PATCH 006/106] move hook stuff to if - related to #282 --- .../jsprit/core/algorithm/box/Jsprit.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 0ada8a96..83551cc5 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -619,33 +619,36 @@ public class Jsprit { private void handleExecutorShutdown(VehicleRoutingAlgorithm vra) { if (setupExecutorInternally) { - vra.addListener(new AlgorithmEndsListener() { - - @Override - public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection solutions) { - es.shutdown(); - } - - }); - } - if (es != null) { final Thread hook = new Thread() { public void run() { if (!es.isShutdown()) { - System.err.println("shutdowHook shuts down executorService"); + System.err.println("shutdownHook shuts down executorService"); es.shutdown(); } } }; Runtime.getRuntime().addShutdownHook(hook); vra.addListener(new AlgorithmEndsListener() { + @Override - public void informAlgorithmEnds(VehicleRoutingProblem aProblem, - Collection aSolutions) { + public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection solutions) { + es.shutdown(); Runtime.getRuntime().removeShutdownHook(hook); } + }); } +// if (es != null) { +// +// Runtime.getRuntime().addShutdownHook(hook); +// vra.addListener(new AlgorithmEndsListener() { +// @Override +// public void informAlgorithmEnds(VehicleRoutingProblem aProblem, +// Collection aSolutions) { +// Runtime.getRuntime().removeShutdownHook(hook); +// } +// }); +// } } String getProperty(String key) { From 76fe48a798564d9dd8d1888f1f810cd1f1076e0d Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 30 Sep 2016 08:42:10 +0200 Subject: [PATCH 007/106] remove warn --- .../jsprit/core/algorithm/VehicleRoutingAlgorithm.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index 37918884..7bdeae78 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -160,10 +160,10 @@ public class VehicleRoutingAlgorithm { } } } - if (nuJobs != 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.", nuJobs, problem.getJobs().values().size()); - } +// if (nuJobs != 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.", nuJobs, problem.getJobs().values().size()); +// } } /** From e7d1019b8f41006d1df5a5c2ab9e631d726d8bf0 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 5 Oct 2016 09:01:04 +0200 Subject: [PATCH 008/106] add name to location --- .../graphhopper/jsprit/core/problem/Location.java | 12 ++++++++++++ .../jsprit/core/problem/LocationTest.java | 9 ++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java index 00f10bf1..4d1dbb64 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java @@ -64,6 +64,8 @@ public final class Location implements HasIndex, HasId { private Coordinate coordinate; + private String name = ""; + public static Builder newInstance() { return new Builder(); } @@ -84,6 +86,11 @@ public final class Location implements HasIndex, HasId { return this; } + public Builder setName(String name){ + this.name = name; + return this; + } + public Location build() { if (id == null && coordinate == null) { if (index == -1) throw new IllegalArgumentException("either id or coordinate or index must be set"); @@ -107,10 +114,13 @@ public final class Location implements HasIndex, HasId { private final String id; + private final String name; + private Location(Builder builder) { this.index = builder.index; this.coordinate = builder.coordinate; this.id = builder.id; + this.name = builder.name; } @Override @@ -127,6 +137,8 @@ public final class Location implements HasIndex, HasId { return coordinate; } + public String getName() { return name; } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java index 8119b59e..f237eadb 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java @@ -19,7 +19,8 @@ package com.graphhopper.jsprit.core.problem; import com.graphhopper.jsprit.core.util.Coordinate; -import junit.framework.Assert; + +import org.junit.Assert; import org.junit.Test; /** @@ -34,6 +35,12 @@ public class LocationTest { Assert.assertTrue(true); } + @Test + public void whenNameSet_buildLocation() { + Location l = Location.Builder.newInstance().setName("mystreet 6a").setIndex(1).build(); + Assert.assertEquals("mystreet 6a",l.getName()); + } + @Test public void whenIndexSetWitFactory_returnCorrectLocation() { Location l = Location.newInstance(1); From 6143e73645ac5bc7099e1e90a9b4f52c85bc7844 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 5 Oct 2016 09:03:07 +0200 Subject: [PATCH 009/106] add name to location --- .../com/graphhopper/jsprit/core/problem/LocationTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java index f237eadb..edcd76ff 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java @@ -75,8 +75,8 @@ public class LocationTest { @Test public void whenCoordinateSet_build() { Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 20)).build(); - Assert.assertEquals(10., l.getCoordinate().getX()); - Assert.assertEquals(20., l.getCoordinate().getY()); + Assert.assertEquals(10., l.getCoordinate().getX(),0.001); + Assert.assertEquals(20., l.getCoordinate().getY(),0.001); Assert.assertTrue(true); } @@ -84,8 +84,8 @@ public class LocationTest { public void whenCoordinateSetWithFactory_returnCorrectLocation() { // Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build(); Location l = Location.newInstance(10, 20); - Assert.assertEquals(10., l.getCoordinate().getX()); - Assert.assertEquals(20., l.getCoordinate().getY()); + Assert.assertEquals(10., l.getCoordinate().getX(),0.001); + Assert.assertEquals(20., l.getCoordinate().getY(),0.001); Assert.assertTrue(true); } From 87e933aafc0b48d178c8a8a16aeee58c1a0049bc Mon Sep 17 00:00:00 2001 From: oblonski Date: Sun, 16 Oct 2016 21:00:44 +0200 Subject: [PATCH 010/106] add docs to location --- .../jsprit/core/problem/Location.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java index 4d1dbb64..f9721e15 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java @@ -70,22 +70,46 @@ public final class Location implements HasIndex, HasId { return new Builder(); } + /** + * Sets location index + * + * @param index + * @return the builder + */ public Builder setIndex(int index) { if (index < 0) throw new IllegalArgumentException("index must be >= 0"); this.index = index; return this; } + /** + * Sets coordinate of location + * + * @param coordinate + * @return + */ public Builder setCoordinate(Coordinate coordinate) { this.coordinate = coordinate; return this; } + /** + * Sets location id + * + * @param id + * @return + */ public Builder setId(String id) { this.id = id; return this; } + /** + * Adds name, e.g. street name, to location + * + * @param name + * @return + */ public Builder setName(String name){ this.name = name; return this; From a7c10b2e947dae587b884eeadb5fa66e3cd96138 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 18 Oct 2016 13:00:13 +0200 Subject: [PATCH 011/106] improve docs - related to #288 --- README.md | 4 +--- docs/Getting-Started.md | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8037f981..574004a7 100644 --- a/README.md +++ b/README.md @@ -51,9 +51,7 @@ You can also use [stackoverflow](http://stackoverflow.com/questions/tagged/jspri For bugs, feature requests or similar use the [issue tracker](https://github.com/jsprit/jsprit/issues). ####Email: -If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, send an email to: - -info@graphhopper.com +If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, contact us via https://graphhopper.com/#contact ##About diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index 557acac9..e46475b0 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -1,5 +1,5 @@ ####Requirements -jsprit requires the Java 2 platform (JDK version 1.7.0 or later). +jsprit requires JDK version 1.7.0 or later. ####Modules jsprit is a multi-module project and consists of: From 8d1680171278f265e49b8814fd44acf83f322662 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 18 Oct 2016 15:09:49 +0200 Subject: [PATCH 012/106] improve docs - related to #288 --- docs/Getting-Started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index e46475b0..c49fe090 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -1,5 +1,5 @@ ####Requirements -jsprit requires JDK version 1.7.0 or later. +jsprit requires Java 1.7.0 or later. ####Modules jsprit is a multi-module project and consists of: From eb9f72b2d15c1d4a6202a0fede0cffa88e080652 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 18 Oct 2016 15:25:23 +0200 Subject: [PATCH 013/106] simplify adding time and distance to cost matrix --- .../core/util/FastVehicleRoutingTransportCostsMatrix.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java index 4249faba..80742c4c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java @@ -94,6 +94,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic return this; } + public Builder addTransportTimeAndDistance(int fromIndex, int toIndex, double time, double distance){ + addTransportTime(fromIndex, toIndex, time); + addTransportDistance(fromIndex,toIndex,distance); + return this; + } /** * Builds the matrix. * From 51740a21d69a7686e60abcba24dba224d6b911d1 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 18 Oct 2016 20:17:24 +0200 Subject: [PATCH 014/106] test adding time and distance to cost matrix --- .../FastVehicleRoutingTransportCostsMatrixTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrixTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrixTest.java index 8acb99b9..bde92c11 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrixTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrixTest.java @@ -40,6 +40,7 @@ public class FastVehicleRoutingTransportCostsMatrixTest { assertEquals(2., matrix.getDistance(2, 1), 0.1); } + @Test public void whenAddingDistanceToAsymmetricMatrix_itShouldReturnCorrectValues() { FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, false); @@ -62,6 +63,18 @@ public class FastVehicleRoutingTransportCostsMatrixTest { assertEquals(2., matrix.getTransportTime(loc(2), loc(1), 0.0, null, null), 0.1); } + @Test + public void whenAddingTimeAndDistanceToSymmetricMatrix_itShouldReturnCorrectValues2() { + FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, true); + matrixBuilder.addTransportTimeAndDistance(1, 2, 2.,100.); + FastVehicleRoutingTransportCostsMatrix matrix = matrixBuilder.build(); + assertEquals(2., matrix.getTransportTime(loc(1), loc(2), 0.0, null, null), 0.1); + assertEquals(2., matrix.getTransportTime(loc(2), loc(1), 0.0, null, null), 0.1); + + assertEquals(100., matrix.getDistance(loc(1), loc(2), 0.0, null), 0.1); + assertEquals(100., matrix.getDistance(loc(2), loc(1), 0.0, null), 0.1); + } + @Test public void whenAddingTimeToAsymmetricMatrix_itShouldReturnCorrectValues() { FastVehicleRoutingTransportCostsMatrix.Builder matrixBuilder = FastVehicleRoutingTransportCostsMatrix.Builder.newInstance(3, false); From 4542f8370da4a8a4b89afc7caae2a4afa5a8ad44 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 1 Nov 2016 08:44:08 +0100 Subject: [PATCH 015/106] remove unused field --- .../graphhopper/jsprit/core/problem/VehicleRoutingProblem.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java index e93c9e61..544c4fe9 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/VehicleRoutingProblem.java @@ -568,8 +568,6 @@ public class VehicleRoutingProblem { */ private final FleetSize fleetSize; - private final Locations locations; - private Map> activityMap; private int nuActivities; @@ -591,7 +589,6 @@ public class VehicleRoutingProblem { this.initialVehicleRoutes = builder.initialRoutes; this.transportCosts = builder.transportCosts; this.activityCosts = builder.activityCosts; - this.locations = builder.getLocations(); this.activityMap = builder.activityMap; this.nuActivities = builder.activityIndexCounter; this.allLocations = builder.allLocations; From f8ea447cb9f6934c41650760c47e07fdbb1d62c9 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 2 Nov 2016 14:23:23 +0100 Subject: [PATCH 016/106] add max distance feature - related to #285 --- .../VehicleDependentTraveledDistance.java | 120 ++++++++++++++++++ .../constraint/MaxDistanceConstraint.java | 117 +++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/state/VehicleDependentTraveledDistance.java create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/state/VehicleDependentTraveledDistance.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/state/VehicleDependentTraveledDistance.java new file mode 100644 index 00000000..bde4058b --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/state/VehicleDependentTraveledDistance.java @@ -0,0 +1,120 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.algorithm.state; + +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.cost.TransportDistance; +import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.activity.ActivityVisitor; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; +import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeKey; + +import java.util.*; + +/** + * Created by schroeder on 17/05/16. + */ +public class VehicleDependentTraveledDistance implements StateUpdater, ActivityVisitor { + + static class State { + + Location prevLocation; + + double distance; + + public State(Location prevLocation, double distance) { + this.prevLocation = prevLocation; + this.distance = distance; + } + + public Location getPrevLocation() { + return prevLocation; + } + + public double getDistance() { + return distance; + } + } + + private final TransportDistance transportDistance; + + private final StateManager stateManager; + + private final StateId traveledDistanceId; + + private VehicleRoute route; + + private List uniqueVehicles; + + private Map states; + + public VehicleDependentTraveledDistance(TransportDistance transportCostMatrices, StateManager stateManager, StateId distanceInRouteId, Collection vehicles) { + this.transportDistance = transportCostMatrices; + this.stateManager = stateManager; + this.traveledDistanceId = distanceInRouteId; + uniqueVehicles = getUniqueVehicles(vehicles); + } + + private List getUniqueVehicles(Collection vehicles) { + Set types = new HashSet<>(); + List uniqueVehicles = new ArrayList<>(); + for(Vehicle v : vehicles){ + if(!types.contains(v.getVehicleTypeIdentifier())){ + types.add(v.getVehicleTypeIdentifier()); + uniqueVehicles.add(v); + } + } + return uniqueVehicles; + } + + @Override + public void begin(VehicleRoute route) { + this.route = route; + states = new HashMap<>(); + for(Vehicle v : uniqueVehicles){ + State state = new State(v.getStartLocation(),0); + states.put(v.getVehicleTypeIdentifier(),state); + } + } + + @Override + public void visit(TourActivity activity) { + for(Vehicle v : uniqueVehicles){ + State old = states.get(v.getVehicleTypeIdentifier()); + double distance = old.getDistance(); + distance += transportDistance.getDistance(old.getPrevLocation(),activity.getLocation(),0,v); + stateManager.putActivityState(activity,v,traveledDistanceId,distance); + states.put(v.getVehicleTypeIdentifier(),new State(activity.getLocation(),distance)); + } + } + + @Override + public void finish() { + for(Vehicle v : uniqueVehicles){ + State old = states.get(v.getVehicleTypeIdentifier()); + double distance = old.getDistance(); + if(v.isReturnToDepot()) { + distance += transportDistance.getDistance(old.getPrevLocation(), v.getEndLocation(), 0, v); + } + stateManager.putRouteState(route,v,traveledDistanceId, distance); + } + } + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java new file mode 100644 index 00000000..9e3f790c --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -0,0 +1,117 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.problem.constraint; + +import com.graphhopper.jsprit.core.algorithm.state.StateId; +import com.graphhopper.jsprit.core.algorithm.state.StateManager; +import com.graphhopper.jsprit.core.problem.cost.TransportDistance; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment; +import com.graphhopper.jsprit.core.problem.solution.route.activity.End; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; +import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; + +import java.util.Collection; +import java.util.Map; + +/** + * Created by schroeder on 11/10/16. + */ +public class MaxDistanceConstraint implements HardActivityConstraint{ + + private StateManager stateManager; + + private StateId distanceId; + + private TransportDistance distanceCalculator; + + private Double[] maxDistances; + + public MaxDistanceConstraint(StateManager stateManager, StateId distanceId, TransportDistance distanceCalculator, Map maxDistancePerVehicleMap) { + this.stateManager = stateManager; + this.distanceId = distanceId; + this.distanceCalculator = distanceCalculator; + makeArray(maxDistancePerVehicleMap); + } + + private void makeArray(Map maxDistances) { + int maxIndex = getMaxIndex(maxDistances.keySet()); + this.maxDistances = new Double[maxIndex]; + for(Vehicle v : maxDistances.keySet()){ + this.maxDistances[v.getIndex()]=maxDistances.get(v); + } + } + + private int getMaxIndex(Collection vehicles) { + int index = 0; + for(Vehicle v : vehicles){ + if(v.getIndex() > index) index = v.getIndex(); + } + return index; + } + + @Override + public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { + if(!hasMaxDistance(iFacts.getNewVehicle())) return ConstraintsStatus.FULFILLED; + Double currentDistance = 0d; + if(!iFacts.getRoute().isEmpty()){ + currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class); + } + + double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); + double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); + if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){ + distanceNewAct2nextAct = 0; + distancePrevAct2NextAct = 0; + } + double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); + double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct; + + double maxDistance = getMaxDistance(iFacts.getNewVehicle()); + if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED; + + if(newAct instanceof DeliverShipment){ + int iIndexOfPickup = iFacts.getRelatedActivityContext().getInsertionIndex(); + TourActivity pickup = iFacts.getAssociatedActivities().get(0); + TourActivity actBeforePickup; + TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); + if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1); + else actBeforePickup = iFacts.getRoute().getStart(); + double additionalDistanceOfPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(),pickup.getLocation(),0,iFacts.getNewVehicle()) + + distanceCalculator.getDistance(pickup.getLocation(),actAfterPickup.getLocation(),0,iFacts.getNewVehicle()) + - distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(),0,iFacts.getNewVehicle()); + + if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){ + return ConstraintsStatus.NOT_FULFILLED; + } + } + + return ConstraintsStatus.FULFILLED; + } + + private boolean hasMaxDistance(Vehicle newVehicle){ + return this.maxDistances[newVehicle.getIndex()] != null; + } + + private double getMaxDistance(Vehicle newVehicle) { + Double maxDistance = this.maxDistances[newVehicle.getIndex()]; + if(maxDistance == null) return Double.MAX_VALUE; + return maxDistance; + } +} From f9242935207623982d1eca3b55623d7859013301 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 8 Nov 2016 11:20:51 +0100 Subject: [PATCH 017/106] remove Double.MAX_VALUE - related to #286 --- ...nsertionConsideringFixCostsCalculator.java | 63 +++--- ...tionConsideringFixCostsCalculatorTest.java | 191 +++++++++++++----- 2 files changed, 170 insertions(+), 84 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java index 19e7cfd9..1ce3d98e 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java @@ -35,32 +35,32 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos private static final Logger logger = LoggerFactory.getLogger(JobInsertionConsideringFixCostsCalculator.class); - private final JobInsertionCostsCalculator standardServiceInsertion; + private final JobInsertionCostsCalculator standardInsertion; - private double weight_deltaFixCost = 0.5; + private double weightDeltaFixCost = 0.5; - private double solution_completeness_ratio = 0.5; + private double solutionCompletenessRatio = 0.5; private RouteAndActivityStateGetter stateGetter; - public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardInsertionCalculator, RouteAndActivityStateGetter stateGetter) { + public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardCalculator, RouteAndActivityStateGetter stateGetter) { super(); - this.standardServiceInsertion = standardInsertionCalculator; + this.standardInsertion = standardCalculator; this.stateGetter = stateGetter; - logger.debug("inialise {}", this); + logger.debug("initialise {}", 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) { + double fixedCostContribution = getFixCostContribution(currentRoute, jobToInsert, newVehicle); + if (fixedCostContribution > bestKnownPrice) { return InsertionData.createEmptyInsertionData(); } - InsertionData iData = standardServiceInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice); + InsertionData iData = standardInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice); if (iData instanceof InsertionData.NoInsertionFound) { return iData; } - double totalInsertionCost = iData.getInsertionCost() + fixcost_contribution; + double totalInsertionCost = iData.getInsertionCost() + fixedCostContribution; InsertionData insertionData = new InsertionData(totalInsertionCost, iData.getPickupInsertionIndex(), iData.getDeliveryInsertionIndex(), newVehicle, newDriver); insertionData.setVehicleDepartureTime(newVehicleDepartureTime); insertionData.getEvents().addAll(iData.getEvents()); @@ -70,55 +70,42 @@ final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCos private double getFixCostContribution(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle) { Capacity currentMaxLoadInRoute = getCurrentMaxLoadInRoute(currentRoute); double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute); - double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute); - double deltaFixCost = (1 - solution_completeness_ratio) * relFixCost + solution_completeness_ratio * absFixCost; - double fixcost_contribution = weight_deltaFixCost * solution_completeness_ratio * deltaFixCost; - return fixcost_contribution; + double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle); + double deltaFixCost = (1 - solutionCompletenessRatio) * relFixCost + solutionCompletenessRatio * absFixCost; + return weightDeltaFixCost * solutionCompletenessRatio * deltaFixCost; } public void setWeightOfFixCost(double weight) { - weight_deltaFixCost = weight; + weightDeltaFixCost = weight; logger.debug("set weightOfFixCostSaving to {}", weight); } @Override public String toString() { - return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weight_deltaFixCost + "]"; + return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; } public void setSolutionCompletenessRatio(double ratio) { - solution_completeness_ratio = ratio; + solutionCompletenessRatio = ratio; } - public double getSolutionCompletenessRatio() { return solution_completeness_ratio; } + public double getSolutionCompletenessRatio() { return solutionCompletenessRatio; } - private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentMaxLoadInRoute) { - Capacity load = Capacity.addup(currentMaxLoadInRoute, job.getSize()); - double currentFix = 0.0; - if (route.getVehicle() != null) { - if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { - currentFix += route.getVehicle().getType().getVehicleCostParams().fix; - } - } - if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) { - return Double.MAX_VALUE; + private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle) { + double currentFix = 0d; + if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { + currentFix = route.getVehicle().getType().getVehicleCostParams().fix; } return newVehicle.getType().getVehicleCostParams().fix - currentFix; } private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentLoad) { Capacity load = Capacity.addup(currentLoad, job.getSize()); - double currentRelFix = 0.0; - if (route.getVehicle() != null) { - if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { - currentRelFix += route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions()); - } + double currentRelFix = 0d; + if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { + currentRelFix = route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions()); } - if (!newVehicle.getType().getCapacityDimensions().isGreaterOrEqual(load)) { - return Double.MAX_VALUE; - } - double relativeFixCost = newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix; - return relativeFixCost; + return newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix; } private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) { diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java index f3367979..7f674c09 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java @@ -36,9 +36,11 @@ public class JobInsertionConsideringFixCostsCalculatorTest { private JobInsertionConsideringFixCostsCalculator calc; - private Vehicle oVehicle; + private Vehicle small; - private Vehicle nVehicle; + private Vehicle medium; + + private Vehicle large; private Job job; @@ -52,18 +54,23 @@ public class JobInsertionConsideringFixCostsCalculatorTest { job = mock(Job.class); when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).build()); - oVehicle = mock(Vehicle.class); - VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).setFixedCost(50.0).build(); - when(oVehicle.getType()).thenReturn(oType); + small = mock(Vehicle.class); + VehicleType smallType = VehicleTypeImpl.Builder.newInstance("smallType").addCapacityDimension(0, 50).setFixedCost(50.0).build(); + when(small.getType()).thenReturn(smallType); - nVehicle = mock(Vehicle.class); - VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).setFixedCost(100.0).build(); - when(nVehicle.getType()).thenReturn(type); + medium = mock(Vehicle.class); + VehicleType mediumType = VehicleTypeImpl.Builder.newInstance("mediumType").addCapacityDimension(0, 100).setFixedCost(100.0).build(); + when(medium.getType()).thenReturn(mediumType); - InsertionData iData = new InsertionData(0.0, 1, 1, nVehicle, null); + large = mock(Vehicle.class); + VehicleType largeType = VehicleTypeImpl.Builder.newInstance("largeType").addCapacityDimension(0, 400).setFixedCost(200.0).build(); + when(large.getType()).thenReturn(largeType); + + InsertionData iData = new InsertionData(0.0, 1, 1, medium, null); route = mock(VehicleRoute.class); - when(jobInsertionCosts.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE)).thenReturn(iData); + when(jobInsertionCosts.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE)).thenReturn(iData); + when(jobInsertionCosts.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE)).thenReturn(new InsertionData(0.0, 1, 1, large, null)); stateGetter = mock(RouteAndActivityStateGetter.class); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().build()); @@ -76,7 +83,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(1.0); calc.setWeightOfFixCost(1.0); //(1.*absFix + 0.*relFix) * completeness * weight = (1.*100. + 0.*50.) * 1. * 1. = 100. - assertEquals(100., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(100., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -84,7 +91,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(0.0); calc.setWeightOfFixCost(1.0); //(0.*absFix + 1.*relFix) * completeness * weight = 0. - assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -92,7 +99,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(0.5); calc.setWeightOfFixCost(1.0); //(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*100+0.5*50)*0.5*1. = 37.5 - assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(37.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -100,7 +107,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(0.75); calc.setWeightOfFixCost(1.0); //(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*100.+0.25*50.)*0.75*1. = 65.625 - assertEquals(65.625, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(65.625, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -108,7 +115,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(1.0); calc.setWeightOfFixCost(.5); //(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*100. + 0.*50.) * 1. * 0.5 = 5. - assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(50., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -116,7 +123,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(0.0); calc.setWeightOfFixCost(.5); //(0.*absFix + 1.*relFix) * 0. * .5 = 0. - assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -124,7 +131,7 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(0.5); calc.setWeightOfFixCost(.5); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*100+0.5*50)*0.5*0.5 = 18.75 - assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(18.75, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -132,98 +139,98 @@ public class JobInsertionConsideringFixCostsCalculatorTest { calc.setSolutionCompletenessRatio(0.75); calc.setWeightOfFixCost(0.5); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*100.+0.25*50.)*0.75*0.5 = 32.8125 - assertEquals(32.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(32.8125, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionComplete_itShouldReturnHalfOfFixedCostsOfNewVehicle() { calc.setSolutionCompletenessRatio(1.0); calc.setWeightOfFixCost(1.0); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(1.*absFix + 0.*relFix) * completeness * weight = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 1. = 50. - assertEquals(50., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(50., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() { calc.setSolutionCompletenessRatio(0.0); calc.setWeightOfFixCost(1.0); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.*absFix + 1.*relFix) * completeness * weight = 0. - assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs50PercentComplete_itShouldCorrectVal() { calc.setSolutionCompletenessRatio(0.5); calc.setWeightOfFixCost(1.0); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*(100-50)+0.5*(50-0))*0.5*1. = 25. - assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(25., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs75PercentComplete_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(0.75); calc.setWeightOfFixCost(1.0); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*(100.-50.)+0.25*(50.-0.))*0.75*1. = 37.5 - assertEquals(37.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(37.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionCompleteAndWeightIs05_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(1.0); calc.setWeightOfFixCost(.5); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 0.5 = 25. - assertEquals(25., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(25., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(0.0); calc.setWeightOfFixCost(.5); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.*absFix + 1.*relFix) * 0. * .5 = 0. - assertEquals(0., calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(0.5); calc.setWeightOfFixCost(.5); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(50-0))*0.5*0.5 = 12.5 - assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(12.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(0.75); calc.setWeightOfFixCost(0.5); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(50.-0.))*0.75*0.5 = 18.75 - assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(18.75, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(0.5); calc.setWeightOfFixCost(.5); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).build()); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 - assertEquals(12.5, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(12.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { calc.setSolutionCompletenessRatio(0.75); calc.setWeightOfFixCost(0.5); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(75.-25.))*0.75*0.5 = 18.75 - assertEquals(18.75, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(18.75, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } @Test @@ -234,12 +241,12 @@ public class JobInsertionConsideringFixCostsCalculatorTest { when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build(); - when(oVehicle.getType()).thenReturn(oType); + when(small.getType()).thenReturn(oType); VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build(); - when(nVehicle.getType()).thenReturn(type); + when(medium.getType()).thenReturn(type); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 /* @@ -249,7 +256,99 @@ public class JobInsertionConsideringFixCostsCalculatorTest { * = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5 * = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125 */ - assertEquals(7.8125, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(7.8125, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + } + + @Test + public void whenOldVehicleIsMoreExpensive() { + calc.setSolutionCompletenessRatio(1); + calc.setWeightOfFixCost(1); + + when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); + + VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build(); + when(medium.getType()).thenReturn(oType); + + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build(); + when(small.getType()).thenReturn(type); + + + when(route.getVehicle()).thenReturn(small); + when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); + //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 + /* + * (0.5*(100-50)+0.5*( + * relFixNew - relFixOld = (75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.) = + * )*0.5*0.5 + * = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5 + * = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125 + */ + double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + assertEquals(-50d, insertionCost, 0.01); + } + + @Test + public void smallVSMediumAbsCosts() { + calc.setSolutionCompletenessRatio(1); + calc.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(small); + double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + assertEquals(50d, insertionCost, 0.01); + } + + @Test + public void smallVSLargeAbsCosts() { + calc.setSolutionCompletenessRatio(1); + calc.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(small); + double insertionCost = calc.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + assertEquals(150d, insertionCost, 0.01); + } + + @Test + public void largeVSMediumAbsCosts() { + calc.setSolutionCompletenessRatio(1); + calc.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(large); + double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + assertEquals(-100d, insertionCost, 0.01); + } + + @Test + public void mediumVSLargeAbsCosts() { + calc.setSolutionCompletenessRatio(1); + calc.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(medium); + double insertionCost = calc.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + assertEquals(100d, insertionCost, 0.01); + } + + @Test + public void whenOldVehicleIsMoreExpensive2() { + calc.setSolutionCompletenessRatio(0.1); + calc.setWeightOfFixCost(1); + + when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); + + VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build(); + when(medium.getType()).thenReturn(oType); + + VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build(); + when(small.getType()).thenReturn(type); + + + when(route.getVehicle()).thenReturn(small); + when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); + //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 + /* + * (0.5*(100-50)+0.5*( + * relFixNew - relFixOld = (75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.) = + * )*0.5*0.5 + * = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5 + * = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125 + */ + double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + assertEquals(-50d, insertionCost, 0.01); } @Test @@ -259,16 +358,16 @@ public class JobInsertionConsideringFixCostsCalculatorTest { when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build(); - when(oVehicle.getType()).thenReturn(oType); + when(small.getType()).thenReturn(oType); VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 100).addCapacityDimension(1, 400).setFixedCost(100.0).build(); - when(nVehicle.getType()).thenReturn(type); + when(medium.getType()).thenReturn(type); - when(route.getVehicle()).thenReturn(oVehicle); + when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*12.5)*0.75*0.5 = 15.234375 - assertEquals(15.234375, calc.getInsertionData(route, job, nVehicle, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(15.234375, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); } From 651b52530fcdd87edf5591f7a324e3f5c9309b07 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 8 Nov 2016 12:16:59 +0100 Subject: [PATCH 018/106] adjust vehicle array - related to #292 --- .../jsprit/core/problem/constraint/MaxDistanceConstraint.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index 9e3f790c..f6896ea8 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -52,7 +52,7 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ private void makeArray(Map maxDistances) { int maxIndex = getMaxIndex(maxDistances.keySet()); - this.maxDistances = new Double[maxIndex]; + this.maxDistances = new Double[maxIndex+1]; for(Vehicle v : maxDistances.keySet()){ this.maxDistances[v.getIndex()]=maxDistances.get(v); } From dc064c730ce1826219f64c76d5e4b074ad71246f Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 8 Nov 2016 12:32:45 +0100 Subject: [PATCH 019/106] add unit tests for max distance feature - related to #292 --- .../VehicleDependentTraveledDistanceTest.java | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java new file mode 100644 index 00000000..5a921625 --- /dev/null +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java @@ -0,0 +1,238 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.problem.constraint; + + +import com.graphhopper.jsprit.core.algorithm.state.StateId; +import com.graphhopper.jsprit.core.algorithm.state.StateManager; +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.cost.TransportDistance; +import com.graphhopper.jsprit.core.problem.job.Delivery; +import com.graphhopper.jsprit.core.problem.job.Job; +import com.graphhopper.jsprit.core.problem.job.Pickup; +import com.graphhopper.jsprit.core.problem.job.Shipment; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; +import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import com.graphhopper.jsprit.core.util.ManhattanCosts; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.*; + +import static org.mockito.Mockito.mock; + +/** + * Created by schroeder on 18/05/16. + */ +public class VehicleDependentTraveledDistanceTest { + + StateManager stateManager; + + VehicleRoute route; + + StateId traveledDistanceId; + + Vehicle vehicle; + + Vehicle vehicle2; + + VehicleRoutingProblem vrp; + + Delivery d1,d2,newDelivery; + + Pickup pickup; + + Shipment s1; + + Map maxDistanceMap; + + + @Before + public void doBefore(){ + vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)).build(); + vehicle2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(Location.newInstance(10,10)).build(); + + maxDistanceMap = new HashMap<>(); + maxDistanceMap.put(vehicle,200d); + maxDistanceMap.put(vehicle2,200d); + + d1 = Delivery.Builder.newInstance("d1").setLocation(Location.newInstance(10,10)).build(); + d2 = Delivery.Builder.newInstance("d2").setLocation(Location.newInstance(20,15)).build(); + pickup = Pickup.Builder.newInstance("pickup").setLocation(Location.newInstance(50,50)).build(); + s1 = Shipment.Builder.newInstance("s1").setPickupLocation(Location.newInstance(35,30)) + .setDeliveryLocation(Location.newInstance(20,25)).build(); + + newDelivery = Delivery.Builder.newInstance("new").setLocation(Location.newInstance(-10,10)).build(); + + vrp = VehicleRoutingProblem.Builder.newInstance() + .setRoutingCost(new ManhattanCosts()).addVehicle(vehicle).addVehicle(vehicle2) + .addJob(d1).addJob(d2).addJob(s1).addJob(pickup).addJob(newDelivery).build(); + + route = VehicleRoute.Builder.newInstance(vehicle).setJobActivityFactory(vrp.getJobActivityFactory()) + .addDelivery(d1).addDelivery(d2).addPickup(s1).addPickup(pickup).addDelivery(s1).build(); + + stateManager = new StateManager(vrp); + + traveledDistanceId = stateManager.createStateId("traveledDistance"); + + com.graphhopper.jsprit.core.algorithm.state.VehicleDependentTraveledDistance traveledDistance = + new com.graphhopper.jsprit.core.algorithm.state.VehicleDependentTraveledDistance(new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return new ManhattanCosts().getDistance(from,to,departureTime,vehicle); + } + },stateManager,traveledDistanceId,Arrays.asList(vehicle,vehicle2)); + + stateManager.addStateUpdater(traveledDistance); + stateManager.informInsertionStarts(Arrays.asList(route), Collections.emptyList()); + } + + /* + vehicle: 200.0 +vehicle (max distance): 200.0 +vehicle2: 160.0 +vehicle2 (max distance): 180.0 + */ + @Test + public void insertNewInVehicleShouldFail(){ + MaxDistanceConstraint maxDistanceConstraint = + new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle); + } + },maxDistanceMap); + JobInsertionContext context = new JobInsertionContext(route,newDelivery,vehicle,null,0); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,route.getStart(),newAct(),act(0),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(0),newAct(),act(1),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(1),newAct(),act(2),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(2),newAct(),act(3),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(3),newAct(),act(4),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(4),newAct(),route.getEnd(),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + } + + + @Test + public void insertNewInVehicle2ShouldBeCorrect(){ + //current distance vehicle2: 160 allowed: 200 + MaxDistanceConstraint maxDistanceConstraint = + new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle); + } + },maxDistanceMap); + JobInsertionContext context = new JobInsertionContext(route,newDelivery,vehicle2,null,0); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,route.getStart(),newAct(),act(0),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + //additional distance: 20+35-15=40 + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(0),newAct(),act(1),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + //additional distance: 35+65-30=70 + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(1),newAct(),act(2),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + //additional distance: 65+100-35 + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(2),newAct(),act(3),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + //additional distance: 100+45-55 + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(3),newAct(),act(4),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + //additional distance: 45+20-25 + Assert.assertTrue(maxDistanceConstraint.fulfilled(context,act(4),newAct(),route.getEnd(),0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + } + + private TourActivity act(int i) { + return route.getActivities().get(i); + } + + private TourActivity newAct(){ + return vrp.getActivities(newDelivery).get(0); + } + + @Test + public void traveledDistanceShouldBeCorrect(){ + Assert.assertEquals(20d,stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(35d,stateManager.getActivityState(route.getActivities().get(1),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(65d,stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(100d,stateManager.getActivityState(route.getActivities().get(3),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(155d,stateManager.getActivityState(route.getActivities().get(4),vehicle,traveledDistanceId,Double.class),0.01); + + } + + @Test + public void traveledDistanceWithVehicle2ShouldBeCorrect(){ + Assert.assertEquals(0d,stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(15d,stateManager.getActivityState(route.getActivities().get(1),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(45d,stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(80d,stateManager.getActivityState(route.getActivities().get(3),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(135d,stateManager.getActivityState(route.getActivities().get(4),vehicle2,traveledDistanceId,Double.class),0.01); + + } + + @Test + public void distanceOfShipmentInRoute(){ + double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle,traveledDistanceId, Double.class); + double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle,traveledDistanceId, Double.class); + Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01); + } + + @Test + public void distanceOfShipmentInRouteVehicle2(){ + double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle2,traveledDistanceId, Double.class); + double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle2,traveledDistanceId, Double.class); + Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01); + } + + @Test + public void distanceOfPickupInRoute(){ + double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3),vehicle, traveledDistanceId, Double.class); + double total = stateManager.getRouteState(route, vehicle,traveledDistanceId, Double.class); + Assert.assertEquals(100d,total-traveledDistanceBeforePickup,0.01); + } + + @Test + public void distanceOfPickupInRouteVehicle2(){ + double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3),vehicle2, traveledDistanceId, Double.class); + double total = stateManager.getRouteState(route, vehicle2,traveledDistanceId, Double.class); + Assert.assertEquals(80d,total-traveledDistanceBeforePickup,0.01); + } + + @Test + public void distanceToTravelShouldBeCorrect(){ + double total = stateManager.getRouteState(route,vehicle,traveledDistanceId,Double.class); + Assert.assertEquals(180d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(165d,total - stateManager.getActivityState(route.getActivities().get(1),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(135d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(100d,total - stateManager.getActivityState(route.getActivities().get(3),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(45d,total - stateManager.getActivityState(route.getActivities().get(4),vehicle,traveledDistanceId,Double.class),0.01); + + } + + @Test + public void distanceToTravelShouldBeCorrectVehicle2(){ + double total = stateManager.getRouteState(route,vehicle2,traveledDistanceId,Double.class); + Assert.assertEquals(160d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(145d,total - stateManager.getActivityState(route.getActivities().get(1),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(115d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(80d,total - stateManager.getActivityState(route.getActivities().get(3),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(25d,total - stateManager.getActivityState(route.getActivities().get(4),vehicle2,traveledDistanceId,Double.class),0.01); + + } +} From 3dcbe71fcfff5f68ee352fdb7e9c6a2ea0c9c045 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 8 Nov 2016 13:11:00 +0100 Subject: [PATCH 020/106] refine max distance constraint - related to #292 --- .../constraint/MaxDistanceConstraint.java | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index f6896ea8..96c752a5 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -73,33 +73,49 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ if(!iFacts.getRoute().isEmpty()){ currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class); } + double maxDistance = getMaxDistance(iFacts.getNewVehicle()); + double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); - double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); + double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getRoute().getVehicle()); if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){ distanceNewAct2nextAct = 0; distancePrevAct2NextAct = 0; } - double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); - double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct; - - double maxDistance = getMaxDistance(iFacts.getNewVehicle()); - if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED; + double additionalDistanceOfPickup = 0; if(newAct instanceof DeliverShipment){ int iIndexOfPickup = iFacts.getRelatedActivityContext().getInsertionIndex(); TourActivity pickup = iFacts.getAssociatedActivities().get(0); TourActivity actBeforePickup; - TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1); else actBeforePickup = iFacts.getRoute().getStart(); - double additionalDistanceOfPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(),pickup.getLocation(),0,iFacts.getNewVehicle()) - + distanceCalculator.getDistance(pickup.getLocation(),actAfterPickup.getLocation(),0,iFacts.getNewVehicle()) - - distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(),0,iFacts.getNewVehicle()); - if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){ - return ConstraintsStatus.NOT_FULFILLED; + TourActivity actAfterPickup; + boolean associatedPickAndDeliveryAreDirectNeighbors = prevAct.getIndex() == pickup.getIndex(); + if(associatedPickAndDeliveryAreDirectNeighbors){ + actAfterPickup = newAct; + distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle()); } + else actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); + double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); + double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle()); + + double distanceBeforePickup2AfterPickup; + if(associatedPickAndDeliveryAreDirectNeighbors){ + distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); + } + else{ + distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getRoute().getVehicle()); + } + additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup; + } + + double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct; + if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED; + + if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){ + return ConstraintsStatus.NOT_FULFILLED; } return ConstraintsStatus.FULFILLED; From 26878a3b519b63bf49d745c922e4f1ff3ce50934 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 8 Nov 2016 16:25:45 +0100 Subject: [PATCH 021/106] refine max distance constraint - related to #292 --- .../constraint/MaxDistanceConstraint.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index 96c752a5..20a90a7d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.cost.TransportDistance; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment; import com.graphhopper.jsprit.core.problem.solution.route.activity.End; +import com.graphhopper.jsprit.core.problem.solution.route.activity.Start; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; @@ -74,14 +75,18 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class); } double maxDistance = getMaxDistance(iFacts.getNewVehicle()); + if(currentDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED_BREAK; double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); - double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getRoute().getVehicle()); + double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle()); if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){ distanceNewAct2nextAct = 0; distancePrevAct2NextAct = 0; } + double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct; + if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED; + double additionalDistanceOfPickup = 0; if(newAct instanceof DeliverShipment){ @@ -89,30 +94,14 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ TourActivity pickup = iFacts.getAssociatedActivities().get(0); TourActivity actBeforePickup; if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1); - else actBeforePickup = iFacts.getRoute().getStart(); - - TourActivity actAfterPickup; - boolean associatedPickAndDeliveryAreDirectNeighbors = prevAct.getIndex() == pickup.getIndex(); - if(associatedPickAndDeliveryAreDirectNeighbors){ - actAfterPickup = newAct; - distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle()); - } - else actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); + else actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE); + TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle()); - - double distanceBeforePickup2AfterPickup; - if(associatedPickAndDeliveryAreDirectNeighbors){ - distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); - } - else{ - distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getRoute().getVehicle()); - } + double distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup; } - double additionalDistance = distancePrevAct2NewAct + distanceNewAct2nextAct - distancePrevAct2NextAct; - if(currentDistance + additionalDistance > maxDistance) return ConstraintsStatus.NOT_FULFILLED; if(currentDistance + additionalDistance + additionalDistanceOfPickup > maxDistance){ return ConstraintsStatus.NOT_FULFILLED; @@ -122,6 +111,7 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ } private boolean hasMaxDistance(Vehicle newVehicle){ + if(newVehicle.getIndex() >= this.maxDistances.length) return false; return this.maxDistances[newVehicle.getIndex()] != null; } From 78405218bb0e3918db6c811ee51c2c289697c6c2 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 9 Nov 2016 10:01:56 +0100 Subject: [PATCH 022/106] refine max distance constraint - related to #292 --- .../jsprit/core/problem/constraint/MaxDistanceConstraint.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index 20a90a7d..2ad64a87 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -96,6 +96,7 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1); else actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE); TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); + //ToDo account here fore End and returnToDepot double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle()); double distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); From 392167051fa808058dba85f083c5c5792b139827 Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 11 Nov 2016 20:16:37 +0100 Subject: [PATCH 023/106] deprecated insertion calculators --- .../recreate/CalculatesServiceInsertionWithTimeScheduling.java | 2 +- .../CalculatesServiceInsertionWithTimeSchedulingInSlices.java | 2 +- .../recreate/RouteLevelActivityInsertionCostsEstimator.java | 2 +- .../recreate/ServiceInsertionOnRouteLevelCalculator.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeScheduling.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeScheduling.java index 62716618..44401a8b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeScheduling.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeScheduling.java @@ -32,7 +32,7 @@ import java.util.Collection; import java.util.List; import java.util.Random; - +@Deprecated class CalculatesServiceInsertionWithTimeScheduling implements JobInsertionCostsCalculator { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeSchedulingInSlices.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeSchedulingInSlices.java index 099b6b24..05d9c6c3 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeSchedulingInSlices.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/CalculatesServiceInsertionWithTimeSchedulingInSlices.java @@ -27,7 +27,7 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; - +@Deprecated class CalculatesServiceInsertionWithTimeSchedulingInSlices implements JobInsertionCostsCalculator { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java index e47a48d8..d6fc01b4 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RouteLevelActivityInsertionCostsEstimator.java @@ -31,7 +31,7 @@ import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivity import java.util.ArrayList; import java.util.List; - +@Deprecated class RouteLevelActivityInsertionCostsEstimator implements ActivityInsertionCostsCalculator { private VehicleRoutingActivityCosts activityCosts; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java index b330d689..a600f3f6 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionOnRouteLevelCalculator.java @@ -45,7 +45,7 @@ import java.util.Comparator; import java.util.List; import java.util.PriorityQueue; - +@Deprecated final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsCalculator { private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionOnRouteLevelCalculator.class); From ab0acfb1d67ea3589337e05f16c0ec45bef55829 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 14 Nov 2016 10:11:27 +0100 Subject: [PATCH 024/106] reproduce bug #297 --- .../VehicleDependentTraveledDistanceTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java index 5a921625..22c07de0 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java @@ -30,6 +30,8 @@ import com.graphhopper.jsprit.core.problem.job.Pickup; import com.graphhopper.jsprit.core.problem.job.Shipment; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.activity.End; +import com.graphhopper.jsprit.core.problem.solution.route.activity.Start; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; @@ -109,6 +111,29 @@ public class VehicleDependentTraveledDistanceTest { stateManager.informInsertionStarts(Arrays.asList(route), Collections.emptyList()); } + @Test + public void whenEndLocationIsSet_constraintShouldWork(){ + VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0,0)) + .setEndLocation(Location.newInstance(10,0)).build(); + Pickup pickup = Pickup.Builder.newInstance("pickup").setLocation(Location.newInstance(10,0)).build(); + vrp = VehicleRoutingProblem.Builder.newInstance().addVehicle(vehicle).addJob(pickup).build(); + route = VehicleRoute.emptyRoute(); + maxDistanceMap = new HashMap<>(); + maxDistanceMap.put(vehicle,5d); + + MaxDistanceConstraint maxDistanceConstraint = + new MaxDistanceConstraint(new StateManager(vrp), traveledDistanceId, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle); + } + },maxDistanceMap); + JobInsertionContext context = new JobInsertionContext(route,pickup,vehicle,null,0); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context, + new Start(vehicle.getStartLocation(),0,Double.MAX_VALUE),vrp.getActivities(pickup).get(0), + new End(vehicle.getEndLocation(),0,Double.MAX_VALUE),0).equals(HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED)); + } + /* vehicle: 200.0 vehicle (max distance): 200.0 From 3699fd5f990374d159e1b46d48a597fb067c81e0 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 14 Nov 2016 10:15:05 +0100 Subject: [PATCH 025/106] fix bug #297 --- .../jsprit/core/problem/constraint/MaxDistanceConstraint.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index 2ad64a87..2bbf0fda 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -71,7 +71,8 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ public ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime) { if(!hasMaxDistance(iFacts.getNewVehicle())) return ConstraintsStatus.FULFILLED; Double currentDistance = 0d; - if(!iFacts.getRoute().isEmpty()){ + boolean routeIsEmpty = iFacts.getRoute().isEmpty(); + if(!routeIsEmpty){ currentDistance = stateManager.getRouteState(iFacts.getRoute(),iFacts.getNewVehicle(), distanceId,Double.class); } double maxDistance = getMaxDistance(iFacts.getNewVehicle()); @@ -80,6 +81,7 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle()); + if(routeIsEmpty) distancePrevAct2NextAct = 0; if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){ distanceNewAct2nextAct = 0; distancePrevAct2NextAct = 0; From 16b9a1164baf4c641d68797eb0eafc5f80d25cf9 Mon Sep 17 00:00:00 2001 From: He Huang Date: Wed, 16 Nov 2016 19:17:35 +0800 Subject: [PATCH 026/106] fix bug 280 --- ...LocalActivityInsertionCostsCalculator.java | 5 +- ...LocalActivityInsertionCostsCalculator.java | 69 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java index cdd7dac2..0f91eab1 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/LocalActivityInsertionCostsCalculator.java @@ -22,6 +22,7 @@ import com.graphhopper.jsprit.core.algorithm.state.InternalStates; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.activity.DeliverShipment; import com.graphhopper.jsprit.core.problem.solution.route.activity.End; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; @@ -77,7 +78,9 @@ class LocalActivityInsertionCostsCalculator implements ActivityInsertionCostsCal double oldCosts = 0.; 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 = 0.; + if (newAct instanceof DeliverShipment) + tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), depTimeAtPrevAct, iFacts.getNewDriver(), iFacts.getNewVehicle()); oldCosts += tp_costs_prevAct_nextAct; } else { double tp_costs_prevAct_nextAct = routingCosts.getTransportCost(prevAct.getLocation(), nextAct.getLocation(), prevAct.getEndTime(), iFacts.getRoute().getDriver(), iFacts.getRoute().getVehicle()); diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java index 66ff5063..b9e4f631 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/TestLocalActivityInsertionCostsCalculator.java @@ -28,6 +28,7 @@ import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts; import com.graphhopper.jsprit.core.problem.cost.WaitingTimeCosts; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Service; +import com.graphhopper.jsprit.core.problem.job.Shipment; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.activity.End; @@ -91,6 +92,74 @@ public class TestLocalActivityInsertionCostsCalculator { return Location.Builder.newInstance().setId(i).build(); } + @Test + public void whenAddingServiceBetweenDiffStartAndEnd_costMustBeCorrect() { + VehicleImpl v = VehicleImpl.Builder.newInstance("v") + .setStartLocation(Location.newInstance(0, 0)) + .setEndLocation(Location.newInstance(20, 0)) + .build(); + Service s = Service.Builder.newInstance("s") + .setLocation(Location.newInstance(10, 0)) + .build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addVehicle(v) + .addJob(s) + .build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + JobInsertionContext jobInsertionContext = + new JobInsertionContext(route, s, v, null, 0); + LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator = + new LocalActivityInsertionCostsCalculator( + vrp.getTransportCosts(), + vrp.getActivityCosts(), + new StateManager(vrp)); + double cost = localActivityInsertionCostsCalculator.getCosts( + jobInsertionContext, + new Start(v.getStartLocation(),0,Double.MAX_VALUE), + new End(v.getEndLocation(),0,Double.MAX_VALUE), + vrp.getActivities(s).get(0), + 0); + assertEquals(20., cost, Math.ulp(20.)); + } + + @Test + public void whenAddingShipmentBetweenDiffStartAndEnd_costMustBeCorrect() { + VehicleImpl v = VehicleImpl.Builder.newInstance("v") + .setStartLocation(Location.newInstance(0, 0)) + .setEndLocation(Location.newInstance(20, 0)) + .build(); + Shipment s = Shipment.Builder.newInstance("p") + .setPickupLocation(Location.newInstance(10, 0)) + .setDeliveryLocation(Location.newInstance(10, 7.5)) + .build(); + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addVehicle(v) + .addJob(s) + .build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + JobInsertionContext jobInsertionContext = + new JobInsertionContext(route, s, v, null, 0); + LocalActivityInsertionCostsCalculator localActivityInsertionCostsCalculator = + new LocalActivityInsertionCostsCalculator( + vrp.getTransportCosts(), + vrp.getActivityCosts(), + new StateManager(vrp)); + double cost = localActivityInsertionCostsCalculator.getCosts( + jobInsertionContext, + new Start(v.getStartLocation(),0,Double.MAX_VALUE), + new End(v.getEndLocation(),0,Double.MAX_VALUE), + vrp.getActivities(s).get(0), + 0); + assertEquals(20., cost, Math.ulp(20.)); + cost = localActivityInsertionCostsCalculator.getCosts( + jobInsertionContext, + vrp.getActivities(s).get(0), + new End(v.getEndLocation(),0,Double.MAX_VALUE), + vrp.getActivities(s).get(1), + 0); + assertEquals(10, cost, Math.ulp(10.)); + } + @Test public void whenInsertingActBetweenTwoRouteActs_itCalcsMarginalTpCosts() { TourActivity prevAct = mock(TourActivity.class); From d628f23b4d709f22306e1e334bfb882db1f72b40 Mon Sep 17 00:00:00 2001 From: He Huang Date: Tue, 29 Nov 2016 11:52:52 +0800 Subject: [PATCH 027/106] fix deliverShipment insertion in max distance constraint --- .../constraint/MaxDistanceConstraint.java | 16 ++- .../VehicleDependentTraveledDistanceTest.java | 118 ++++++++++++++++-- 2 files changed, 118 insertions(+), 16 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java index 2bbf0fda..fac022db 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/MaxDistanceConstraint.java @@ -81,7 +81,7 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ double distancePrevAct2NewAct = distanceCalculator.getDistance(prevAct.getLocation(), newAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); double distanceNewAct2nextAct = distanceCalculator.getDistance(newAct.getLocation(), nextAct.getLocation(), iFacts.getNewDepTime(), iFacts.getNewVehicle()); double distancePrevAct2NextAct = distanceCalculator.getDistance(prevAct.getLocation(), nextAct.getLocation(), prevActDepTime, iFacts.getNewVehicle()); - if(routeIsEmpty) distancePrevAct2NextAct = 0; + if(prevAct instanceof Start && nextAct instanceof End) distancePrevAct2NextAct = 0; if(nextAct instanceof End && !iFacts.getNewVehicle().isReturnToDepot()){ distanceNewAct2nextAct = 0; distancePrevAct2NextAct = 0; @@ -97,12 +97,20 @@ public class MaxDistanceConstraint implements HardActivityConstraint{ TourActivity actBeforePickup; if(iIndexOfPickup > 0) actBeforePickup = iFacts.getRoute().getActivities().get(iIndexOfPickup-1); else actBeforePickup = new Start(iFacts.getNewVehicle().getStartLocation(),0,Double.MAX_VALUE); - TourActivity actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); - //ToDo account here fore End and returnToDepot + TourActivity actAfterPickup; + if (iIndexOfPickup < iFacts.getRoute().getActivities().size()) + actAfterPickup = iFacts.getRoute().getActivities().get(iIndexOfPickup); + else + actAfterPickup = nextAct; double distanceActBeforePickup2Pickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), pickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); double distancePickup2ActAfterPickup = distanceCalculator.getDistance(pickup.getLocation(), actAfterPickup.getLocation(), iFacts.getRelatedActivityContext().getEndTime(), iFacts.getNewVehicle()); double distanceBeforePickup2AfterPickup = distanceCalculator.getDistance(actBeforePickup.getLocation(), actAfterPickup.getLocation(), actBeforePickup.getEndTime(), iFacts.getNewVehicle()); - additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup; + if (routeIsEmpty) distanceBeforePickup2AfterPickup = 0; + if (actAfterPickup instanceof End && !iFacts.getNewVehicle().isReturnToDepot()) { + distancePickup2ActAfterPickup = 0; + distanceBeforePickup2AfterPickup = 0; + } + additionalDistanceOfPickup = distanceActBeforePickup2Pickup + distancePickup2ActAfterPickup - distanceBeforePickup2AfterPickup; } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java index 22c07de0..a1ed5145 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/constraint/VehicleDependentTraveledDistanceTest.java @@ -28,6 +28,7 @@ import com.graphhopper.jsprit.core.problem.job.Delivery; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.job.Pickup; import com.graphhopper.jsprit.core.problem.job.Shipment; +import com.graphhopper.jsprit.core.problem.misc.ActivityContext; import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.activity.End; @@ -214,50 +215,143 @@ vehicle2 (max distance): 180.0 @Test public void distanceOfShipmentInRoute(){ double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle,traveledDistanceId, Double.class); - double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle,traveledDistanceId, Double.class); + double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class); Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01); } @Test public void distanceOfShipmentInRouteVehicle2(){ double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(2), vehicle2,traveledDistanceId, Double.class); - double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle2,traveledDistanceId, Double.class); + double traveledDistanceBeforeDelivery = stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class); Assert.assertEquals(90d,traveledDistanceBeforeDelivery-traveledDistanceBeforePickup,0.01); } @Test public void distanceOfPickupInRoute(){ - double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3),vehicle, traveledDistanceId, Double.class); + double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class); double total = stateManager.getRouteState(route, vehicle,traveledDistanceId, Double.class); Assert.assertEquals(100d,total-traveledDistanceBeforePickup,0.01); } @Test public void distanceOfPickupInRouteVehicle2(){ - double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3),vehicle2, traveledDistanceId, Double.class); + double traveledDistanceBeforePickup = stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class); double total = stateManager.getRouteState(route, vehicle2,traveledDistanceId, Double.class); Assert.assertEquals(80d,total-traveledDistanceBeforePickup,0.01); } @Test public void distanceToTravelShouldBeCorrect(){ - double total = stateManager.getRouteState(route,vehicle,traveledDistanceId,Double.class); + double total = stateManager.getRouteState(route, vehicle, traveledDistanceId, Double.class); Assert.assertEquals(180d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle,traveledDistanceId,Double.class),0.01); - Assert.assertEquals(165d,total - stateManager.getActivityState(route.getActivities().get(1),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(165d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle, traveledDistanceId, Double.class), 0.01); Assert.assertEquals(135d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle,traveledDistanceId,Double.class),0.01); - Assert.assertEquals(100d,total - stateManager.getActivityState(route.getActivities().get(3),vehicle,traveledDistanceId,Double.class),0.01); - Assert.assertEquals(45d,total - stateManager.getActivityState(route.getActivities().get(4),vehicle,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(100d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle, traveledDistanceId, Double.class), 0.01); + Assert.assertEquals(45d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle, traveledDistanceId, Double.class), 0.01); } @Test public void distanceToTravelShouldBeCorrectVehicle2(){ - double total = stateManager.getRouteState(route,vehicle2,traveledDistanceId,Double.class); + double total = stateManager.getRouteState(route, vehicle2, traveledDistanceId, Double.class); Assert.assertEquals(160d,total - stateManager.getActivityState(route.getActivities().get(0),vehicle2,traveledDistanceId,Double.class),0.01); - Assert.assertEquals(145d,total - stateManager.getActivityState(route.getActivities().get(1),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(145d, total - stateManager.getActivityState(route.getActivities().get(1), vehicle2, traveledDistanceId, Double.class), 0.01); Assert.assertEquals(115d,total - stateManager.getActivityState(route.getActivities().get(2),vehicle2,traveledDistanceId,Double.class),0.01); - Assert.assertEquals(80d,total - stateManager.getActivityState(route.getActivities().get(3),vehicle2,traveledDistanceId,Double.class),0.01); - Assert.assertEquals(25d,total - stateManager.getActivityState(route.getActivities().get(4),vehicle2,traveledDistanceId,Double.class),0.01); + Assert.assertEquals(80d, total - stateManager.getActivityState(route.getActivities().get(3), vehicle2, traveledDistanceId, Double.class), 0.01); + Assert.assertEquals(25d, total - stateManager.getActivityState(route.getActivities().get(4), vehicle2, traveledDistanceId, Double.class), 0.01); } + + @Test + public void whenAddingDeliverShipment_constraintShouldWork() { + Shipment shipment = Shipment.Builder.newInstance("s") + .setPickupLocation(Location.newInstance(0, 3)) + .setDeliveryLocation(Location.newInstance(4, 0)) + .build(); + VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v") + .setStartLocation(Location.newInstance(0, 0)) + .build(); + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addJob(shipment) + .addVehicle(vehicle) + .build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0); + context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0)); + context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1)); + maxDistanceMap = new HashMap<>(); + maxDistanceMap.put(vehicle,12d); + + StateManager stateManager = new StateManager(vrp); + MaxDistanceConstraint maxDistanceConstraint = + new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle); + } + },maxDistanceMap); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context, + new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE), + vrp.getActivities(shipment).get(0), + new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE), + 0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + + ActivityContext pickupContext = new ActivityContext(); + pickupContext.setArrivalTime(3); + pickupContext.setEndTime(3); + pickupContext.setInsertionIndex(0); + context.setRelatedActivityContext(pickupContext); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context, + vrp.getActivities(shipment).get(0), + vrp.getActivities(shipment).get(1), + new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE), + 3).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + } + + @Test + public void whenAddingDeliverShipmentWithVehDiffStartEndLocs_constraintShouldWork() { + Shipment shipment = Shipment.Builder.newInstance("s") + .setPickupLocation(Location.newInstance(0, 1)) + .setDeliveryLocation(Location.newInstance(4, 1)) + .build(); + VehicleImpl vehicle = VehicleImpl.Builder.newInstance("v") + .setStartLocation(Location.newInstance(0, 0)) + .setEndLocation(Location.newInstance(0, 4)) + .build(); + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance() + .addJob(shipment) + .addVehicle(vehicle) + .build(); + VehicleRoute route = VehicleRoute.emptyRoute(); + JobInsertionContext context = new JobInsertionContext(route, shipment, vehicle, null, 0); + context.getAssociatedActivities().add(vrp.getActivities(shipment).get(0)); + context.getAssociatedActivities().add(vrp.getActivities(shipment).get(1)); + maxDistanceMap = new HashMap<>(); + maxDistanceMap.put(vehicle,10d); + + StateManager stateManager = new StateManager(vrp); + MaxDistanceConstraint maxDistanceConstraint = + new MaxDistanceConstraint(stateManager, traveledDistanceId, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportTime(from,to,departureTime, null, vehicle); + } + },maxDistanceMap); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context, + new Start(vehicle.getStartLocation(), 0, Double.MAX_VALUE), + vrp.getActivities(shipment).get(0), + new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE), + 0).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + + ActivityContext pickupContext = new ActivityContext(); + pickupContext.setArrivalTime(1); + pickupContext.setEndTime(1); + pickupContext.setInsertionIndex(0); + context.setRelatedActivityContext(pickupContext); + Assert.assertTrue(maxDistanceConstraint.fulfilled(context, + vrp.getActivities(shipment).get(0), + vrp.getActivities(shipment).get(1), + new End(vehicle.getEndLocation(), 0, Double.MAX_VALUE), + 1).equals(HardActivityConstraint.ConstraintsStatus.FULFILLED)); + } } From 851f0f98615a8726a41cf39f31ca1c42ca22b370 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 5 Dec 2016 19:31:12 +0100 Subject: [PATCH 028/106] make regret scorer configurable --- .../jsprit/core/algorithm/box/Jsprit.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 83551cc5..5f514d73 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -161,6 +161,8 @@ public class Jsprit { private SolutionAcceptor solutionAcceptor; + private ScoringFunction regretScorer = null; + public static Builder newInstance(VehicleRoutingProblem vrp) { return new Builder(vrp); } @@ -266,6 +268,11 @@ public class Jsprit { return this; } + public Builder setRegretScorer(ScoringFunction scoringFunction) { + this.regretScorer = scoringFunction; + return this; + } + public VehicleRoutingAlgorithm buildAlgorithm() { return new Jsprit(this).create(vrp); } @@ -328,6 +335,8 @@ public class Jsprit { private SolutionAcceptor acceptor; + private ScoringFunction regretScorer; + private Jsprit(Builder builder) { this.stateManager = builder.stateManager; this.constraintManager = builder.constraintManager; @@ -339,9 +348,15 @@ public class Jsprit { this.random = builder.random; this.activityInsertion = builder.activityInsertionCalculator; this.acceptor = builder.solutionAcceptor; + regretScorer = builder.regretScorer; + } + + private void ini(VehicleRoutingProblem vrp) { + if (regretScorer == null) regretScorer = getRegretScorer(vrp); } private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) { + ini(vrp); VehicleFleetManager fm; if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) { fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); @@ -450,7 +465,7 @@ public class Jsprit { ); AbstractInsertionStrategy regret; - final DefaultScorer scorer; + final ScoringFunction scorer; boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString())); if (es != null) { @@ -463,7 +478,7 @@ public class Jsprit { .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setActivityInsertionCostCalculator(activityInsertion) .build(); - scorer = getRegretScorer(vrp); + scorer = regretScorer; regretInsertion.setScoringFunction(scorer); regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes()); regret = regretInsertion; @@ -476,7 +491,7 @@ public class Jsprit { .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .setActivityInsertionCostCalculator(activityInsertion) .build(); - scorer = getRegretScorer(vrp); + scorer = regretScorer; regretInsertion.setScoringFunction(scorer); regret = regretInsertion; } @@ -489,7 +504,7 @@ public class Jsprit { .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .setActivityInsertionCostCalculator(activityInsertion) .build(); - scorer = getRegretScorer(vrp); + scorer = regretScorer; regretInsertion.setScoringFunction(scorer); regretInsertion.setDependencyTypes(constraintManager.getDependencyTypes()); regret = regretInsertion; @@ -501,7 +516,7 @@ public class Jsprit { .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) .setActivityInsertionCostCalculator(activityInsertion) .build(); - scorer = getRegretScorer(vrp); + scorer = regretScorer; regretInsertion.setScoringFunction(scorer); regret = regretInsertion; } From d3df091ece43e4f913d68c9418372653a1b3af2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Wed, 14 Dec 2016 09:23:40 +0100 Subject: [PATCH 029/106] add @balage1551 --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 262988d3..40b4b91d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,7 @@ The following people have contributed code, bug fixes and ideas. * [Abraham Gausachs](https://github.com/agausachs) + * [Balage1551](https://github.com/balage1551) * [Giulio Collura](https://github.com/gcollura) * [Gwénaël Rault](https://github.com/braktar) * [Heinrich Filter](https://github.com/HeinrichFilter) From f027dea8102790d7f6794b0ec2d20a44a4eaf7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Wed, 14 Dec 2016 09:25:46 +0100 Subject: [PATCH 030/106] add he --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 40b4b91d..c5cfe7b6 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -5,6 +5,7 @@ The following people have contributed code, bug fixes and ideas. * [Giulio Collura](https://github.com/gcollura) * [Gwénaël Rault](https://github.com/braktar) * [Heinrich Filter](https://github.com/HeinrichFilter) + * [jie31best](https://github.com/jie31best) * Josh Pilkington * [Julia Loikova](https://github.com/Jullil) * [muzuro](https://github.com/muzuro) From 0becec2ce8b6418e78a66882b25292916ac5ac52 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 11 Jan 2017 20:08:31 +0100 Subject: [PATCH 031/106] split fix cost calculation - related to #286 --- .../jsprit/core/algorithm/box/Jsprit.java | 9 + .../DecreasingRelativeFixedCosts.java | 77 +++++ .../recreate/DellAmicoFixCostCalculator.java | 4 +- .../IncreasingAbsoluteFixedCosts.java | 61 ++++ ...nsertionConsideringFixCostsCalculator.java | 122 ------- .../JobInsertionCostsCalculatorBuilder.java | 16 +- ...or.java => SolutionCompletenessRatio.java} | 36 +- .../ConfigureFixCostCalculatorTest.java | 95 ------ ...tionConsideringFixCostsCalculatorTest.java | 320 +++++++++++++----- 9 files changed, 402 insertions(+), 338 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java delete mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java rename jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/{ConfigureFixCostCalculator.java => SolutionCompletenessRatio.java} (59%) delete mode 100644 jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculatorTest.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 83551cc5..0a533515 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -368,6 +368,14 @@ public class Jsprit { } } + double fixedCostParam = toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString())); + IncreasingAbsoluteFixedCosts increasingAbsoluteFixedCosts = null; + if (fixedCostParam > 0d) { + increasingAbsoluteFixedCosts = new IncreasingAbsoluteFixedCosts(vrp.getJobs().size()); + increasingAbsoluteFixedCosts.setWeightOfFixCost(fixedCostParam); + constraintManager.addConstraint(increasingAbsoluteFixedCosts); + } + double noiseLevel = toDouble(getProperty(Parameter.INSERTION_NOISE_LEVEL.toString())); double noiseProbability = toDouble(getProperty(Parameter.INSERTION_NOISE_PROB.toString())); @@ -598,6 +606,7 @@ public class Jsprit { vra.addListener(noiseConfigurator); vra.addListener(noise); vra.addListener(clusters); + if (increasingAbsoluteFixedCosts != null) vra.addListener(increasingAbsoluteFixedCosts); if(toBoolean(getProperty(Parameter.BREAK_SCHEDULING.toString()))) { vra.addListener(new BreakScheduling(vrp, stateManager, constraintManager)); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java new file mode 100644 index 00000000..f9b45879 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java @@ -0,0 +1,77 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.graphhopper.jsprit.core.algorithm.recreate; + +import com.graphhopper.jsprit.core.algorithm.state.InternalStates; +import com.graphhopper.jsprit.core.problem.Capacity; +import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public final class DecreasingRelativeFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint { + + private static final Logger logger = LoggerFactory.getLogger(DecreasingRelativeFixedCosts.class); + + private double weightDeltaFixCost = 0.5; + + private RouteAndActivityStateGetter stateGetter; + + public DecreasingRelativeFixedCosts(RouteAndActivityStateGetter stateGetter, int noJobs) { + super(noJobs); + this.stateGetter = stateGetter; + logger.debug("initialise {}", this); + } + + + public void setWeightOfFixCost(double weight) { + weightDeltaFixCost = weight; + logger.debug("set weightOfFixCostSaving to {}", weight); + } + + @Override + public String toString() { + return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; + } + + private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) { + Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class); + if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build(); + return maxLoad; + } + + @Override + public double getCosts(JobInsertionContext insertionContext) { + VehicleRoute route = insertionContext.getRoute(); + Capacity currentLoad = getCurrentMaxLoadInRoute(route); + Capacity load = Capacity.addup(currentLoad, insertionContext.getJob().getSize()); + double currentRelFix = 0d; + if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { + currentRelFix = route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions()); + } + double newRelFix = insertionContext.getNewVehicle().getType().getVehicleCostParams().fix * (Capacity.divide(load, insertionContext.getNewVehicle().getType().getCapacityDimensions())); + double decreasingRelativeFixedCosts = (1 - solutionCompletenessRatio) * (newRelFix - currentRelFix); + return weightDeltaFixCost * solutionCompletenessRatio * decreasingRelativeFixedCosts; + } + + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DellAmicoFixCostCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DellAmicoFixCostCalculator.java index 4ed97ed6..a08fe6d7 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DellAmicoFixCostCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DellAmicoFixCostCalculator.java @@ -31,14 +31,14 @@ public class DellAmicoFixCostCalculator implements SoftRouteConstraint, Insertio private int nuOfJobsToRecreate; - private final JobInsertionConsideringFixCostsCalculator calculator; + private final IncreasingAbsoluteFixedCosts calculator; private final int nuOfJobs; public DellAmicoFixCostCalculator(final int nuOfJobs, final RouteAndActivityStateGetter stateGetter) { super(); this.nuOfJobs = nuOfJobs; - calculator = new JobInsertionConsideringFixCostsCalculator(null, stateGetter); + calculator = new IncreasingAbsoluteFixedCosts(nuOfJobs); } @Override diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java new file mode 100644 index 00000000..96854d57 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java @@ -0,0 +1,61 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.graphhopper.jsprit.core.algorithm.recreate; + +import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public final class IncreasingAbsoluteFixedCosts extends SolutionCompletenessRatio implements SoftRouteConstraint { + + private static final Logger logger = LoggerFactory.getLogger(IncreasingAbsoluteFixedCosts.class); + + private double weightDeltaFixCost = 0.5; + + public IncreasingAbsoluteFixedCosts(int noJobs) { + super(noJobs); + logger.debug("initialise {}", this); + } + + + public void setWeightOfFixCost(double weight) { + weightDeltaFixCost = weight; + logger.debug("set weightOfFixCostSaving to {}", weight); + } + + @Override + public String toString() { + return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; + } + + @Override + public double getCosts(JobInsertionContext insertionContext) { + final VehicleRoute currentRoute = insertionContext.getRoute(); + double currentFix = 0d; + if (currentRoute.getVehicle() != null && !(currentRoute.getVehicle() instanceof VehicleImpl.NoVehicle)) { + currentFix = currentRoute.getVehicle().getType().getVehicleCostParams().fix; + } + double increasingAbsoluteFixedCosts = solutionCompletenessRatio * (insertionContext.getNewVehicle().getType().getVehicleCostParams().fix - currentFix); + return weightDeltaFixCost * solutionCompletenessRatio * increasingAbsoluteFixedCosts; + } + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java deleted file mode 100644 index 1ce3d98e..00000000 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculator.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.graphhopper.jsprit.core.algorithm.recreate; - -import com.graphhopper.jsprit.core.algorithm.state.InternalStates; -import com.graphhopper.jsprit.core.problem.Capacity; -import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint; -import com.graphhopper.jsprit.core.problem.driver.Driver; -import com.graphhopper.jsprit.core.problem.job.Job; -import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; -import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; -import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; -import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; -import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -final class JobInsertionConsideringFixCostsCalculator implements JobInsertionCostsCalculator, SoftRouteConstraint { - - private static final Logger logger = LoggerFactory.getLogger(JobInsertionConsideringFixCostsCalculator.class); - - private final JobInsertionCostsCalculator standardInsertion; - - private double weightDeltaFixCost = 0.5; - - private double solutionCompletenessRatio = 0.5; - - private RouteAndActivityStateGetter stateGetter; - - public JobInsertionConsideringFixCostsCalculator(final JobInsertionCostsCalculator standardCalculator, RouteAndActivityStateGetter stateGetter) { - super(); - this.standardInsertion = standardCalculator; - this.stateGetter = stateGetter; - logger.debug("initialise {}", this); - } - - @Override - public InsertionData getInsertionData(final VehicleRoute currentRoute, final Job jobToInsert, final Vehicle newVehicle, double newVehicleDepartureTime, final Driver newDriver, final double bestKnownPrice) { - double fixedCostContribution = getFixCostContribution(currentRoute, jobToInsert, newVehicle); - if (fixedCostContribution > bestKnownPrice) { - return InsertionData.createEmptyInsertionData(); - } - InsertionData iData = standardInsertion.getInsertionData(currentRoute, jobToInsert, newVehicle, newVehicleDepartureTime, newDriver, bestKnownPrice); - if (iData instanceof InsertionData.NoInsertionFound) { - return iData; - } - double totalInsertionCost = iData.getInsertionCost() + fixedCostContribution; - 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) { - Capacity currentMaxLoadInRoute = getCurrentMaxLoadInRoute(currentRoute); - double relFixCost = getDeltaRelativeFixCost(currentRoute, newVehicle, jobToInsert,currentMaxLoadInRoute); - double absFixCost = getDeltaAbsoluteFixCost(currentRoute, newVehicle); - double deltaFixCost = (1 - solutionCompletenessRatio) * relFixCost + solutionCompletenessRatio * absFixCost; - return weightDeltaFixCost * solutionCompletenessRatio * deltaFixCost; - } - - public void setWeightOfFixCost(double weight) { - weightDeltaFixCost = weight; - logger.debug("set weightOfFixCostSaving to {}", weight); - } - - @Override - public String toString() { - return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; - } - - public void setSolutionCompletenessRatio(double ratio) { - solutionCompletenessRatio = ratio; - } - - public double getSolutionCompletenessRatio() { return solutionCompletenessRatio; } - - private double getDeltaAbsoluteFixCost(VehicleRoute route, Vehicle newVehicle) { - double currentFix = 0d; - if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { - currentFix = route.getVehicle().getType().getVehicleCostParams().fix; - } - return newVehicle.getType().getVehicleCostParams().fix - currentFix; - } - - private double getDeltaRelativeFixCost(VehicleRoute route, Vehicle newVehicle, Job job, Capacity currentLoad) { - Capacity load = Capacity.addup(currentLoad, job.getSize()); - double currentRelFix = 0d; - if (route.getVehicle() != null && !(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { - currentRelFix = route.getVehicle().getType().getVehicleCostParams().fix * Capacity.divide(currentLoad, route.getVehicle().getType().getCapacityDimensions()); - } - return newVehicle.getType().getVehicleCostParams().fix * (Capacity.divide(load, newVehicle.getType().getCapacityDimensions())) - currentRelFix; - } - - private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) { - Capacity maxLoad = stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class); - if (maxLoad == null) maxLoad = Capacity.Builder.newInstance().build(); - return maxLoad; - } - - @Override - public double getCosts(JobInsertionContext insertionContext) { - return getFixCostContribution(insertionContext.getRoute(), insertionContext.getJob(), insertionContext.getNewVehicle()); - } - -} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java index 01284d80..1135adb8 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionCostsCalculatorBuilder.java @@ -218,10 +218,10 @@ public class JobInsertionCostsCalculatorBuilder { addAlgorithmListeners(standardLocal.getAlgorithmListener()); addInsertionListeners(standardLocal.getInsertionListener()); if (considerFixedCost) { - CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost); - baseCalculator = withFixed.getCalculator(); - addAlgorithmListeners(withFixed.getAlgorithmListener()); - addInsertionListeners(withFixed.getInsertionListener()); +// CalculatorPlusListeners withFixed = createCalculatorConsideringFixedCosts(vrp, baseCalculator, states, weightOfFixedCost); +// baseCalculator = withFixed.getCalculator(); +// addAlgorithmListeners(withFixed.getAlgorithmListener()); +// addInsertionListeners(withFixed.getInsertionListener()); } if (timeScheduling) { // baseCalculator = new CalculatesServiceInsertionWithTimeSchedulingInSlices(baseCalculator,timeSlice,neighbors); @@ -309,14 +309,6 @@ public class JobInsertionCostsCalculatorBuilder { return calculatorPlusListeners; } - private CalculatorPlusListeners createCalculatorConsideringFixedCosts(VehicleRoutingProblem vrp, JobInsertionCostsCalculator baseCalculator, RouteAndActivityStateGetter activityStates2, double weightOfFixedCosts) { - final JobInsertionConsideringFixCostsCalculator withFixCost = new JobInsertionConsideringFixCostsCalculator(baseCalculator, activityStates2); - withFixCost.setWeightOfFixCost(weightOfFixedCosts); - CalculatorPlusListeners calcPlusListeners = new CalculatorPlusListeners(withFixCost); - calcPlusListeners.getInsertionListener().add(new ConfigureFixCostCalculator(vrp, withFixCost)); - return calcPlusListeners; - } - private CalculatorPlusListeners createStandardRoute(final VehicleRoutingProblem vrp, RouteAndActivityStateGetter activityStates2, int forwardLooking, int solutionMemory) { ActivityInsertionCostsCalculator routeLevelCostEstimator; if (activityInsertionCostCalculator == null && addDefaultCostCalc) { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/SolutionCompletenessRatio.java similarity index 59% rename from jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculator.java rename to jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/SolutionCompletenessRatio.java index 16c7ab03..9f059088 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/SolutionCompletenessRatio.java @@ -15,50 +15,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.graphhopper.jsprit.core.algorithm.recreate; +package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.algorithm.recreate.listener.InsertionStartsListener; import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobInsertedListener; -import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import java.util.Collection; +/** + * Created by schroeder on 11/01/17. + */ +class SolutionCompletenessRatio implements InsertionStartsListener, JobInsertedListener { -final class ConfigureFixCostCalculator implements InsertionStartsListener, JobInsertedListener { + protected double solutionCompletenessRatio = 0.5; - private final VehicleRoutingProblem vrp; - - private final JobInsertionConsideringFixCostsCalculator calcConsideringFix; - - private final double minRatio = 0.5; + private final int nuOfJobs; private int nuOfJobsToRecreate; - public ConfigureFixCostCalculator(VehicleRoutingProblem vrp, JobInsertionConsideringFixCostsCalculator calcConsideringFix) { - super(); - this.vrp = vrp; - this.calcConsideringFix = calcConsideringFix; + public SolutionCompletenessRatio(int nuOfJobs) { + this.nuOfJobs = nuOfJobs; } - @Override - public String toString() { - return "[name=configureFixCostCalculator]"; + public void setSolutionCompletenessRatio(double ratio) { + solutionCompletenessRatio = ratio; + } + + public double getSolutionCompletenessRatio() { + return solutionCompletenessRatio; } @Override public void informInsertionStarts(Collection routes, Collection unassignedJobs) { this.nuOfJobsToRecreate = unassignedJobs.size(); - double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size())); - calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio,completenessRatio)); + solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs)); } @Override public void informJobInserted(Job job2insert, VehicleRoute inRoute, double additionalCosts, double additionalTime) { nuOfJobsToRecreate--; - double completenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) vrp.getJobs().values().size())); - calcConsideringFix.setSolutionCompletenessRatio(Math.max(minRatio,completenessRatio)); + solutionCompletenessRatio = (1 - ((double) nuOfJobsToRecreate / (double) nuOfJobs)); } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculatorTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculatorTest.java deleted file mode 100644 index 5ed06ce6..00000000 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ConfigureFixCostCalculatorTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.graphhopper.jsprit.core.algorithm.recreate; - -import com.graphhopper.jsprit.core.algorithm.state.StateManager; -import com.graphhopper.jsprit.core.problem.AbstractJob; -import com.graphhopper.jsprit.core.problem.Location; -import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; -import com.graphhopper.jsprit.core.problem.job.Job; -import com.graphhopper.jsprit.core.problem.job.Service; -import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.mockito.Mockito.mock; - -/** - * Created by schroeder on 15/08/16. - */ -public class ConfigureFixCostCalculatorTest { - - VehicleRoutingProblem vrp; - - @Before - public void before(){ - VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); - for(int i=0;i<100;i++){ - Service service = Service.Builder.newInstance("" + i).setLocation(Location.newInstance(0)).build(); - vrpBuilder.addJob(service); - } - vrp = vrpBuilder.build(); - } - - @Test - public void shouldCalculateCorrectly(){ - List unassigned = new ArrayList<>(); - int count = 1; - for(String key : vrp.getJobs().keySet()) { - if(count <= 25) { - unassigned.add(vrp.getJobs().get(key)); - } - count++; - } - JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class)); - ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc); - c.informInsertionStarts(new ArrayList(), unassigned); - Assert.assertEquals(0.75, jicc.getSolutionCompletenessRatio(), 0.001); - } - - @Test - public void shouldBeMinRatio(){ - List unassigned = new ArrayList<>(); - int count = 1; - for(String key : vrp.getJobs().keySet()) { - if(count <= 75) { - unassigned.add(vrp.getJobs().get(key)); - } - count++; - } - JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class)); - ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc); - c.informInsertionStarts(new ArrayList(), unassigned); - Assert.assertEquals(0.5, jicc.getSolutionCompletenessRatio(), 0.001); - } - - @Test - public void shouldBeOne(){ - List unassigned = new ArrayList<>(); - JobInsertionConsideringFixCostsCalculator jicc = new JobInsertionConsideringFixCostsCalculator(mock(JobInsertionCostsCalculator.class),mock(StateManager.class)); - ConfigureFixCostCalculator c = new ConfigureFixCostCalculator(vrp,jicc); - c.informInsertionStarts(new ArrayList(), unassigned); - Assert.assertEquals(1.0, jicc.getSolutionCompletenessRatio(), 0.001); - } -} diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java index 7f674c09..e35273a8 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/JobInsertionConsideringFixCostsCalculatorTest.java @@ -20,6 +20,7 @@ package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.algorithm.state.InternalStates; import com.graphhopper.jsprit.core.problem.Capacity; import com.graphhopper.jsprit.core.problem.job.Job; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.state.RouteAndActivityStateGetter; import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; @@ -34,7 +35,9 @@ import static org.mockito.Mockito.when; public class JobInsertionConsideringFixCostsCalculatorTest { - private JobInsertionConsideringFixCostsCalculator calc; + private IncreasingAbsoluteFixedCosts absFixedCosts; + + private DecreasingRelativeFixedCosts relFixedCosts; private Vehicle small; @@ -75,168 +78,270 @@ public class JobInsertionConsideringFixCostsCalculatorTest { stateGetter = mock(RouteAndActivityStateGetter.class); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().build()); - calc = new JobInsertionConsideringFixCostsCalculator(jobInsertionCosts, stateGetter); + absFixedCosts = new IncreasingAbsoluteFixedCosts(10); + relFixedCosts = new DecreasingRelativeFixedCosts(stateGetter, 10); } @Test public void whenOldVehicleIsNullAndSolutionComplete_itShouldReturnFixedCostsOfNewVehicle() { - calc.setSolutionCompletenessRatio(1.0); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(1.0); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(1.0); + relFixedCosts.setWeightOfFixCost(1.0); //(1.*absFix + 0.*relFix) * completeness * weight = (1.*100. + 0.*50.) * 1. * 1. = 100. - assertEquals(100., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + assertEquals(100., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() { - calc.setSolutionCompletenessRatio(0.0); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(0.0); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(0.0); + relFixedCosts.setWeightOfFixCost(1.0); //(0.*absFix + 1.*relFix) * completeness * weight = 0. - assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + + assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.1); } @Test public void whenOldVehicleIsNullAndSolutionIs50PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() { - calc.setSolutionCompletenessRatio(0.5); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(0.5); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(0.5); + relFixedCosts.setWeightOfFixCost(1.0); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*100+0.5*50)*0.5*1. = 37.5 - assertEquals(37.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNullAndSolutionIs75PercentComplete_itShouldReturnAvgOfRelFixedAndAbsFixedCostOfNewVehicle() { - calc.setSolutionCompletenessRatio(0.75); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(0.75); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(0.75); + relFixedCosts.setWeightOfFixCost(1.0); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + //(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*100.+0.25*50.)*0.75*1. = 65.625 - assertEquals(65.625, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(65.625, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNullAndSolutionCompleteAndWeightIs05_itShouldReturnHalfOfFixedCostsOfNewVehicle() { - calc.setSolutionCompletenessRatio(1.0); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(1.0); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(1.0); + relFixedCosts.setWeightOfFixCost(.5); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*100. + 0.*50.) * 1. * 0.5 = 5. - assertEquals(50., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnHalfOfNoFixedCosts() { - calc.setSolutionCompletenessRatio(0.0); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(0.0); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(0.0); + relFixedCosts.setWeightOfFixCost(.5); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.*absFix + 1.*relFix) * 0. * .5 = 0. - assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() { - calc.setSolutionCompletenessRatio(0.5); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(0.5); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(0.5); + relFixedCosts.setWeightOfFixCost(.5); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*100+0.5*50)*0.5*0.5 = 18.75 - assertEquals(18.75, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnHalfOfAvgOfRelFixedAndAbsFixedCostOfNewVehicle() { - calc.setSolutionCompletenessRatio(0.75); - calc.setWeightOfFixCost(0.5); + absFixedCosts.setSolutionCompletenessRatio(0.75); + absFixedCosts.setWeightOfFixCost(0.5); + + relFixedCosts.setSolutionCompletenessRatio(0.75); + relFixedCosts.setWeightOfFixCost(0.5); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*100.+0.25*50.)*0.75*0.5 = 32.8125 - assertEquals(32.8125, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(32.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionComplete_itShouldReturnHalfOfFixedCostsOfNewVehicle() { - calc.setSolutionCompletenessRatio(1.0); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(1.0); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(1.0); + relFixedCosts.setWeightOfFixCost(1.0); + when(route.getVehicle()).thenReturn(small); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + //(1.*absFix + 0.*relFix) * completeness * weight = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 1. = 50. - assertEquals(50., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(50., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs0PercentComplete_itShouldReturnNoFixedCosts() { - calc.setSolutionCompletenessRatio(0.0); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(0.0); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(0.0); + relFixedCosts.setWeightOfFixCost(1.0); + when(route.getVehicle()).thenReturn(small); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.*absFix + 1.*relFix) * completeness * weight = 0. - assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs50PercentComplete_itShouldCorrectVal() { - calc.setSolutionCompletenessRatio(0.5); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(0.5); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(0.5); + relFixedCosts.setWeightOfFixCost(1.0); + when(route.getVehicle()).thenReturn(small); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.5*absFix + 0.5*relFix) * 0.5 * 1. = (0.5*(100-50)+0.5*(50-0))*0.5*1. = 25. - assertEquals(25., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs75PercentComplete_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.75); - calc.setWeightOfFixCost(1.0); + absFixedCosts.setSolutionCompletenessRatio(0.75); + absFixedCosts.setWeightOfFixCost(1.0); + + relFixedCosts.setSolutionCompletenessRatio(0.75); + relFixedCosts.setWeightOfFixCost(1.0); + when(route.getVehicle()).thenReturn(small); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.75*absFix + 0.25*relFix) * 0.75 * 1.= (0.75*(100.-50.)+0.25*(50.-0.))*0.75*1. = 37.5 - assertEquals(37.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(37.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionCompleteAndWeightIs05_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(1.0); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(1.0); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(1.0); + relFixedCosts.setWeightOfFixCost(.5); + when(route.getVehicle()).thenReturn(small); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(1.*absFix + 0.*relFix) * 1. * 0.5 = (1.*(100.-50.) + 0.*(50.-0.)) * 1. * 0.5 = 25. - assertEquals(25., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(25., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs0PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.0); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(0.0); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(0.0); + relFixedCosts.setWeightOfFixCost(.5); + when(route.getVehicle()).thenReturn(small); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.*absFix + 1.*relFix) * 0. * .5 = 0. - assertEquals(0., calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(0., absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.5); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(0.5); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(0.5); + relFixedCosts.setWeightOfFixCost(.5); + when(route.getVehicle()).thenReturn(small); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(50-0))*0.5*0.5 = 12.5 - assertEquals(12.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.75); - calc.setWeightOfFixCost(0.5); + absFixedCosts.setSolutionCompletenessRatio(0.75); + absFixedCosts.setWeightOfFixCost(0.5); + + relFixedCosts.setSolutionCompletenessRatio(0.75); + relFixedCosts.setWeightOfFixCost(0.5); + when(route.getVehicle()).thenReturn(small); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(50.-0.))*0.75*0.5 = 18.75 - assertEquals(18.75, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.5); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(0.5); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(0.5); + relFixedCosts.setWeightOfFixCost(.5); + when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).build()); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 - assertEquals(12.5, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(12.5, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.75); - calc.setWeightOfFixCost(0.5); + absFixedCosts.setSolutionCompletenessRatio(0.75); + absFixedCosts.setWeightOfFixCost(0.5); + + relFixedCosts.setSolutionCompletenessRatio(0.75); + relFixedCosts.setWeightOfFixCost(0.5); + when(route.getVehicle()).thenReturn(small); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*(75.-25.))*0.75*0.5 = 18.75 - assertEquals(18.75, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(18.75, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs50PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(.5); - calc.setWeightOfFixCost(.5); + absFixedCosts.setSolutionCompletenessRatio(.5); + absFixedCosts.setWeightOfFixCost(.5); + + relFixedCosts.setSolutionCompletenessRatio(.5); + relFixedCosts.setWeightOfFixCost(.5); when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); @@ -248,6 +353,8 @@ public class JobInsertionConsideringFixCostsCalculatorTest { when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 /* * (0.5*(100-50)+0.5*( @@ -256,13 +363,16 @@ public class JobInsertionConsideringFixCostsCalculatorTest { * = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5 * = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125 */ - assertEquals(7.8125, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(7.8125, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } @Test public void whenOldVehicleIsMoreExpensive() { - calc.setSolutionCompletenessRatio(1); - calc.setWeightOfFixCost(1); + absFixedCosts.setSolutionCompletenessRatio(1); + absFixedCosts.setWeightOfFixCost(1); + + relFixedCosts.setSolutionCompletenessRatio(1); + relFixedCosts.setWeightOfFixCost(1); when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); @@ -283,50 +393,77 @@ public class JobInsertionConsideringFixCostsCalculatorTest { * = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5 * = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125 */ - double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + + double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context); assertEquals(-50d, insertionCost, 0.01); } @Test public void smallVSMediumAbsCosts() { - calc.setSolutionCompletenessRatio(1); - calc.setWeightOfFixCost(1); + absFixedCosts.setSolutionCompletenessRatio(1); + absFixedCosts.setWeightOfFixCost(1); + + relFixedCosts.setSolutionCompletenessRatio(1); + relFixedCosts.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(small); - double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context); assertEquals(50d, insertionCost, 0.01); } @Test public void smallVSLargeAbsCosts() { - calc.setSolutionCompletenessRatio(1); - calc.setWeightOfFixCost(1); + absFixedCosts.setSolutionCompletenessRatio(1); + absFixedCosts.setWeightOfFixCost(1); + + relFixedCosts.setSolutionCompletenessRatio(1); + relFixedCosts.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(small); - double insertionCost = calc.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d); + double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context); assertEquals(150d, insertionCost, 0.01); } @Test public void largeVSMediumAbsCosts() { - calc.setSolutionCompletenessRatio(1); - calc.setWeightOfFixCost(1); + absFixedCosts.setSolutionCompletenessRatio(1); + absFixedCosts.setWeightOfFixCost(1); + + relFixedCosts.setSolutionCompletenessRatio(1); + relFixedCosts.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(large); - double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context); assertEquals(-100d, insertionCost, 0.01); } @Test public void mediumVSLargeAbsCosts() { - calc.setSolutionCompletenessRatio(1); - calc.setWeightOfFixCost(1); + absFixedCosts.setSolutionCompletenessRatio(1); + absFixedCosts.setWeightOfFixCost(1); + + relFixedCosts.setSolutionCompletenessRatio(1); + relFixedCosts.setWeightOfFixCost(1); + when(route.getVehicle()).thenReturn(medium); - double insertionCost = calc.getInsertionData(route, job, large, 0.0, null, Double.MAX_VALUE).getInsertionCost(); + JobInsertionContext context = new JobInsertionContext(route, job, large, null, 0d); + + double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context); assertEquals(100d, insertionCost, 0.01); } @Test public void whenOldVehicleIsMoreExpensive2() { - calc.setSolutionCompletenessRatio(0.1); - calc.setWeightOfFixCost(1); + absFixedCosts.setSolutionCompletenessRatio(0.1); + absFixedCosts.setWeightOfFixCost(1); + + relFixedCosts.setSolutionCompletenessRatio(0.1); + relFixedCosts.setWeightOfFixCost(1); when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); @@ -339,22 +476,27 @@ public class JobInsertionConsideringFixCostsCalculatorTest { when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); - //(0.5*absFix + 0.5*relFix) * 0.5 * 0.= (0.5*(100-50)+0.5*(75-25))*0.5*0.5 = 12.5 /* - * (0.5*(100-50)+0.5*( - * relFixNew - relFixOld = (75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.) = - * )*0.5*0.5 - * = (0.5*(100-50)+0.5*((75/100+100/400)/2.*100 - ((25/50+100/100)/2.*50.)))*0.5*0.5 - * = (0.5*(100-50)+0.5*12.5)*0.5*0.5 = 7.8125 - */ - double insertionCost = calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(); - assertEquals(-50d, insertionCost, 0.01); + job = 50 + abs = (50 - 100) * 0.1 * 0.1 * 1.0 = -0.5 + rel = ( (75/50+100/100)/2 * 50 - (25/100 + 100/400)/2 * 100) * 0.9 * 0.1 = 3.375 + c = -0.5 + 3.375 = 2.875 + + */ + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); + + double insertionCost = absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context); + assertEquals(2.875, insertionCost, 0.01); } @Test public void whenOldVehicleIsNotNullAndCurrentLoadIs25AndSolutionIs75PercentCompleteAndWeightIs05WithMultipleCapDims_itShouldReturnCorrectVal() { - calc.setSolutionCompletenessRatio(0.75); - calc.setWeightOfFixCost(0.5); + absFixedCosts.setSolutionCompletenessRatio(0.75); + absFixedCosts.setWeightOfFixCost(0.5); + + relFixedCosts.setSolutionCompletenessRatio(0.75); + relFixedCosts.setWeightOfFixCost(0.5); + when(job.getSize()).thenReturn(Capacity.Builder.newInstance().addDimension(0, 50).addDimension(1, 0).build()); VehicleType oType = VehicleTypeImpl.Builder.newInstance("otype").addCapacityDimension(0, 50).addCapacityDimension(1, 100).setFixedCost(50.0).build(); @@ -365,9 +507,11 @@ public class JobInsertionConsideringFixCostsCalculatorTest { when(route.getVehicle()).thenReturn(small); when(stateGetter.getRouteState(route, InternalStates.MAXLOAD, Capacity.class)).thenReturn(Capacity.Builder.newInstance().addDimension(0, 25).addDimension(1, 100).build()); + + JobInsertionContext context = new JobInsertionContext(route, job, medium, null, 0d); //(0.75*absFix + 0.25*relFix) * 0.75 * 0.5 = (0.75*(100.-50.)+0.25*12.5)*0.75*0.5 = 15.234375 - assertEquals(15.234375, calc.getInsertionData(route, job, medium, 0.0, null, Double.MAX_VALUE).getInsertionCost(), 0.01); + assertEquals(15.234375, absFixedCosts.getCosts(context) + relFixedCosts.getCosts(context), 0.01); } From 0f38d5ed7880e7d21e98d55315efa07d751c98d5 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 11 Jan 2017 20:30:07 +0100 Subject: [PATCH 032/106] align toString --- .../core/algorithm/recreate/DecreasingRelativeFixedCosts.java | 2 +- .../core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java index f9b45879..4f5b67f4 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/DecreasingRelativeFixedCosts.java @@ -50,7 +50,7 @@ public final class DecreasingRelativeFixedCosts extends SolutionCompletenessRati @Override public String toString() { - return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; + return "[name=DecreasingRelativeFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; } private Capacity getCurrentMaxLoadInRoute(VehicleRoute route) { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java index 96854d57..ffaf2674 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/IncreasingAbsoluteFixedCosts.java @@ -44,7 +44,7 @@ public final class IncreasingAbsoluteFixedCosts extends SolutionCompletenessRati @Override public String toString() { - return "[name=calculatesServiceInsertionConsideringFixCost][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; + return "[name=IncreasingAbsoluteFixedCosts][weightOfFixedCostSavings=" + weightDeltaFixCost + "]"; } @Override From 142c3beff6ae41b0d0b9f771dcba13393012d427 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 12 Jan 2017 11:19:16 +0100 Subject: [PATCH 033/106] v1.7 --- jsprit-analysis/pom.xml | 2 +- jsprit-core/pom.xml | 2 +- jsprit-examples/pom.xml | 2 +- jsprit-instances/pom.xml | 2 +- jsprit-io/pom.xml | 4 ++-- pom.xml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/jsprit-analysis/pom.xml b/jsprit-analysis/pom.xml index dc12d885..a5707f18 100644 --- a/jsprit-analysis/pom.xml +++ b/jsprit-analysis/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.6.3-SNAPSHOT + 1.7-SNAPSHOT 4.0.0 jsprit-analysis diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index 5e2d2512..f3d79fc0 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -21,7 +21,7 @@ com.graphhopper jsprit - 1.6.3-SNAPSHOT + 1.7-SNAPSHOT 4.0.0 jsprit-core diff --git a/jsprit-examples/pom.xml b/jsprit-examples/pom.xml index 0600d0d3..3680ba94 100644 --- a/jsprit-examples/pom.xml +++ b/jsprit-examples/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.6.3-SNAPSHOT + 1.7-SNAPSHOT 4.0.0 diff --git a/jsprit-instances/pom.xml b/jsprit-instances/pom.xml index 5f7aace3..04a8e8f4 100644 --- a/jsprit-instances/pom.xml +++ b/jsprit-instances/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.6.3-SNAPSHOT + 1.7-SNAPSHOT 4.0.0 diff --git a/jsprit-io/pom.xml b/jsprit-io/pom.xml index 343cfe84..8487e20a 100644 --- a/jsprit-io/pom.xml +++ b/jsprit-io/pom.xml @@ -22,8 +22,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> com.graphhopper - jsprit - 1.6.3-SNAPSHOT + jsprit + 1.7-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index da7ba9ec..ed207968 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ com.graphhopper jsprit - 1.6.3-SNAPSHOT + 1.7-SNAPSHOT pom From f7088b8ba2348362a1aece9ac746975b55f32dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Thu, 12 Jan 2017 11:28:43 +0100 Subject: [PATCH 034/106] v1.7 --- WHATS_NEW.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WHATS_NEW.md b/WHATS_NEW.md index 462a7cc0..04e27c30 100644 --- a/WHATS_NEW.md +++ b/WHATS_NEW.md @@ -1,15 +1,17 @@ WHATS NEW ========== ------------------------------ -?? new release **v1.7** +2017-01-12 new release **v1.7** - move packages to [graphhopper.com](https://graphhopper.com/) - change license from GPLv3 to [Apache v2](https://github.com/graphhopper/jsprit/blob/master/LICENSE.md) to make it even more attractive for other developers and their commercial applications - pushed binaries to maven central, i.e. made it better accessible and we get rid of our own repo - outsourced various io operations, e.g. reading writing problem/algorithm to a new module called [jsprit-io](https://github.com/graphhopper/jsprit/tree/master/jsprit-io). this way the core is even more lightweight and less dependent on other libraries - switched from log4j to the [logger facade slf4j](http://www.slf4j.org/) to allow developers to plugin the logger of their choice - made it [much more memory efficient](https://github.com/graphhopper/jsprit/issues/230) for large problems +- fixed [memory leak](https://github.com/graphhopper/jsprit/pull/282) - add [priority feature](https://github.com/graphhopper/jsprit/issues/242) - [refine exceptions](https://github.com/graphhopper/jsprit/issues/251) to get a clear separation of IllegalArgument and [IllegalState](https://stackoverflow.com/questions/12698275/whats-the-intended-use-of-illegalstateexception) +- many further improvements (see https://github.com/graphhopper/jsprit/issues?q=is%3Aissue+is%3Aclosed) 2016-02-02 new release **v1.6.2** From bbde9f47516924c58f264a0580cf287934376be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Thu, 12 Jan 2017 11:32:16 +0100 Subject: [PATCH 035/106] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa7957f3..cd6636b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Change-log ========== +**v1.7** @ 2017-01-12 +- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md) + **v1.6.2** @ 2016-02-02 new features: From 332009e3bc2d59dc3526cd2448ab32cf8cf486d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Fri, 13 Jan 2017 00:31:32 +0100 Subject: [PATCH 036/106] Update Getting-Started.md --- docs/Getting-Started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index c49fe090..3efb5586 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -15,7 +15,7 @@ If you want to use the latest release of jsprit-core, add the following lines to
<dependency>
    <groupId>com.graphhopper</groupId>
    <artifactId>jsprit-core</artifactId>
-   <version>1.7-RC1</version>
+   <version>1.7</version>
 </dependency>
 
From 6d4f26c5ae5934ac986530e9420f391f1f467fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Fri, 13 Jan 2017 09:22:03 +0100 Subject: [PATCH 037/106] Update Getting-Started.md --- docs/Getting-Started.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index 3efb5586..f57de61d 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -15,10 +15,12 @@ If you want to use the latest release of jsprit-core, add the following lines to
<dependency>
    <groupId>com.graphhopper</groupId>
    <artifactId>jsprit-core</artifactId>
-   <version>1.7</version>
+   <version>{version}</version>
 </dependency>
 
+Find the latest versions here: [maven search](https://search.maven.org/#search%7Cga%7C1%7Cjsprit). + ####Build yourself If you want to build the master branch yourself, do this: From 0e4b8ed5d79ece5807847453734a74b94d2ea5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Fri, 13 Jan 2017 09:24:03 +0100 Subject: [PATCH 038/106] Update Getting-Started.md --- docs/Getting-Started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index f57de61d..de791933 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -19,7 +19,7 @@ If you want to use the latest release of jsprit-core, add the following lines to </dependency> -Find the latest versions here: [maven search](https://search.maven.org/#search%7Cga%7C1%7Cjsprit). +Find the latest versions here: [maven search](https://search.maven.org/#search%7Cga%7C1%7Cjsprit) or [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core). ####Build yourself If you want to build the master branch yourself, do this: From 9c85f674924fa932d1184fcc96ce249dc9e1ea4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Sat, 14 Jan 2017 11:37:36 +0100 Subject: [PATCH 039/106] Update Getting-Started.md --- docs/Getting-Started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index de791933..44528c2b 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -19,7 +19,7 @@ If you want to use the latest release of jsprit-core, add the following lines to </dependency> -Find the latest versions here: [maven search](https://search.maven.org/#search%7Cga%7C1%7Cjsprit) or [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core). +Find the latest versions here:[mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core). ####Build yourself If you want to build the master branch yourself, do this: From 802a20a90c9fd0361e55a9d114eef60cc61f7698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Sat, 14 Jan 2017 11:37:57 +0100 Subject: [PATCH 040/106] Update Getting-Started.md --- docs/Getting-Started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index 44528c2b..ac5af692 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -19,7 +19,7 @@ If you want to use the latest release of jsprit-core, add the following lines to </dependency> -Find the latest versions here:[mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core). +Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core). ####Build yourself If you want to build the master branch yourself, do this: From 25fe0838099e968d1dd847f809e7105b4f153593 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 18 Jan 2017 19:43:52 +0100 Subject: [PATCH 041/106] refine string removal --- .../jsprit/core/algorithm/box/Jsprit.java | 21 +- .../core/algorithm/ruin/RuinString.java | 231 ++++++++ .../core/algorithm/ruin/StringUtil.java | 52 ++ .../core/algorithm/ruin/StringUtilTest.java | 87 +++ jsprit-examples/input/p01_mod | 56 ++ jsprit-examples/input/p08 | 508 +++++++++--------- .../examples/BuildAlgorithmFromScratch.java | 17 +- .../examples/BuildAlgorithmFromScratch2.java | 252 +++++++++ 8 files changed, 960 insertions(+), 264 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtil.java create mode 100644 jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtilTest.java create mode 100644 jsprit-examples/input/p01_mod create mode 100644 jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 3ad56495..c0a243cc 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -82,7 +82,9 @@ public class Jsprit { WORST_BEST("worst_best"), WORST_REGRET("worst_regret"), CLUSTER_BEST("cluster_best"), - CLUSTER_REGRET("cluster_regret"); + CLUSTER_REGRET("cluster_regret"), + STRING_BEST("string_best"), + STRING_REGRET("string_regret"); String strategyName; @@ -178,6 +180,10 @@ public class Jsprit { defaults.put(Strategy.RADIAL_REGRET.toString(), ".5"); defaults.put(Strategy.RANDOM_BEST.toString(), ".5"); defaults.put(Strategy.RANDOM_REGRET.toString(), ".5"); + + defaults.put(Strategy.STRING_BEST.toString(), ".5"); + defaults.put(Strategy.STRING_REGRET.toString(), ".5"); + defaults.put(Strategy.WORST_BEST.toString(), "0."); defaults.put(Strategy.WORST_REGRET.toString(), "1."); defaults.put(Strategy.CLUSTER_BEST.toString(), "0."); @@ -472,6 +478,9 @@ public class Jsprit { random) ); + final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods); + stringRuin.setRandom(random); + AbstractInsertionStrategy regret; final ScoringFunction scorer; @@ -592,6 +601,11 @@ public class Jsprit { final SearchStrategy clusters_best = new SearchStrategy(Strategy.CLUSTER_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); clusters_best.addModule(new RuinAndRecreateModule(Strategy.CLUSTER_BEST.toString(), best, clusters)); + SearchStrategy stringRegret = new SearchStrategy(Strategy.STRING_REGRET.toString(), new SelectBest(), acceptor, objectiveFunction); + stringRegret.addModule(new RuinAndRecreateModule(Strategy.STRING_REGRET.toString(), regret, stringRuin)); + + SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); + stringBest.addModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin)); PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager); prettyBuilder.setRandom(random); @@ -605,7 +619,10 @@ public class Jsprit { .withStrategy(worst_best, toDouble(getProperty(Strategy.WORST_BEST.toString()))) .withStrategy(worst_regret, toDouble(getProperty(Strategy.WORST_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()))) + .withStrategy(stringBest, toDouble(getProperty(Strategy.STRING_BEST.toString()))) + .withStrategy(stringRegret, toDouble(getProperty(Strategy.STRING_REGRET.toString()))); + if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) { prettyBuilder.constructInitialSolutionWith(best, objectiveFunction); } else { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java new file mode 100644 index 00000000..530f103c --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -0,0 +1,231 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.graphhopper.jsprit.core.algorithm.ruin; + +import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance; +import com.graphhopper.jsprit.core.problem.AbstractActivity; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.job.Job; +import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; +import com.graphhopper.jsprit.core.util.RandomUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + + +/** + * RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by + * the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary + * measure). + * + * @author stefan + */ +public final class RuinString extends AbstractRuinStrategy { + + private Logger logger = LoggerFactory.getLogger(RuinString.class); + + private VehicleRoutingProblem vrp; + + private JobNeighborhoods jobNeighborhoods; + + private int Kmin = 1; + + private int Kmax = 6; + + private int Lmin = 1; + + private int Lmax = 40; + + /** + * Constructs RuinRadial. + * + * @param vrp + * @param jobDistance i.e. a measure to define the distance between two jobs and whether they are located close or distant to eachother + * @param Kmin + * @param Kmax + * @param Lmin + * @param Lmax + */ + public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance, int Kmin, int Kmax, int Lmin, int Lmax) { + super(vrp); + this.vrp = vrp; + JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax); + jobNeighborhoodsImpl.initialise(); + jobNeighborhoods = jobNeighborhoodsImpl; + this.Kmin = Kmin; + this.Kmax = Kmax; + this.Lmin = Lmin; + this.Lmax = Lmax; + logger.debug("initialise {}", this); + } + + public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance) { + super(vrp); + this.vrp = vrp; + JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax); + jobNeighborhoodsImpl.initialise(); + jobNeighborhoods = jobNeighborhoodsImpl; + logger.debug("initialise {}", this); + } + + public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) { + super(vrp); + this.vrp = vrp; + this.jobNeighborhoods = jobNeighborhoods; + logger.debug("initialise {}", this); + } + + @Override + public String toString() { + return "[name=splitRuin]"; + } + + /** + * Ruins the collection of vehicleRoutes, i.e. removes a share of jobs. First, it selects a job randomly. Second, it identifies its neighborhood. And finally, it removes + * the neighborhood plus the randomly selected job from the number of vehicleRoutes. All removed jobs are then returned as a collection. + */ + @Override + public Collection ruinRoutes(Collection vehicleRoutes) { + if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) { + return Collections.emptyList(); + } + int noStrings = Kmin + random.nextInt((Kmax - Kmin)); + noStrings = Math.min(noStrings, vehicleRoutes.size()); + Set unassignedJobs = new HashSet<>(); + Set ruinedRoutes = new HashSet<>(); + Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random); + Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(Kmax * Lmax, prevJob); + while (neighborhoodIterator.hasNext() && ruinedRoutes.size() <= noStrings) { + if (!unassignedJobs.contains(prevJob)) { + VehicleRoute route = getRouteOf(prevJob, vehicleRoutes); + if (route != null && !ruinedRoutes.contains(route)) { + if (random.nextDouble() < .5) { + ruinRouteWithStringRuin(route, prevJob, unassignedJobs); + } else { + ruinRouteWithSplitStringRuin(route, prevJob, unassignedJobs); + } + ruinedRoutes.add(route); + } + } + prevJob = neighborhoodIterator.next(); + } + return unassignedJobs; + } + + private VehicleRoute getRouteOf(Job job, Collection vehicleRoutes) { + for (VehicleRoute route : vehicleRoutes) { + if (route.getTourActivities().servesJob(job)) return route; + } + return null; + } + + private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { + int noActivities = seedRoute.getActivities().size(); + int stringLength = Lmin + random.nextInt(Lmax - Lmin); + stringLength = Math.min(stringLength, seedRoute.getActivities().size()); + + int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random); + + List acts = vrp.getActivities(prevJob); + AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random); + int seedIndex = 0; + + int index = 0; + for (TourActivity act : seedRoute.getActivities()) { + if (act.getIndex() == randomSeedAct.getIndex()) { + seedIndex = index; + break; + } + index++; + } + + int totalStringLength = stringLength + preservedSubstringLength; + List stringBounds = StringUtil.getLowerBoundsOfAllStrings(totalStringLength, seedIndex, noActivities); + if (stringBounds.isEmpty()) return; + int lowerBound = RandomUtils.nextItem(stringBounds, random); + + List jobs2Remove = new ArrayList<>(); + int startIndexOfPreservedSubstring = random.nextInt(stringLength); + int position = 0; + int noStringsInPreservedSubstring = 0; + boolean isPreservedSubstring = false; + for (int i = lowerBound; i < (lowerBound + totalStringLength); i++) { + if (position == startIndexOfPreservedSubstring) { + isPreservedSubstring = true; + } + if (noStringsInPreservedSubstring >= preservedSubstringLength) { + isPreservedSubstring = false; + } + if (!isPreservedSubstring) { + TourActivity act = seedRoute.getActivities().get(i); + if (act instanceof TourActivity.JobActivity) { + Job job = ((TourActivity.JobActivity) act).getJob(); + if (vrp.getJobs().containsKey(job.getId())) { + jobs2Remove.add(job); + } + } + } else noStringsInPreservedSubstring++; + position++; + } + for (Job job : jobs2Remove) { + removeJob(job, seedRoute); + unassignedJobs.add(job); + } + + } + + + private void ruinRouteWithStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { + int stringLength = Lmin + random.nextInt(Lmax - Lmin); + stringLength = Math.min(stringLength, seedRoute.getActivities().size()); + List acts = vrp.getActivities(prevJob); + AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random); + int seedIndex = 0; + int noActivities = seedRoute.getActivities().size(); + int index = 0; + for (TourActivity act : seedRoute.getActivities()) { + if (act.getIndex() == randomSeedAct.getIndex()) { + seedIndex = index; + break; + } + index++; + } + List stringBounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities); + if (stringBounds.isEmpty()) return; + int lowerBound = RandomUtils.nextItem(stringBounds, random); + List jobs2Remove = new ArrayList<>(); + for (int i = lowerBound; i < (lowerBound + stringLength); i++) { + TourActivity act = seedRoute.getActivities().get(i); + if (act instanceof TourActivity.JobActivity) { + Job job = ((TourActivity.JobActivity) act).getJob(); + if (vrp.getJobs().containsKey(job.getId())) { + jobs2Remove.add(job); + } + } + } + for (Job job : jobs2Remove) { + removeJob(job, seedRoute); + unassignedJobs.add(job); + } + + } + + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtil.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtil.java new file mode 100644 index 00000000..b9070a1c --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtil.java @@ -0,0 +1,52 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.algorithm.ruin; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Created by schroeder on 13/01/17. + */ +class StringUtil { + + static List getLowerBoundsOfAllStrings(int length, int seedIndex, int routeLength) { + List lowerBounds = new ArrayList<>(); + for (int i = 1; i <= length; i++) { + int lower = seedIndex - (length - i); + int upper = seedIndex + (i - 1); + if (lower >= 0 && upper < routeLength) { + lowerBounds.add(lower); + } + } + return lowerBounds; + } + + static int determineSubstringLength(int baseLength, int routeLength, Random random) { + if (baseLength == routeLength) return 0; + int substringLength = 1; + while (baseLength + substringLength < routeLength) { + if (random.nextDouble() < 0.01) { + return substringLength; + } else substringLength++; + } + return substringLength; + } +} diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtilTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtilTest.java new file mode 100644 index 00000000..9a8cbbf4 --- /dev/null +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/ruin/StringUtilTest.java @@ -0,0 +1,87 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.algorithm.ruin; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +/** + * Created by schroeder on 13/01/17. + */ +public class StringUtilTest { + + @Test + public void test() { + int stringLength = 4; + int seedIndex = 4; + int noActivities = 10; + List bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities); + Assert.assertEquals(4, bounds.size()); + Assert.assertEquals(1, (int) bounds.get(0)); + Assert.assertEquals(2, (int) bounds.get(1)); + Assert.assertEquals(3, (int) bounds.get(2)); + Assert.assertEquals(4, (int) bounds.get(3)); + + } + + @Test + public void test2() { + int stringLength = 4; + int seedIndex = 2; + int noActivities = 10; + List bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities); + Assert.assertEquals(3, bounds.size()); + Assert.assertEquals(0, (int) bounds.get(0)); + Assert.assertEquals(1, (int) bounds.get(1)); + Assert.assertEquals(2, (int) bounds.get(2)); + } + + @Test + public void test3() { + int stringLength = 4; + int seedIndex = 0; + int noActivities = 10; + List bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities); + Assert.assertEquals(1, bounds.size()); + Assert.assertEquals(0, (int) bounds.get(0)); + } + + @Test + public void test4() { + int stringLength = 4; + int seedIndex = 9; + int noActivities = 10; + List bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities); + Assert.assertEquals(1, bounds.size()); + Assert.assertEquals(6, (int) bounds.get(0)); + } + + @Test + public void test5() { + int stringLength = 4; + int seedIndex = 8; + int noActivities = 10; + List bounds = StringUtil.getLowerBoundsOfAllStrings(stringLength, seedIndex, noActivities); + Assert.assertEquals(2, bounds.size()); + Assert.assertEquals(5, (int) bounds.get(0)); + Assert.assertEquals(6, (int) bounds.get(1)); + } +} diff --git a/jsprit-examples/input/p01_mod b/jsprit-examples/input/p01_mod new file mode 100644 index 00000000..f7126b87 --- /dev/null +++ b/jsprit-examples/input/p01_mod @@ -0,0 +1,56 @@ +2 4 50 4 +0 2000 + 1 37 52 0 7 1 4 1 2 4 8 + 2 49 49 0 30 1 4 1 2 4 8 + 3 52 64 0 16 1 4 1 2 4 8 + 4 20 26 0 9 1 4 1 2 4 8 + 5 40 30 0 21 1 4 1 2 4 8 + 6 21 47 0 15 1 4 1 2 4 8 + 7 17 63 0 19 1 4 1 2 4 8 + 8 31 62 0 23 1 4 1 2 4 8 + 9 52 33 0 11 1 4 1 2 4 8 +10 51 21 0 5 1 4 1 2 4 8 +11 42 41 0 19 1 4 1 2 4 8 +12 31 32 0 29 1 4 1 2 4 8 +13 5 25 0 23 1 4 1 2 4 8 +14 12 42 0 21 1 4 1 2 4 8 +15 36 16 0 10 1 4 1 2 4 8 +16 52 41 0 15 1 4 1 2 4 8 +17 27 23 0 3 1 4 1 2 4 8 +18 17 33 0 41 1 4 1 2 4 8 +19 13 13 0 9 1 4 1 2 4 8 +20 57 58 0 28 1 4 1 2 4 8 +21 62 42 0 8 1 4 1 2 4 8 +22 42 57 0 8 1 4 1 2 4 8 +23 16 57 0 16 1 4 1 2 4 8 +24 8 52 0 10 1 4 1 2 4 8 +25 7 38 0 28 1 4 1 2 4 8 +26 27 68 0 7 1 4 1 2 4 8 +27 30 48 0 15 1 4 1 2 4 8 +28 43 67 0 14 1 4 1 2 4 8 +29 58 48 0 6 1 4 1 2 4 8 +30 58 27 0 19 1 4 1 2 4 8 +31 37 69 0 11 1 4 1 2 4 8 +32 38 46 0 12 1 4 1 2 4 8 +33 46 10 0 23 1 4 1 2 4 8 +34 61 33 0 26 1 4 1 2 4 8 +35 62 63 0 17 1 4 1 2 4 8 +36 63 69 0 6 1 4 1 2 4 8 +37 32 22 0 9 1 4 1 2 4 8 +38 45 35 0 15 1 4 1 2 4 8 +39 59 15 0 14 1 4 1 2 4 8 +40 5 6 0 7 1 4 1 2 4 8 +41 10 17 0 27 1 4 1 2 4 8 +42 21 10 0 13 1 4 1 2 4 8 +43 5 64 0 11 1 4 1 2 4 8 +44 30 15 0 16 1 4 1 2 4 8 +45 39 10 0 10 1 4 1 2 4 8 +46 32 39 0 5 1 4 1 2 4 8 +47 25 32 0 25 1 4 1 2 4 8 +48 25 55 0 17 1 4 1 2 4 8 +49 48 28 0 18 1 4 1 2 4 8 +50 56 37 0 10 1 4 1 2 4 8 +51 20 20 0 0 0 0 +52 30 40 0 0 0 0 +53 50 30 0 0 0 0 +54 60 50 0 0 0 0 diff --git a/jsprit-examples/input/p08 b/jsprit-examples/input/p08 index e272d5d8..a2ab1f28 100644 --- a/jsprit-examples/input/p08 +++ b/jsprit-examples/input/p08 @@ -1,254 +1,254 @@ -2 14 249 2 -310 500 -310 500 - 1 -99 -97 0 6 1 2 1 2 - 2 -59 50 0 72 1 2 1 2 - 3 0 14 0 93 1 2 1 2 - 4 -17 -66 0 28 1 2 1 2 - 5 -69 -19 0 5 1 2 1 2 - 6 31 12 0 43 1 2 1 2 - 7 5 -41 0 1 1 2 1 2 - 8 -12 10 0 36 1 2 1 2 - 9 -64 70 0 53 1 2 1 2 - 10 -12 85 0 63 1 2 1 2 - 11 -18 64 0 25 1 2 1 2 - 12 -77 -16 0 50 1 2 1 2 - 13 -53 88 0 57 1 2 1 2 - 14 83 -24 0 1 1 2 1 2 - 15 24 41 0 66 1 2 1 2 - 16 17 21 0 37 1 2 1 2 - 17 42 96 0 51 1 2 1 2 - 18 -65 0 0 47 1 2 1 2 - 19 -47 -26 0 88 1 2 1 2 - 20 85 36 0 75 1 2 1 2 - 21 -35 -54 0 48 1 2 1 2 - 22 54 -21 0 40 1 2 1 2 - 23 64 -17 0 8 1 2 1 2 - 24 55 89 0 69 1 2 1 2 - 25 17 -25 0 93 1 2 1 2 - 26 -61 66 0 29 1 2 1 2 - 27 -61 26 0 5 1 2 1 2 - 28 17 -72 0 53 1 2 1 2 - 29 79 38 0 8 1 2 1 2 - 30 -62 -2 0 24 1 2 1 2 - 31 -90 -68 0 53 1 2 1 2 - 32 52 66 0 13 1 2 1 2 - 33 -54 -50 0 47 1 2 1 2 - 34 8 -84 0 57 1 2 1 2 - 35 37 -90 0 9 1 2 1 2 - 36 -83 49 0 74 1 2 1 2 - 37 35 -1 0 83 1 2 1 2 - 38 7 59 0 96 1 2 1 2 - 39 12 48 0 42 1 2 1 2 - 40 57 95 0 80 1 2 1 2 - 41 92 28 0 22 1 2 1 2 - 42 -3 97 0 56 1 2 1 2 - 43 -7 52 0 43 1 2 1 2 - 44 42 -15 0 12 1 2 1 2 - 45 77 -43 0 73 1 2 1 2 - 46 59 -49 0 32 1 2 1 2 - 47 25 91 0 8 1 2 1 2 - 48 69 -19 0 79 1 2 1 2 - 49 -82 -14 0 79 1 2 1 2 - 50 74 -70 0 4 1 2 1 2 - 51 69 59 0 14 1 2 1 2 - 52 29 33 0 17 1 2 1 2 - 53 -97 9 0 19 1 2 1 2 - 54 -58 9 0 44 1 2 1 2 - 55 28 93 0 5 1 2 1 2 - 56 7 73 0 37 1 2 1 2 - 57 -28 73 0 100 1 2 1 2 - 58 -76 55 0 62 1 2 1 2 - 59 41 42 0 90 1 2 1 2 - 60 92 40 0 57 1 2 1 2 - 61 -84 -29 0 44 1 2 1 2 - 62 -12 42 0 37 1 2 1 2 - 63 51 -45 0 80 1 2 1 2 - 64 -37 46 0 60 1 2 1 2 - 65 -97 35 0 95 1 2 1 2 - 66 14 89 0 56 1 2 1 2 - 67 60 58 0 56 1 2 1 2 - 68 -63 -75 0 9 1 2 1 2 - 69 -18 34 0 39 1 2 1 2 - 70 -46 -82 0 15 1 2 1 2 - 71 -86 -79 0 4 1 2 1 2 - 72 -43 -30 0 58 1 2 1 2 - 73 -44 7 0 73 1 2 1 2 - 74 -3 -20 0 5 1 2 1 2 - 75 36 41 0 12 1 2 1 2 - 76 -30 -94 0 3 1 2 1 2 - 77 79 -62 0 8 1 2 1 2 - 78 51 70 0 31 1 2 1 2 - 79 -61 -26 0 48 1 2 1 2 - 80 6 94 0 3 1 2 1 2 - 81 -19 -62 0 52 1 2 1 2 - 82 -20 51 0 99 1 2 1 2 - 83 -81 37 0 29 1 2 1 2 - 84 7 31 0 12 1 2 1 2 - 85 52 12 0 50 1 2 1 2 - 86 83 -91 0 98 1 2 1 2 - 87 -7 -92 0 4 1 2 1 2 - 88 82 -74 0 56 1 2 1 2 - 89 -70 85 0 24 1 2 1 2 - 90 -83 -30 0 33 1 2 1 2 - 91 71 -61 0 45 1 2 1 2 - 92 85 11 0 98 1 2 1 2 - 93 66 -48 0 4 1 2 1 2 - 94 78 -87 0 36 1 2 1 2 - 95 9 -79 0 72 1 2 1 2 - 96 -36 4 0 26 1 2 1 2 - 97 66 39 0 71 1 2 1 2 - 98 92 -17 0 84 1 2 1 2 - 99 -46 -79 0 21 1 2 1 2 -100 -30 -63 0 99 1 2 1 2 -101 -42 63 0 33 1 2 1 2 -102 20 42 0 84 1 2 1 2 -103 15 98 0 74 1 2 1 2 -104 1 -17 0 93 1 2 1 2 -105 64 20 0 25 1 2 1 2 -106 -96 85 0 39 1 2 1 2 -107 93 -29 0 42 1 2 1 2 -108 -40 -84 0 77 1 2 1 2 -109 86 35 0 68 1 2 1 2 -110 91 36 0 50 1 2 1 2 -111 62 -8 0 42 1 2 1 2 -112 -24 4 0 71 1 2 1 2 -113 11 96 0 85 1 2 1 2 -114 -53 62 0 78 1 2 1 2 -115 -28 -71 0 64 1 2 1 2 -116 7 -4 0 5 1 2 1 2 -117 95 -9 0 93 1 2 1 2 -118 -3 17 0 18 1 2 1 2 -119 53 -90 0 38 1 2 1 2 -120 58 -19 0 29 1 2 1 2 -121 -83 84 0 81 1 2 1 2 -122 -1 49 0 4 1 2 1 2 -123 -4 17 0 23 1 2 1 2 -124 -82 -3 0 11 1 2 1 2 -125 -43 47 0 86 1 2 1 2 -126 6 -6 0 2 1 2 1 2 -127 70 99 0 31 1 2 1 2 -128 68 -29 0 54 1 2 1 2 -129 -94 -30 0 87 1 2 1 2 -130 -94 -20 0 17 1 2 1 2 -131 -21 77 0 81 1 2 1 2 -132 64 37 0 72 1 2 1 2 -133 -70 -19 0 10 1 2 1 2 -134 88 65 0 50 1 2 1 2 -135 2 29 0 25 1 2 1 2 -136 33 57 0 71 1 2 1 2 -137 -70 6 0 85 1 2 1 2 -138 -38 -56 0 51 1 2 1 2 -139 -80 -95 0 29 1 2 1 2 -140 -5 -39 0 55 1 2 1 2 -141 8 -22 0 45 1 2 1 2 -142 -61 -76 0 100 1 2 1 2 -143 76 -22 0 38 1 2 1 2 -144 49 -71 0 11 1 2 1 2 -145 -30 -68 0 82 1 2 1 2 -146 1 34 0 50 1 2 1 2 -147 77 79 0 39 1 2 1 2 -148 -58 64 0 6 1 2 1 2 -149 82 -97 0 87 1 2 1 2 -150 -80 55 0 83 1 2 1 2 -151 81 -86 0 22 1 2 1 2 -152 39 -49 0 24 1 2 1 2 -153 -67 72 0 69 1 2 1 2 -154 -25 -89 0 97 1 2 1 2 -155 -44 -95 0 65 1 2 1 2 -156 32 -68 0 97 1 2 1 2 -157 -17 49 0 79 1 2 1 2 -158 93 49 0 79 1 2 1 2 -159 99 81 0 46 1 2 1 2 -160 10 -49 0 52 1 2 1 2 -161 63 -41 0 39 1 2 1 2 -162 38 39 0 94 1 2 1 2 -163 -28 39 0 97 1 2 1 2 -164 -2 -47 0 18 1 2 1 2 -165 38 8 0 3 1 2 1 2 -166 -42 -6 0 23 1 2 1 2 -167 -67 88 0 19 1 2 1 2 -168 19 93 0 40 1 2 1 2 -169 40 27 0 49 1 2 1 2 -170 -61 56 0 96 1 2 1 2 -171 43 33 0 58 1 2 1 2 -172 -18 -39 0 15 1 2 1 2 -173 -69 19 0 21 1 2 1 2 -174 75 -18 0 56 1 2 1 2 -175 31 85 0 67 1 2 1 2 -176 25 58 0 10 1 2 1 2 -177 -16 36 0 36 1 2 1 2 -178 91 15 0 84 1 2 1 2 -179 60 -39 0 59 1 2 1 2 -180 49 -47 0 85 1 2 1 2 -181 42 33 0 60 1 2 1 2 -182 16 -81 0 33 1 2 1 2 -183 -78 53 0 62 1 2 1 2 -184 53 -80 0 70 1 2 1 2 -185 -46 -26 0 79 1 2 1 2 -186 -25 -54 0 98 1 2 1 2 -187 69 -46 0 99 1 2 1 2 -188 0 -78 0 18 1 2 1 2 -189 -84 74 0 55 1 2 1 2 -190 -16 16 0 75 1 2 1 2 -191 -63 -14 0 94 1 2 1 2 -192 51 -77 0 89 1 2 1 2 -193 -39 61 0 13 1 2 1 2 -194 5 97 0 19 1 2 1 2 -195 -55 39 0 19 1 2 1 2 -196 70 -14 0 90 1 2 1 2 -197 0 95 0 35 1 2 1 2 -198 -45 7 0 76 1 2 1 2 -199 38 -24 0 3 1 2 1 2 -200 50 -37 0 11 1 2 1 2 -201 59 71 0 98 1 2 1 2 -202 -73 -96 0 92 1 2 1 2 -203 -29 72 0 1 1 2 1 2 -204 -47 12 0 2 1 2 1 2 -205 -88 -61 0 63 1 2 1 2 -206 -88 36 0 57 1 2 1 2 -207 -46 -3 0 50 1 2 1 2 -208 26 -37 0 19 1 2 1 2 -209 -39 -67 0 24 1 2 1 2 -210 92 27 0 14 1 2 1 2 -211 -80 -31 0 18 1 2 1 2 -212 93 -50 0 77 1 2 1 2 -213 -20 -5 0 28 1 2 1 2 -214 -22 73 0 72 1 2 1 2 -215 -4 -7 0 49 1 2 1 2 -216 54 -48 0 58 1 2 1 2 -217 -70 39 0 84 1 2 1 2 -218 54 -82 0 58 1 2 1 2 -219 29 41 0 41 1 2 1 2 -220 -87 51 0 98 1 2 1 2 -221 -96 -36 0 77 1 2 1 2 -222 49 8 0 57 1 2 1 2 -223 -5 54 0 39 1 2 1 2 -224 -26 43 0 99 1 2 1 2 -225 -11 60 0 83 1 2 1 2 -226 40 61 0 54 1 2 1 2 -227 82 35 0 86 1 2 1 2 -228 -92 12 0 2 1 2 1 2 -229 -93 -86 0 14 1 2 1 2 -230 -66 63 0 42 1 2 1 2 -231 -72 -87 0 14 1 2 1 2 -232 -57 -84 0 55 1 2 1 2 -233 23 52 0 2 1 2 1 2 -234 -56 -62 0 18 1 2 1 2 -235 -19 59 0 17 1 2 1 2 -236 63 -14 0 22 1 2 1 2 -237 -13 38 0 28 1 2 1 2 -238 -19 87 0 3 1 2 1 2 -239 44 -84 0 96 1 2 1 2 -240 98 -17 0 53 1 2 1 2 -241 -16 62 0 15 1 2 1 2 -242 3 66 0 36 1 2 1 2 -243 26 22 0 98 1 2 1 2 -244 -38 -81 0 78 1 2 1 2 -245 70 -80 0 92 1 2 1 2 -246 17 -35 0 65 1 2 1 2 -247 96 -83 0 64 1 2 1 2 -248 -77 80 0 43 1 2 1 2 -249 -14 44 0 50 1 2 1 2 -250 -33 33 0 0 0 0 -251 33 -33 0 0 0 0 +2 14 249 2 +310 500 +310 500 + 1 -99 -97 0 6 1 2 1 2 + 2 -59 50 0 72 1 2 1 2 + 3 0 14 0 93 1 2 1 2 + 4 -17 -66 0 28 1 2 1 2 + 5 -69 -19 0 5 1 2 1 2 + 6 31 12 0 43 1 2 1 2 + 7 5 -41 0 1 1 2 1 2 + 8 -12 10 0 36 1 2 1 2 + 9 -64 70 0 53 1 2 1 2 + 10 -12 85 0 63 1 2 1 2 + 11 -18 64 0 25 1 2 1 2 + 12 -77 -16 0 50 1 2 1 2 + 13 -53 88 0 57 1 2 1 2 + 14 83 -24 0 1 1 2 1 2 + 15 24 41 0 66 1 2 1 2 + 16 17 21 0 37 1 2 1 2 + 17 42 96 0 51 1 2 1 2 + 18 -65 0 0 47 1 2 1 2 + 19 -47 -26 0 88 1 2 1 2 + 20 85 36 0 75 1 2 1 2 + 21 -35 -54 0 48 1 2 1 2 + 22 54 -21 0 40 1 2 1 2 + 23 64 -17 0 8 1 2 1 2 + 24 55 89 0 69 1 2 1 2 + 25 17 -25 0 93 1 2 1 2 + 26 -61 66 0 29 1 2 1 2 + 27 -61 26 0 5 1 2 1 2 + 28 17 -72 0 53 1 2 1 2 + 29 79 38 0 8 1 2 1 2 + 30 -62 -2 0 24 1 2 1 2 + 31 -90 -68 0 53 1 2 1 2 + 32 52 66 0 13 1 2 1 2 + 33 -54 -50 0 47 1 2 1 2 + 34 8 -84 0 57 1 2 1 2 + 35 37 -90 0 9 1 2 1 2 + 36 -83 49 0 74 1 2 1 2 + 37 35 -1 0 83 1 2 1 2 + 38 7 59 0 96 1 2 1 2 + 39 12 48 0 42 1 2 1 2 + 40 57 95 0 80 1 2 1 2 + 41 92 28 0 22 1 2 1 2 + 42 -3 97 0 56 1 2 1 2 + 43 -7 52 0 43 1 2 1 2 + 44 42 -15 0 12 1 2 1 2 + 45 77 -43 0 73 1 2 1 2 + 46 59 -49 0 32 1 2 1 2 + 47 25 91 0 8 1 2 1 2 + 48 69 -19 0 79 1 2 1 2 + 49 -82 -14 0 79 1 2 1 2 + 50 74 -70 0 4 1 2 1 2 + 51 69 59 0 14 1 2 1 2 + 52 29 33 0 17 1 2 1 2 + 53 -97 9 0 19 1 2 1 2 + 54 -58 9 0 44 1 2 1 2 + 55 28 93 0 5 1 2 1 2 + 56 7 73 0 37 1 2 1 2 + 57 -28 73 0 100 1 2 1 2 + 58 -76 55 0 62 1 2 1 2 + 59 41 42 0 90 1 2 1 2 + 60 92 40 0 57 1 2 1 2 + 61 -84 -29 0 44 1 2 1 2 + 62 -12 42 0 37 1 2 1 2 + 63 51 -45 0 80 1 2 1 2 + 64 -37 46 0 60 1 2 1 2 + 65 -97 35 0 95 1 2 1 2 + 66 14 89 0 56 1 2 1 2 + 67 60 58 0 56 1 2 1 2 + 68 -63 -75 0 9 1 2 1 2 + 69 -18 34 0 39 1 2 1 2 + 70 -46 -82 0 15 1 2 1 2 + 71 -86 -79 0 4 1 2 1 2 + 72 -43 -30 0 58 1 2 1 2 + 73 -44 7 0 73 1 2 1 2 + 74 -3 -20 0 5 1 2 1 2 + 75 36 41 0 12 1 2 1 2 + 76 -30 -94 0 3 1 2 1 2 + 77 79 -62 0 8 1 2 1 2 + 78 51 70 0 31 1 2 1 2 + 79 -61 -26 0 48 1 2 1 2 + 80 6 94 0 3 1 2 1 2 + 81 -19 -62 0 52 1 2 1 2 + 82 -20 51 0 99 1 2 1 2 + 83 -81 37 0 29 1 2 1 2 + 84 7 31 0 12 1 2 1 2 + 85 52 12 0 50 1 2 1 2 + 86 83 -91 0 98 1 2 1 2 + 87 -7 -92 0 4 1 2 1 2 + 88 82 -74 0 56 1 2 1 2 + 89 -70 85 0 24 1 2 1 2 + 90 -83 -30 0 33 1 2 1 2 + 91 71 -61 0 45 1 2 1 2 + 92 85 11 0 98 1 2 1 2 + 93 66 -48 0 4 1 2 1 2 + 94 78 -87 0 36 1 2 1 2 + 95 9 -79 0 72 1 2 1 2 + 96 -36 4 0 26 1 2 1 2 + 97 66 39 0 71 1 2 1 2 + 98 92 -17 0 84 1 2 1 2 + 99 -46 -79 0 21 1 2 1 2 +100 -30 -63 0 99 1 2 1 2 +101 -42 63 0 33 1 2 1 2 +102 20 42 0 84 1 2 1 2 +103 15 98 0 74 1 2 1 2 +104 1 -17 0 93 1 2 1 2 +105 64 20 0 25 1 2 1 2 +106 -96 85 0 39 1 2 1 2 +107 93 -29 0 42 1 2 1 2 +108 -40 -84 0 77 1 2 1 2 +109 86 35 0 68 1 2 1 2 +110 91 36 0 50 1 2 1 2 +111 62 -8 0 42 1 2 1 2 +112 -24 4 0 71 1 2 1 2 +113 11 96 0 85 1 2 1 2 +114 -53 62 0 78 1 2 1 2 +115 -28 -71 0 64 1 2 1 2 +116 7 -4 0 5 1 2 1 2 +117 95 -9 0 93 1 2 1 2 +118 -3 17 0 18 1 2 1 2 +119 53 -90 0 38 1 2 1 2 +120 58 -19 0 29 1 2 1 2 +121 -83 84 0 81 1 2 1 2 +122 -1 49 0 4 1 2 1 2 +123 -4 17 0 23 1 2 1 2 +124 -82 -3 0 11 1 2 1 2 +125 -43 47 0 86 1 2 1 2 +126 6 -6 0 2 1 2 1 2 +127 70 99 0 31 1 2 1 2 +128 68 -29 0 54 1 2 1 2 +129 -94 -30 0 87 1 2 1 2 +130 -94 -20 0 17 1 2 1 2 +131 -21 77 0 81 1 2 1 2 +132 64 37 0 72 1 2 1 2 +133 -70 -19 0 10 1 2 1 2 +134 88 65 0 50 1 2 1 2 +135 2 29 0 25 1 2 1 2 +136 33 57 0 71 1 2 1 2 +137 -70 6 0 85 1 2 1 2 +138 -38 -56 0 51 1 2 1 2 +139 -80 -95 0 29 1 2 1 2 +140 -5 -39 0 55 1 2 1 2 +141 8 -22 0 45 1 2 1 2 +142 -61 -76 0 100 1 2 1 2 +143 76 -22 0 38 1 2 1 2 +144 49 -71 0 11 1 2 1 2 +145 -30 -68 0 82 1 2 1 2 +146 1 34 0 50 1 2 1 2 +147 77 79 0 39 1 2 1 2 +148 -58 64 0 6 1 2 1 2 +149 82 -97 0 87 1 2 1 2 +150 -80 55 0 83 1 2 1 2 +151 81 -86 0 22 1 2 1 2 +152 39 -49 0 24 1 2 1 2 +153 -67 72 0 69 1 2 1 2 +154 -25 -89 0 97 1 2 1 2 +155 -44 -95 0 65 1 2 1 2 +156 32 -68 0 97 1 2 1 2 +157 -17 49 0 79 1 2 1 2 +158 93 49 0 79 1 2 1 2 +159 99 81 0 46 1 2 1 2 +160 10 -49 0 52 1 2 1 2 +161 63 -41 0 39 1 2 1 2 +162 38 39 0 94 1 2 1 2 +163 -28 39 0 97 1 2 1 2 +164 -2 -47 0 18 1 2 1 2 +165 38 8 0 3 1 2 1 2 +166 -42 -6 0 23 1 2 1 2 +167 -67 88 0 19 1 2 1 2 +168 19 93 0 40 1 2 1 2 +169 40 27 0 49 1 2 1 2 +170 -61 56 0 96 1 2 1 2 +171 43 33 0 58 1 2 1 2 +172 -18 -39 0 15 1 2 1 2 +173 -69 19 0 21 1 2 1 2 +174 75 -18 0 56 1 2 1 2 +175 31 85 0 67 1 2 1 2 +176 25 58 0 10 1 2 1 2 +177 -16 36 0 36 1 2 1 2 +178 91 15 0 84 1 2 1 2 +179 60 -39 0 59 1 2 1 2 +180 49 -47 0 85 1 2 1 2 +181 42 33 0 60 1 2 1 2 +182 16 -81 0 33 1 2 1 2 +183 -78 53 0 62 1 2 1 2 +184 53 -80 0 70 1 2 1 2 +185 -46 -26 0 79 1 2 1 2 +186 -25 -54 0 98 1 2 1 2 +187 69 -46 0 99 1 2 1 2 +188 0 -78 0 18 1 2 1 2 +189 -84 74 0 55 1 2 1 2 +190 -16 16 0 75 1 2 1 2 +191 -63 -14 0 94 1 2 1 2 +192 51 -77 0 89 1 2 1 2 +193 -39 61 0 13 1 2 1 2 +194 5 97 0 19 1 2 1 2 +195 -55 39 0 19 1 2 1 2 +196 70 -14 0 90 1 2 1 2 +197 0 95 0 35 1 2 1 2 +198 -45 7 0 76 1 2 1 2 +199 38 -24 0 3 1 2 1 2 +200 50 -37 0 11 1 2 1 2 +201 59 71 0 98 1 2 1 2 +202 -73 -96 0 92 1 2 1 2 +203 -29 72 0 1 1 2 1 2 +204 -47 12 0 2 1 2 1 2 +205 -88 -61 0 63 1 2 1 2 +206 -88 36 0 57 1 2 1 2 +207 -46 -3 0 50 1 2 1 2 +208 26 -37 0 19 1 2 1 2 +209 -39 -67 0 24 1 2 1 2 +210 92 27 0 14 1 2 1 2 +211 -80 -31 0 18 1 2 1 2 +212 93 -50 0 77 1 2 1 2 +213 -20 -5 0 28 1 2 1 2 +214 -22 73 0 72 1 2 1 2 +215 -4 -7 0 49 1 2 1 2 +216 54 -48 0 58 1 2 1 2 +217 -70 39 0 84 1 2 1 2 +218 54 -82 0 58 1 2 1 2 +219 29 41 0 41 1 2 1 2 +220 -87 51 0 98 1 2 1 2 +221 -96 -36 0 77 1 2 1 2 +222 49 8 0 57 1 2 1 2 +223 -5 54 0 39 1 2 1 2 +224 -26 43 0 99 1 2 1 2 +225 -11 60 0 83 1 2 1 2 +226 40 61 0 54 1 2 1 2 +227 82 35 0 86 1 2 1 2 +228 -92 12 0 2 1 2 1 2 +229 -93 -86 0 14 1 2 1 2 +230 -66 63 0 42 1 2 1 2 +231 -72 -87 0 14 1 2 1 2 +232 -57 -84 0 55 1 2 1 2 +233 23 52 0 2 1 2 1 2 +234 -56 -62 0 18 1 2 1 2 +235 -19 59 0 17 1 2 1 2 +236 63 -14 0 22 1 2 1 2 +237 -13 38 0 28 1 2 1 2 +238 -19 87 0 3 1 2 1 2 +239 44 -84 0 96 1 2 1 2 +240 98 -17 0 53 1 2 1 2 +241 -16 62 0 15 1 2 1 2 +242 3 66 0 36 1 2 1 2 +243 26 22 0 98 1 2 1 2 +244 -38 -81 0 78 1 2 1 2 +245 70 -80 0 92 1 2 1 2 +246 17 -35 0 65 1 2 1 2 +247 96 -83 0 64 1 2 1 2 +248 -77 80 0 43 1 2 1 2 +249 -14 44 0 50 1 2 1 2 +250 -33 33 0 0 0 0 +251 33 -33 0 0 0 0 diff --git a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch.java b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch.java index df30c0ee..72cd3426 100644 --- a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch.java +++ b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch.java @@ -20,7 +20,6 @@ package com.graphhopper.jsprit.examples; import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder; -import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsViewer; import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder; import com.graphhopper.jsprit.core.algorithm.SearchStrategy; import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; @@ -116,17 +115,18 @@ public class BuildAlgorithmFromScratch { final VehicleRoutingProblem vrp = vrpBuilder.build(); VehicleRoutingAlgorithm vra = createAlgorithm(vrp); - vra.setMaxIterations(100); + vra.setMaxIterations(2000); AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz"); eventsRecorder.setRecordingRange(90, 100); vra.addListener(eventsRecorder); VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); - AlgorithmEventsViewer viewer = new AlgorithmEventsViewer(); - viewer.setRuinDelay(3); - viewer.setRecreationDelay(1); - viewer.display("output/events.dgs.gz"); + +// AlgorithmEventsViewer viewer = new AlgorithmEventsViewer(); +// viewer.setRuinDelay(3); +// viewer.setRecreationDelay(1); +// viewer.display("output/events.dgs.gz"); } @@ -146,10 +146,11 @@ public class BuildAlgorithmFromScratch { //regret insertion InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager); iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET); + iBuilder.setFastRegret(true); RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build(); DefaultScorer scoringFunction = new DefaultScorer(vrp); - scoringFunction.setDepotDistanceParam(0.2); - scoringFunction.setTimeWindowParam(-.2); + scoringFunction.setDepotDistanceParam(0.0); + scoringFunction.setTimeWindowParam(0.0); regret.setScoringFunction(scoringFunction); /* diff --git a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java new file mode 100644 index 00000000..88544ec4 --- /dev/null +++ b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java @@ -0,0 +1,252 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.examples; + + +import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder; +import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer; +import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder; +import com.graphhopper.jsprit.core.algorithm.SearchStrategy; +import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; +import com.graphhopper.jsprit.core.algorithm.acceptor.SchrimpfAcceptance; +import com.graphhopper.jsprit.core.algorithm.box.Jsprit; +import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener; +import com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule; +import com.graphhopper.jsprit.core.algorithm.recreate.*; +import com.graphhopper.jsprit.core.algorithm.ruin.RadialRuinStrategyFactory; +import com.graphhopper.jsprit.core.algorithm.ruin.RandomRuinStrategyFactory; +import com.graphhopper.jsprit.core.algorithm.ruin.RuinStrategy; +import com.graphhopper.jsprit.core.algorithm.ruin.RuinString; +import com.graphhopper.jsprit.core.algorithm.ruin.distance.AvgServiceAndShipmentDistance; +import com.graphhopper.jsprit.core.algorithm.selector.SelectBest; +import com.graphhopper.jsprit.core.algorithm.state.StateManager; +import com.graphhopper.jsprit.core.analysis.SolutionAnalyser; +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; +import com.graphhopper.jsprit.core.problem.cost.TransportDistance; +import com.graphhopper.jsprit.core.problem.job.Job; +import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory; +import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager; +import com.graphhopper.jsprit.core.reporting.SolutionPrinter; +import com.graphhopper.jsprit.core.util.Solutions; +import com.graphhopper.jsprit.instance.reader.CordeauReader; +import com.graphhopper.jsprit.util.Examples; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class BuildAlgorithmFromScratch2 { + + + public static class MyBestStrategy extends AbstractInsertionStrategy { + + private JobInsertionCostsCalculatorLight insertionCalculator; + + + public MyBestStrategy(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) { + super(vrp); + insertionCalculator = JobInsertionCostsCalculatorLightFactory.createStandardCalculator(vrp, fleetManager, stateManager, constraintManager); + } + + @Override + public Collection insertUnassignedJobs(Collection vehicleRoutes, Collection unassignedJobs) { + List badJobs = new ArrayList(); + List unassigned = new ArrayList(unassignedJobs); + Collections.shuffle(unassigned, random); + + for (Job j : unassigned) { + + InsertionData bestInsertionData = InsertionData.createEmptyInsertionData(); + VehicleRoute bestRoute = null; + //look for inserting unassigned job into existing route + for (VehicleRoute r : vehicleRoutes) { + InsertionData insertionData = insertionCalculator.getInsertionData(j, r, bestInsertionData.getInsertionCost()); + if (insertionData instanceof InsertionData.NoInsertionFound) continue; + if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) { + bestInsertionData = insertionData; + bestRoute = r; + } + } + //try whole new route + VehicleRoute empty = VehicleRoute.emptyRoute(); + InsertionData insertionData = insertionCalculator.getInsertionData(j, empty, bestInsertionData.getInsertionCost()); + if (!(insertionData instanceof InsertionData.NoInsertionFound)) { + if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) { + vehicleRoutes.add(empty); + insertJob(j, insertionData, empty); + } + } else { + if (bestRoute != null) insertJob(j, bestInsertionData, bestRoute); + else badJobs.add(j); + } + } + return badJobs; + } + + + } + + + public static void main(String[] args) { + Examples.createOutputFolder(); + + VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); + new CordeauReader(vrpBuilder).read("input/p11"); + final VehicleRoutingProblem vrp = vrpBuilder.build(); + +// VehicleRoutingAlgorithm vra = createAlgorithm(vrp); + VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setProperty(Jsprit.Parameter.FAST_REGRET, "true") + .setProperty(Jsprit.Parameter.THREADS, "4") + .setProperty(Jsprit.Parameter.REGRET_DISTANCE_SCORER, "0.0001") + .setProperty(Jsprit.Strategy.STRING_BEST, "0.2") + .setProperty(Jsprit.Strategy.STRING_REGRET, "0.2") + .buildAlgorithm(); + + vra.setMaxIterations(15000); + AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz"); + eventsRecorder.setRecordingRange(40, 100); +// vra.addListener(eventsRecorder); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); + + new GraphStreamViewer(vrp, solution).display(); +// AlgorithmEventsViewer viewer = new AlgorithmEventsViewer(); +// viewer.setRuinDelay(6); +// viewer.setRecreationDelay(1); +// viewer.display("output/events.dgs.gz"); + + } + + + public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp) { + + VehicleFleetManager fleetManager = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); + StateManager stateManager = new StateManager(vrp); + ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager); + + /* + * insertion strategies + */ + //my custom best insertion + MyBestStrategy best = new MyBestStrategy(vrp, fleetManager, stateManager, constraintManager); + + //regret insertion + InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager); + iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET); + iBuilder.setFastRegret(true); + + RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build(); + DefaultScorer scoringFunction = new DefaultScorer(vrp); + scoringFunction.setDepotDistanceParam(0.00001); + scoringFunction.setTimeWindowParam(0); + regret.setScoringFunction(scoringFunction); + + /* + * ruin strategies + */ + RuinStrategy randomRuin = new RandomRuinStrategyFactory(0.5).createStrategy(vrp); + RuinStrategy radialRuin = new RadialRuinStrategyFactory(0.3, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())).createStrategy(vrp); + + /* + * objective function + */ + + RuinStrategy stringRuin = new RuinString(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())); + + SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp); + + final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, 0.15); + IterationStartsListener schrimpfThreshold = new IterationStartsListener() { + @Override + public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { + if (i == 1) { + double initialThreshold = Solutions.bestOf(solutions).getCost() * 0.03; + schrimpfAcceptance.setInitialThreshold(initialThreshold); + } + } + }; + + SearchStrategy firstStrategy = new SearchStrategy("firstStrategy", new SelectBest(), schrimpfAcceptance, objectiveFunction); + firstStrategy.addModule(new RuinAndRecreateModule("randRuinRegretIns", regret, stringRuin)); + +// SearchStrategy secondStrategy = new SearchStrategy("secondStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction); +// secondStrategy.addModule(new RuinAndRecreateModule("radRuinRegretIns", regret, radialRuin)); + +// SearchStrategy thirdStrategy = new SearchStrategy("thirdStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction); +// secondStrategy.addModule(new RuinAndRecreateModule("radRuinBestIns", regret, radialRuin)); + + PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fleetManager, stateManager, constraintManager); + final VehicleRoutingAlgorithm vra = prettyAlgorithmBuilder + .withStrategy(firstStrategy, 0.5) +// .withStrategy(secondStrategy, 0.5).withStrategy(thirdStrategy, 0.2) + .addCoreStateAndConstraintStuff() + .constructInitialSolutionWith(regret, objectiveFunction) + .build(); + + //if you want to switch on/off strategies or adapt their weight within the search, you can do the following + //e.g. from iteration 50 on, switch off first strategy + //switch on again at iteration 90 with slightly higher weight +// IterationStartsListener strategyAdaptor = new IterationStartsListener() { +// @Override +// public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { +// if (i == 50) { +// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.0); +// System.out.println("switched off firstStrategy"); +// } +// if (i == 90) { +// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.7); +// System.out.println("switched on firstStrategy again with higher weight"); +// } +// } +// }; +// vra.addListener(strategyAdaptor); + vra.addListener(schrimpfThreshold); + vra.addListener(schrimpfAcceptance); + return vra; + + } + + private static SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp) { + return new SolutionCostCalculator() { + + + @Override + public double getCosts(VehicleRoutingProblemSolution solution) { + SolutionAnalyser analyser = new SolutionAnalyser(vrp, solution, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportCost(from, to, 0., null, null); + } + }); + return analyser.getVariableTransportCosts() + solution.getUnassignedJobs().size() * 500.; + } + + }; + } + + +} From 7d2881f4c17347409dc6745aa07113226e4251fb Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 30 Jan 2017 20:02:34 +0100 Subject: [PATCH 042/106] allow more priority levels - up to 10 --- .../com/graphhopper/jsprit/core/problem/job/Service.java | 7 ++++--- .../com/graphhopper/jsprit/core/problem/job/Shipment.java | 5 +++-- .../graphhopper/jsprit/core/problem/job/ServiceTest.java | 7 +++++++ .../graphhopper/jsprit/core/problem/job/ShipmentTest.java | 8 ++++++++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java index 38a496b6..11be0994 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java @@ -212,15 +212,16 @@ public class Service extends AbstractJob { } /** - * Set priority to service. Only 1 = high priority, 2 = medium and 3 = low are allowed. + * Set priority to service. Only 1 (very high) to 10 (very low) are allowed. *

- * Default is 2 = medium. + * Default is 2. * * @param priority * @return builder */ public Builder setPriority(int priority) { - if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed"); + if (priority < 1 || priority > 10) + throw new IllegalArgumentException("incorrect priority. only priority values from 1 to 10 are allowed where 1 = high and 10 is low"); this.priority = priority; return this; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java index 3275e901..6b8bde5d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java @@ -269,7 +269,7 @@ public class Shipment extends AbstractJob { } /** - * Set priority to shipment. Only 1 = high priority, 2 = medium and 3 = low are allowed. + * Set priority to shipment. Only 1 (high) to 10 (low) are allowed. *

* Default is 2 = medium. * @@ -277,7 +277,8 @@ public class Shipment extends AbstractJob { * @return builder */ public Builder setPriority(int priority) { - if(priority < 1 || priority > 3) throw new IllegalArgumentException("incorrect priority. only 1 = high, 2 = medium and 3 = low is allowed"); + if (priority < 1 || priority > 10) + throw new IllegalArgumentException("incorrect priority. only 1 (very high) to 10 (very low) are allowed"); this.priority = priority; return this; } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java index bec514e2..f1efce37 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java @@ -250,6 +250,13 @@ public class ServiceTest { Assert.assertEquals(3, s.getPriority()); } + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly3() { + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setPriority(10).build(); + Assert.assertEquals(10, s.getPriority()); + } + @Test public void whenNotSettingPriorities_defaultShouldBe2(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java index 6c463d04..cbfa1f26 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java @@ -401,6 +401,14 @@ public class ShipmentTest { Assert.assertEquals(3, s.getPriority()); } + @Test + public void whenSettingPriorities_itShouldBeSetCorrectly3() { + Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(10).build(); + Assert.assertEquals(10, s.getPriority()); + } + @Test public void whenNotSettingPriorities_defaultShouldBe2(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) From d7b4122e10c7df4b7d3aabce0be7a721f187bcc5 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 30 Jan 2017 20:05:49 +0100 Subject: [PATCH 043/106] account for more prio levels in scorer and obj function --- .../com/graphhopper/jsprit/core/algorithm/box/Jsprit.java | 2 +- .../graphhopper/jsprit/core/algorithm/recreate/Scorer.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 3ad56495..472bb792 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -720,7 +720,7 @@ public class Jsprit { } } for(Job j : solution.getUnassignedJobs()){ - costs += maxCosts * 2 * (4 - j.getPriority()); + costs += maxCosts * 2 * (11 - j.getPriority()); } return costs; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java index 6aabb134..a6607d26 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/Scorer.java @@ -33,9 +33,9 @@ class Scorer { if (secondBest == null) { //either there is only one vehicle or there are more vehicles, but they cannot load unassignedJob //if only one vehicle, I want the job to be inserted with min iCosts //if there are more vehicles, I want this job to be prioritized since there are no alternatives - score = (4 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); + score = (11 - unassignedJob.getPriority()) * (Integer.MAX_VALUE - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); } else { - score = (4 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); + score = (11 - unassignedJob.getPriority()) * (secondBest.getInsertionCost() - best.getInsertionCost()) + scoringFunction.score(best, unassignedJob); } return score; } From a2787ca3908e250c628dc2ee4270892ce97aea0a Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 21:28:44 +0100 Subject: [PATCH 044/106] add google guava - related to #180 --- jsprit-core/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index f3d79fc0..3ae778a0 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -42,6 +42,12 @@ ${logger.version} + + com.google.guava + guava + 21.0 + + From ba6dbfae456edd55a34b0262b49e5db91089944f Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 21:29:22 +0100 Subject: [PATCH 045/106] add unassigned job listener - related to #180 --- .../recreate/listener/InsertionListeners.java | 9 ++++++ .../listener/JobUnassignedListener.java | 32 +++++++++++++++++++ .../problem/constraint/ConstraintManager.java | 30 ++++++++++++++--- .../ShipmentInsertionCalculatorTest.java | 2 +- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java index 37ccd7bb..f0c5e9a8 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/InsertionListeners.java @@ -24,6 +24,7 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import java.util.ArrayList; import java.util.Collection; +import java.util.List; public class InsertionListeners { @@ -74,6 +75,14 @@ public class InsertionListeners { } } + public void informJobUnassignedListeners(Job unassigned, List reasons) { + for (InsertionListener l : listeners) { + if (l instanceof JobUnassignedListener) { + ((JobUnassignedListener) l).informJobUnassigned(unassigned, reasons); + } + } + } + public void addListener(InsertionListener insertionListener) { listeners.add(insertionListener); } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java new file mode 100644 index 00000000..55a2921d --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/listener/JobUnassignedListener.java @@ -0,0 +1,32 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.algorithm.recreate.listener; + +import com.graphhopper.jsprit.core.problem.job.Job; + +import java.util.Collection; + +/** + * Created by schroeder on 06/02/17. + */ +public interface JobUnassignedListener extends InsertionListener { + + void informJobUnassigned(Job unassigned, Collection failedConstraintNames); + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java index dcd19cd6..1275f825 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/constraint/ConstraintManager.java @@ -37,6 +37,7 @@ import java.util.List; */ public class ConstraintManager implements HardActivityConstraint, HardRouteConstraint, SoftActivityConstraint, SoftRouteConstraint { + public static enum Priority { CRITICAL, HIGH, LOW } @@ -45,7 +46,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst private HardActivityLevelConstraintManager actLevelConstraintManager = new HardActivityLevelConstraintManager(); - private HardRouteLevelConstraintManager routeLevelConstraintManager = new HardRouteLevelConstraintManager(); + private HardRouteLevelConstraintManager hardRouteConstraintManager = new HardRouteLevelConstraintManager(); private SoftActivityConstraintManager softActivityConstraintManager = new SoftActivityConstraintManager(); @@ -76,6 +77,25 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst resolveConstraints(constraints); } + public Collection getHardRouteConstraints() { + return hardRouteConstraintManager.getConstraints(); + } + + public Collection getCriticalHardActivityConstraints() { + return actLevelConstraintManager.getCriticalConstraints(); + } + + public Collection getHighPrioHardActivityConstraints() { + return actLevelConstraintManager.getHighPrioConstraints(); + } + + public Collection getLowPrioHardActivityConstraints() { + return actLevelConstraintManager.getLowPrioConstraints(); + } +// public Collection getHardActivityConstraints() { +// return actLevelConstraintManager.g; +// } + public DependencyType[] getDependencyTypes() { return dependencyTypes; } @@ -103,7 +123,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst constraintTypeKnown = true; } if (c instanceof HardRouteConstraint) { - routeLevelConstraintManager.addConstraint((HardRouteConstraint) c); + hardRouteConstraintManager.addConstraint((HardRouteConstraint) c); constraintTypeKnown = true; } if (c instanceof SoftRouteConstraint) { @@ -152,7 +172,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst } public void addConstraint(HardRouteConstraint routeLevelConstraint) { - routeLevelConstraintManager.addConstraint(routeLevelConstraint); + hardRouteConstraintManager.addConstraint(routeLevelConstraint); } public void addConstraint(SoftActivityConstraint softActivityConstraint) { @@ -165,7 +185,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst @Override public boolean fulfilled(JobInsertionContext insertionContext) { - return routeLevelConstraintManager.fulfilled(insertionContext); + return hardRouteConstraintManager.fulfilled(insertionContext); } @Override @@ -176,7 +196,7 @@ public class ConstraintManager implements HardActivityConstraint, HardRouteConst public Collection getConstraints() { List constraints = new ArrayList(); constraints.addAll(actLevelConstraintManager.getAllConstraints()); - constraints.addAll(routeLevelConstraintManager.getConstraints()); + constraints.addAll(hardRouteConstraintManager.getConstraints()); constraints.addAll(softActivityConstraintManager.getConstraints()); constraints.addAll(softRouteConstraintManager.getConstraints()); return Collections.unmodifiableCollection(constraints); diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java index 70dd2ee3..9713744a 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculatorTest.java @@ -178,7 +178,7 @@ public class ShipmentInsertionCalculatorTest { insertionCalculator.setJobActivityFactory(activityFactory); InsertionData iData = insertionCalculator.getInsertionData(route, shipment2, vehicle, 0.0, null, Double.MAX_VALUE); - assertEquals(InsertionData.createEmptyInsertionData(), iData); + assertTrue(iData instanceof InsertionData.NoInsertionFound); } From 8da37cf4b382efd6041a825d6bdd0640a5543398 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 21:30:16 +0100 Subject: [PATCH 046/106] memorize failed constraint names - related to #180 --- .../recreate/AbstractInsertionCalculator.java | 95 +++++++++++++++++++ .../recreate/AbstractInsertionStrategy.java | 5 + .../algorithm/recreate/BestInsertion.java | 11 ++- .../recreate/BestInsertionConcurrent.java | 14 ++- .../algorithm/recreate/InsertionData.java | 11 +++ .../recreate/InsertionDataUpdater.java | 14 ++- .../algorithm/recreate/RegretInsertion.java | 30 +++--- .../recreate/RegretInsertionConcurrent.java | 18 ++-- .../RegretInsertionConcurrentFast.java | 14 +-- .../recreate/RegretInsertionFast.java | 16 ++-- .../core/algorithm/recreate/ScoredJob.java | 12 ++- .../recreate/ServiceInsertionCalculator.java | 32 ++++--- .../recreate/ShipmentInsertionCalculator.java | 30 +++--- ...leTypeDependentJobInsertionCalculator.java | 3 +- 14 files changed, 237 insertions(+), 68 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java new file mode 100644 index 00000000..6f3d54a4 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionCalculator.java @@ -0,0 +1,95 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.algorithm.recreate; + +import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; +import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint; +import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus; +import com.graphhopper.jsprit.core.problem.constraint.HardRouteConstraint; +import com.graphhopper.jsprit.core.problem.misc.JobInsertionContext; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Created by schroeder on 06/02/17. + */ +abstract class AbstractInsertionCalculator implements JobInsertionCostsCalculator { + + InsertionData checkRouteContraints(JobInsertionContext insertionContext, ConstraintManager constraintManager) { + for (HardRouteConstraint hardRouteConstraint : constraintManager.getHardRouteConstraints()) { + if (!hardRouteConstraint.fulfilled(insertionContext)) { + InsertionData emptyInsertionData = new InsertionData.NoInsertionFound(); + emptyInsertionData.addFailedConstrainName(hardRouteConstraint.getClass().getSimpleName()); + return emptyInsertionData; + } + } + return null; + } + + ConstraintsStatus fulfilled(JobInsertionContext iFacts, TourActivity prevAct, TourActivity newAct, TourActivity nextAct, double prevActDepTime, Collection failedActivityConstraints, ConstraintManager constraintManager) { + ConstraintsStatus notFulfilled = null; + List failed = new ArrayList<>(); + for (HardActivityConstraint c : constraintManager.getCriticalHardActivityConstraints()) { + ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); + if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) { + failedActivityConstraints.add(c.getClass().getSimpleName()); + return status; + } else { + if (status.equals(ConstraintsStatus.NOT_FULFILLED)) { + failed.add(c.getClass().getSimpleName()); + notFulfilled = status; + } + } + } + if (notFulfilled != null) { + failedActivityConstraints.addAll(failed); + return notFulfilled; + } + + for (HardActivityConstraint c : constraintManager.getHighPrioHardActivityConstraints()) { + ConstraintsStatus status = c.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); + if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK)) { + failedActivityConstraints.add(c.getClass().getSimpleName()); + return status; + } else { + if (status.equals(ConstraintsStatus.NOT_FULFILLED)) { + failed.add(c.getClass().getSimpleName()); + notFulfilled = status; + } + } + } + if (notFulfilled != null) { + failedActivityConstraints.addAll(failed); + return notFulfilled; + } + + for (HardActivityConstraint constraint : constraintManager.getLowPrioHardActivityConstraints()) { + ConstraintsStatus status = constraint.fulfilled(iFacts, prevAct, newAct, nextAct, prevActDepTime); + if (status.equals(ConstraintsStatus.NOT_FULFILLED_BREAK) || status.equals(ConstraintsStatus.NOT_FULFILLED)) { + failedActivityConstraints.add(constraint.getClass().getSimpleName()); + return status; + } + } + return ConstraintsStatus.FULFILLED; + } + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java index 7d794a6d..5f5973f5 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AbstractInsertionStrategy.java @@ -32,6 +32,7 @@ import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Random; public abstract class AbstractInsertionStrategy implements InsertionStrategy { @@ -92,6 +93,10 @@ public abstract class AbstractInsertionStrategy implements InsertionStrategy { return badJobs; } + public void markUnassigned(Job unassigned, List reasons) { + insertionsListeners.informJobUnassignedListeners(unassigned, reasons); + } + public abstract Collection insertUnassignedJobs(Collection vehicleRoutes, Collection unassignedJobs); @Override diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java index a78205ae..329a05ff 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java @@ -66,10 +66,12 @@ public final class BestInsertion extends AbstractInsertionStrategy { sometimesSortPriorities(unassignedJobList); for (Job unassignedJob : unassignedJobList) { Insertion bestInsertion = null; + InsertionData empty = new InsertionData.NoInsertionFound(); double bestInsertionCost = Double.MAX_VALUE; for (VehicleRoute vehicleRoute : vehicleRoutes) { InsertionData iData = bestInsertionCostCalculator.getInsertionData(vehicleRoute, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, bestInsertionCost); if (iData instanceof InsertionData.NoInsertionFound) { + empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames()); continue; } if (iData.getInsertionCost() < bestInsertionCost + noiseMaker.makeNoise()) { @@ -84,14 +86,19 @@ public final class BestInsertion extends AbstractInsertionStrategy { bestInsertion = new Insertion(newRoute, newIData); vehicleRoutes.add(newRoute); } + } else { + empty.getFailedConstraintNames().addAll(newIData.getFailedConstraintNames()); + } + if (bestInsertion == null) { + badJobs.add(unassignedJob); + markUnassigned(unassignedJob, empty.getFailedConstraintNames()); } - if (bestInsertion == null) badJobs.add(unassignedJob); else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); -// nextInsertion(); } return badJobs; } + private void sometimesSortPriorities(List unassignedJobList) { if(random.nextDouble() < 0.5){ Collections.sort(unassignedJobList, new Comparator() { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java index 52d913df..2b014df0 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java @@ -101,6 +101,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { Collections.shuffle(unassignedJobList, random); sometimesSortPriorities(unassignedJobList); List batches = distributeRoutes(vehicleRoutes, nuOfBatches); + List failedConstraintNames = new ArrayList<>(); for (final Job unassignedJob : unassignedJobList) { Insertion bestInsertion = null; double bestInsertionCost = Double.MAX_VALUE; @@ -118,7 +119,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { for (int i = 0; i < batches.size(); i++) { Future futureIData = completionService.take(); Insertion insertion = futureIData.get(); - if (insertion == null) continue; + if (insertion.insertionData instanceof NoInsertionFound) { + failedConstraintNames.addAll(insertion.getInsertionData().getFailedConstraintNames()); + continue; + } if (insertion.getInsertionData().getInsertionCost() < bestInsertionCost) { bestInsertion = insertion; bestInsertionCost = insertion.getInsertionData().getInsertionCost(); @@ -136,7 +140,10 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { vehicleRoutes.add(newRoute); batches.get(random.nextInt(batches.size())).routes.add(newRoute); } - if (bestInsertion == null) badJobs.add(unassignedJob); + if (bestInsertion == null) { + badJobs.add(unassignedJob); + markUnassigned(unassignedJob, failedConstraintNames); + } else insertJob(unassignedJob, bestInsertion.getInsertionData(), bestInsertion.getRoute()); } return badJobs; @@ -155,10 +162,12 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { private Insertion getBestInsertion(Batch batch, Job unassignedJob) { Insertion bestInsertion = null; + InsertionData empty = new InsertionData.NoInsertionFound(); 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) { + empty.getFailedConstraintNames().addAll(iData.getFailedConstraintNames()); continue; } if (iData.getInsertionCost() < bestInsertionCost) { @@ -166,6 +175,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { bestInsertionCost = iData.getInsertionCost(); } } + if (bestInsertion == null) return new Insertion(null, empty); return bestInsertion; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java index d5b5ef8d..fd78b3e9 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionData.java @@ -31,6 +31,7 @@ import java.util.List; */ public class InsertionData { + public static class NoInsertionFound extends InsertionData { public NoInsertionFound() { @@ -75,6 +76,8 @@ public class InsertionData { return events; } + private List reasons = new ArrayList<>(); + /** * @return the additionalTime */ @@ -82,6 +85,14 @@ public class InsertionData { return additionalTime; } + public void addFailedConstrainName(String name) { + reasons.add(name); + } + + public List getFailedConstraintNames() { + return reasons; + } + /** * @param additionalTime the additionalTime to set */ diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java index ced87182..8d019e2c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/InsertionDataUpdater.java @@ -33,7 +33,7 @@ class InsertionDataUpdater { static boolean update(boolean addAllAvailable, Set initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, TreeSet insertionDataSet, int updateRound, Job unassignedJob, Collection routes) { for(VehicleRoute route : routes) { - Collection relevantVehicles = new ArrayList(); + Collection relevantVehicles = new ArrayList<>(); if (!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) { relevantVehicles.add(route.getVehicle()); if(addAllAvailable && !initialVehicleIds.contains(route.getVehicle().getId())){ @@ -71,7 +71,7 @@ class InsertionDataUpdater { }; } - static ScoredJob getBest(boolean switchAllowed, Set initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet[] priorityQueues, Map updates, List unassignedJobList, List badJobs) { + static ScoredJob getBest(boolean switchAllowed, Set initialVehicleIds, VehicleFleetManager fleetManager, JobInsertionCostsCalculator insertionCostsCalculator, ScoringFunction scoringFunction, TreeSet[] priorityQueues, Map updates, List unassignedJobList, List badJobs) { ScoredJob bestScoredJob = null; for(Job j : unassignedJobList){ VehicleRoute bestRoute = null; @@ -79,6 +79,7 @@ class InsertionDataUpdater { InsertionData secondBest = null; TreeSet priorityQueue = priorityQueues[j.getIndex()]; Iterator iterator = priorityQueue.iterator(); + List failedConstraintNames = new ArrayList<>(); while(iterator.hasNext()){ VersionedInsertionData versionedIData = iterator.next(); if(bestRoute != null){ @@ -86,7 +87,10 @@ class InsertionDataUpdater { continue; } } - if(versionedIData.getiData() instanceof InsertionData.NoInsertionFound) continue; + if (versionedIData.getiData() instanceof InsertionData.NoInsertionFound) { + failedConstraintNames.addAll(versionedIData.getiData().getFailedConstraintNames()); + continue; + } if(!(versionedIData.getRoute().getVehicle() instanceof VehicleImpl.NoVehicle)) { if (versionedIData.getiData().getSelectedVehicle() != versionedIData.getRoute().getVehicle()) { if (!switchAllowed) continue; @@ -136,9 +140,9 @@ class InsertionDataUpdater { } else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) { secondBest = iData; } - } + } else failedConstraintNames.addAll(iData.getFailedConstraintNames()); if (best == null) { - badJobs.add(j); + badJobs.add(new ScoredJob.BadJob(j, failedConstraintNames)); continue; } double score = score(j, best, secondBest, scoringFunction); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java index 6e405dec..30a7a98a 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertion.java @@ -105,10 +105,10 @@ public class RegretInsertion extends AbstractInsertionStrategy { } } - List jobs = new ArrayList(unassignedJobs); + List jobs = new ArrayList<>(unassignedJobs); while (!jobs.isEmpty()) { - List unassignedJobList = new ArrayList(jobs); - List badJobList = new ArrayList(); + List unassignedJobList = new ArrayList<>(jobs); + List badJobList = new ArrayList<>(); ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList); if (bestScoredJob != null) { if (bestScoredJob.isNewRoute()) { @@ -117,9 +117,11 @@ public class RegretInsertion extends AbstractInsertionStrategy { insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); jobs.remove(bestScoredJob.getJob()); } - for (Job bad : badJobList) { - jobs.remove(bad); - badJobs.add(bad); + for (ScoredJob bad : badJobList) { + Job unassigned = bad.getJob(); + jobs.remove(unassigned); + badJobs.add(unassigned); + markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames()); } } return badJobs; @@ -132,12 +134,12 @@ public class RegretInsertion extends AbstractInsertionStrategy { return null; } - private ScoredJob nextJob(Collection routes, Collection unassignedJobList, List badJobs) { + private ScoredJob nextJob(Collection routes, Collection unassignedJobList, List badJobs) { ScoredJob bestScoredJob = null; for (Job unassignedJob : unassignedJobList) { ScoredJob scoredJob = getScoredJob(routes, unassignedJob, insertionCostsCalculator, scoringFunction); if (scoredJob instanceof ScoredJob.BadJob) { - badJobs.add(unassignedJob); + badJobs.add(scoredJob); continue; } if (bestScoredJob == null) bestScoredJob = scoredJob; @@ -158,14 +160,17 @@ public class RegretInsertion extends AbstractInsertionStrategy { InsertionData best = null; InsertionData secondBest = null; VehicleRoute bestRoute = null; - + List failedConstraintNames = new ArrayList<>(); double benchmark = Double.MAX_VALUE; for (VehicleRoute route : routes) { if (secondBest != null) { benchmark = secondBest.getInsertionCost(); } InsertionData iData = insertionCostsCalculator.getInsertionData(route, unassignedJob, NO_NEW_VEHICLE_YET, NO_NEW_DEPARTURE_TIME_YET, NO_NEW_DRIVER_YET, benchmark); - if (iData instanceof InsertionData.NoInsertionFound) continue; + if (iData instanceof InsertionData.NoInsertionFound) { + failedConstraintNames.addAll(iData.getFailedConstraintNames()); + continue; + } if (best == null) { best = iData; bestRoute = route; @@ -191,9 +196,10 @@ public class RegretInsertion extends AbstractInsertionStrategy { } else if (secondBest == null || (iData.getInsertionCost() < secondBest.getInsertionCost())) { secondBest = iData; } - } + } else failedConstraintNames.addAll(iData.getFailedConstraintNames()); if (best == null) { - return new ScoredJob.BadJob(unassignedJob); + ScoredJob.BadJob badJob = new ScoredJob.BadJob(unassignedJob, failedConstraintNames); + return badJob; } double score = score(unassignedJob, best, secondBest, scoringFunction); ScoredJob scoredJob; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java index fe2146ba..b71ac5ab 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrent.java @@ -109,10 +109,10 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy { } } - List jobs = new ArrayList(unassignedJobs); + List jobs = new ArrayList<>(unassignedJobs); while (!jobs.isEmpty()) { - List unassignedJobList = new ArrayList(jobs); - List badJobList = new ArrayList(); + List unassignedJobList = new ArrayList<>(jobs); + List badJobList = new ArrayList<>(); ScoredJob bestScoredJob = nextJob(routes, unassignedJobList, badJobList); if (bestScoredJob != null) { if (bestScoredJob.isNewRoute()) { @@ -121,15 +121,17 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy { insertJob(bestScoredJob.getJob(), bestScoredJob.getInsertionData(), bestScoredJob.getRoute()); jobs.remove(bestScoredJob.getJob()); } - for (Job j : badJobList) { - jobs.remove(j); - badJobs.add(j); + for (ScoredJob bad : badJobList) { + Job unassigned = bad.getJob(); + jobs.remove(unassigned); + badJobs.add(unassigned); + markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames()); } } return badJobs; } - private ScoredJob nextJob(final Collection routes, List unassignedJobList, List badJobList) { + private ScoredJob nextJob(final Collection routes, List unassignedJobList, List badJobList) { ScoredJob bestScoredJob = null; for (final Job unassignedJob : unassignedJobList) { @@ -148,7 +150,7 @@ public class RegretInsertionConcurrent extends AbstractInsertionStrategy { Future fsj = completionService.take(); ScoredJob sJob = fsj.get(); if (sJob instanceof ScoredJob.BadJob) { - badJobList.add(sJob.getJob()); + badJobList.add(sJob); continue; } if (bestScoredJob == null) { diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java index 187145f6..be4f5d11 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionConcurrentFast.java @@ -143,8 +143,8 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { int updateRound = 0; Map updates = new HashMap(); while (!jobs.isEmpty()) { - List unassignedJobList = new ArrayList(jobs); - List badJobList = new ArrayList(); + List unassignedJobList = new ArrayList<>(jobs); + List badJobList = new ArrayList<>(); if(!firstRun && lastModified == null) throw new IllegalStateException("ho. this must not be."); updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound,firstRun,lastModified,updates); if(firstRun) firstRun = false; @@ -159,9 +159,11 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { lastModified = bestScoredJob.getRoute(); } else lastModified = null; - for (Job bad : badJobList) { - jobs.remove(bad); - badJobs.add(bad); + for (ScoredJob bad : badJobList) { + Job unassigned = bad.getJob(); + jobs.remove(unassigned); + badJobs.add(unassigned); + markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames()); } } return badJobs; @@ -172,7 +174,7 @@ public class RegretInsertionConcurrentFast extends AbstractInsertionStrategy { boolean updatedAllRoutes = false; for (final Job unassignedJob : unassignedJobList) { if(priorityQueues[unassignedJob.getIndex()] == null){ - priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator()); + priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator()); } if(firstRun) { updatedAllRoutes = true; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java index 4369dd01..d805e55d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/RegretInsertionFast.java @@ -131,10 +131,10 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { VehicleRoute lastModified = null; boolean firstRun = true; int updateRound = 0; - Map updates = new HashMap(); + Map updates = new HashMap<>(); while (!jobs.isEmpty()) { - List unassignedJobList = new ArrayList(jobs); - List badJobList = new ArrayList(); + List unassignedJobList = new ArrayList<>(jobs); + List badJobList = new ArrayList<>(); if(!firstRun && lastModified == null) throw new IllegalStateException("last modified route is null. this should not be."); if(firstRun){ updateInsertionData(priorityQueues, routes, unassignedJobList, updateRound, firstRun, lastModified, updates); @@ -156,9 +156,11 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { lastModified = bestScoredJob.getRoute(); } else lastModified = null; - for (Job bad : badJobList) { - jobs.remove(bad); - badJobs.add(bad); + for (ScoredJob bad : badJobList) { + Job unassigned = bad.getJob(); + jobs.remove(unassigned); + badJobs.add(unassigned); + markUnassigned(unassigned, bad.getInsertionData().getFailedConstraintNames()); } } return badJobs; @@ -167,7 +169,7 @@ public class RegretInsertionFast extends AbstractInsertionStrategy { private void updateInsertionData(TreeSet[] priorityQueues, Collection routes, List unassignedJobList, int updateRound, boolean firstRun, VehicleRoute lastModified, Map updates) { for (Job unassignedJob : unassignedJobList) { if(priorityQueues[unassignedJob.getIndex()] == null){ - priorityQueues[unassignedJob.getIndex()] = new TreeSet(InsertionDataUpdater.getComparator()); + priorityQueues[unassignedJob.getIndex()] = new TreeSet<>(InsertionDataUpdater.getComparator()); } if(firstRun) { InsertionDataUpdater.update(switchAllowed, initialVehicleIds, fleetManager, insertionCostsCalculator, priorityQueues[unassignedJob.getIndex()], updateRound, unassignedJob, routes); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java index 48582800..f0f8950f 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoredJob.java @@ -21,6 +21,8 @@ package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.problem.job.Job; import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; +import java.util.List; + /** * Created by schroeder on 15/10/15. */ @@ -28,8 +30,14 @@ class ScoredJob { static class BadJob extends ScoredJob { - BadJob(Job job) { - super(job, 0., null, null, false); + BadJob(Job job, List failedConstraintNames) { + super(job, 0., getEmptyInsertion(failedConstraintNames), null, false); + } + + private static InsertionData getEmptyInsertion(List failedConstraintNames) { + InsertionData empty = new InsertionData.NoInsertionFound(); + empty.getFailedConstraintNames().addAll(failedConstraintNames); + return empty; } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java index 977ba6ab..9f91ff9b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ServiceInsertionCalculator.java @@ -18,8 +18,10 @@ package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.problem.JobActivityFactory; -import com.graphhopper.jsprit.core.problem.constraint.*; +import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus; +import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint; +import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts; import com.graphhopper.jsprit.core.problem.driver.Driver; @@ -36,6 +38,8 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; /** @@ -43,13 +47,13 @@ import java.util.Iterator; * * @author schroeder */ -final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { +final class ServiceInsertionCalculator extends AbstractInsertionCalculator { private static final Logger logger = LoggerFactory.getLogger(ServiceInsertionCalculator.class); - private HardRouteConstraint hardRouteLevelConstraint; +// private HardRouteConstraint hardRouteLevelConstraint; - private HardActivityConstraint hardActivityLevelConstraint; +// private HardActivityConstraint hardActivityLevelConstraint; private SoftRouteConstraint softRouteConstraint; @@ -65,12 +69,13 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { private AdditionalAccessEgressCalculator additionalAccessEgressCalculator; + private ConstraintManager constraintManager; + public ServiceInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator additionalTransportCostsCalculator, ConstraintManager constraintManager) { super(); this.transportCosts = routingCosts; this.activityCosts = activityCosts; - hardRouteLevelConstraint = constraintManager; - hardActivityLevelConstraint = constraintManager; + this.constraintManager = constraintManager; softActivityConstraint = constraintManager; softRouteConstraint = constraintManager; this.additionalTransportCostsCalculator = additionalTransportCostsCalculator; @@ -103,9 +108,10 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { /* check hard constraints at route level */ - if (!hardRouteLevelConstraint.fulfilled(insertionContext)) { - return InsertionData.createEmptyInsertionData(); - } + InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager); + if (noInsertion != null) return noInsertion; + + Collection failedActivityConstraints = new ArrayList<>(); /* check soft constraints at route level @@ -142,7 +148,7 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { ActivityContext activityContext = new ActivityContext(); activityContext.setInsertionIndex(actIndex); insertionContext.setActivityContext(activityContext); - ConstraintsStatus status = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); + ConstraintsStatus status = fulfilled(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime, failedActivityConstraints, constraintManager); if (status.equals(ConstraintsStatus.FULFILLED)) { double additionalICostsAtActLevel = softActivityConstraint.getCosts(insertionContext, prevAct, deliveryAct2Insert, nextAct, prevActStartTime); double additionalTransportationCosts = additionalTransportCostsCalculator.getCosts(insertionContext, prevAct, nextAct, deliveryAct2Insert, prevActStartTime); @@ -163,7 +169,9 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { actIndex++; } if(insertionIndex == InsertionData.NO_INDEX) { - return InsertionData.createEmptyInsertionData(); + InsertionData emptyInsertionData = new InsertionData.NoInsertionFound(); + emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints); + return emptyInsertionData; } InsertionData insertionData = new InsertionData(bestCost, InsertionData.NO_INDEX, insertionIndex, newVehicle, newDriver); deliveryAct2Insert.setTheoreticalEarliestOperationStartTime(bestTimeWindow.getStart()); @@ -173,4 +181,6 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator { insertionData.setVehicleDepartureTime(newVehicleDepartureTime); return insertionData; } + + } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java index 87c29c0e..e8698483 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ShipmentInsertionCalculator.java @@ -18,8 +18,10 @@ package com.graphhopper.jsprit.core.algorithm.recreate; import com.graphhopper.jsprit.core.problem.JobActivityFactory; -import com.graphhopper.jsprit.core.problem.constraint.*; +import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; import com.graphhopper.jsprit.core.problem.constraint.HardActivityConstraint.ConstraintsStatus; +import com.graphhopper.jsprit.core.problem.constraint.SoftActivityConstraint; +import com.graphhopper.jsprit.core.problem.constraint.SoftRouteConstraint; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingActivityCosts; import com.graphhopper.jsprit.core.problem.cost.VehicleRoutingTransportCosts; import com.graphhopper.jsprit.core.problem.driver.Driver; @@ -36,16 +38,19 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.List; -final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { +final class ShipmentInsertionCalculator extends AbstractInsertionCalculator { private static final Logger logger = LoggerFactory.getLogger(ShipmentInsertionCalculator.class); - private HardRouteConstraint hardRouteLevelConstraint; + private final ConstraintManager constraintManager; - private HardActivityConstraint hardActivityLevelConstraint; +// private HardRouteConstraint hardRouteLevelConstraint; +// +// private HardActivityConstraint hardActivityLevelConstraint; private SoftRouteConstraint softRouteConstraint; @@ -64,8 +69,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { public ShipmentInsertionCalculator(VehicleRoutingTransportCosts routingCosts, VehicleRoutingActivityCosts activityCosts, ActivityInsertionCostsCalculator activityInsertionCostsCalculator, ConstraintManager constraintManager) { super(); this.activityInsertionCostsCalculator = activityInsertionCostsCalculator; - this.hardRouteLevelConstraint = constraintManager; - this.hardActivityLevelConstraint = constraintManager; + this.constraintManager = constraintManager; this.softActivityConstraint = constraintManager; this.softRouteConstraint = constraintManager; this.transportCosts = routingCosts; @@ -99,9 +103,8 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { /* check hard route constraints */ - if (!hardRouteLevelConstraint.fulfilled(insertionContext)) { - return InsertionData.createEmptyInsertionData(); - } + InsertionData noInsertion = checkRouteContraints(insertionContext, constraintManager); + if (noInsertion != null) return noInsertion; /* check soft route constraints */ @@ -132,6 +135,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { //pickupShipmentLoop List activities = currentRoute.getTourActivities().getActivities(); + List failedActivityConstraints = new ArrayList<>(); while (!tourEnd) { TourActivity nextAct; if (i < activities.size()) { @@ -148,7 +152,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { ActivityContext activityContext = new ActivityContext(); activityContext.setInsertionIndex(i); insertionContext.setActivityContext(activityContext); - ConstraintsStatus pickupShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime); + ConstraintsStatus pickupShipmentConstraintStatus = fulfilled(insertionContext, prevAct, pickupShipment, nextAct, prevActEndTime, failedActivityConstraints, constraintManager); if (pickupShipmentConstraintStatus.equals(ConstraintsStatus.NOT_FULFILLED)) { pickupInsertionNotFulfilledBreak = false; continue; @@ -194,7 +198,7 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { ActivityContext activityContext_ = new ActivityContext(); activityContext_.setInsertionIndex(j); insertionContext.setActivityContext(activityContext_); - ConstraintsStatus deliverShipmentConstraintStatus = hardActivityLevelConstraint.fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop); + ConstraintsStatus deliverShipmentConstraintStatus = fulfilled(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop, failedActivityConstraints, constraintManager); if (deliverShipmentConstraintStatus.equals(ConstraintsStatus.FULFILLED)) { double additionalDeliveryICosts = softActivityConstraint.getCosts(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop); double deliveryAIC = calculate(insertionContext, prevAct_deliveryLoop, deliverShipment, nextAct_deliveryLoop, prevActEndTime_deliveryLoop); @@ -230,7 +234,9 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator { i++; } if (pickupInsertionIndex == InsertionData.NO_INDEX) { - return InsertionData.createEmptyInsertionData(); + InsertionData emptyInsertionData = new InsertionData.NoInsertionFound(); + emptyInsertionData.getFailedConstraintNames().addAll(failedActivityConstraints); + return emptyInsertionData; } InsertionData insertionData = new InsertionData(bestCost, pickupInsertionIndex, deliveryInsertionIndex, newVehicle, newDriver); pickupShipment.setTheoreticalEarliestOperationStartTime(bestPickupTimeWindow.getStart()); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java index 9190a2f2..ad522012 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/VehicleTypeDependentJobInsertionCalculator.java @@ -98,7 +98,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo } Vehicle selectedVehicle = currentRoute.getVehicle(); Driver selectedDriver = currentRoute.getDriver(); - InsertionData bestIData = InsertionData.createEmptyInsertionData(); + InsertionData bestIData = new InsertionData.NoInsertionFound(); double bestKnownCost_ = bestKnownCost; Collection relevantVehicles = new ArrayList(); if (!(selectedVehicle instanceof VehicleImpl.NoVehicle)) { @@ -115,6 +115,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo else depTime = v.getEarliestDeparture(); InsertionData iData = insertionCalculator.getInsertionData(currentRoute, jobToInsert, v, depTime, selectedDriver, bestKnownCost_); if (iData instanceof InsertionData.NoInsertionFound) { + bestIData.getFailedConstraintNames().addAll(iData.getFailedConstraintNames()); continue; } if (iData.getInsertionCost() < bestKnownCost_) { From 79ac22f7f4daa80c1cdae05532ff292f928f617f Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 21:31:56 +0100 Subject: [PATCH 047/106] memorize reasons and translates constraint names into code and reason - related to #180 --- .../core/util/UnassignedJobReasonTracker.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java new file mode 100644 index 00000000..49eb8cd4 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -0,0 +1,111 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.util; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobUnassignedListener; +import com.graphhopper.jsprit.core.problem.job.Job; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Created by schroeder on 06/02/17. + */ +public class UnassignedJobReasonTracker implements JobUnassignedListener { + + Map> reasons = new HashMap<>(); + + Map codesToReason = new HashMap<>(); + + Map failedConstraintNamesToCode = new HashMap<>(); + + public UnassignedJobReasonTracker() { + codesToReason.put(1, "cannot serve required skill"); + codesToReason.put(2, "cannot be visited within time window"); + codesToReason.put(3, "does not fit into any vehicle due to capacity"); + codesToReason.put(4, "cannot be assigned due to max distance constraint of vehicle"); + + failedConstraintNamesToCode.put("HardSkillConstraint", 1); + failedConstraintNamesToCode.put("VehicleDependentTimeWindowConstraints", 2); + failedConstraintNamesToCode.put("ServiceLoadRouteLevelConstraint", 3); + failedConstraintNamesToCode.put("PickupAndDeliverShipmentLoadActivityLevelConstraint", 3); + failedConstraintNamesToCode.put("ServiceLoadActivityLevelConstraint", 3); + failedConstraintNamesToCode.put("MaxDistanceConstraint", 4); + } + + @Override + public void informJobUnassigned(Job unassigned, Collection failedConstraintNames) { + if (!this.reasons.containsKey(unassigned.getId())) { + Multiset ms = HashMultiset.create(); + this.reasons.put(unassigned.getId(), ms); + } + for (String r : failedConstraintNames) { + this.reasons.get(unassigned.getId()).add(r); + } + } + + public void put(String simpleNameOfFailedConstraint, int code, String reason) { + if (code <= 20) + throw new IllegalArgumentException("first 20 codes are reserved internally. choose a code > 20"); + codesToReason.put(code, reason); + if (failedConstraintNamesToCode.containsKey(simpleNameOfFailedConstraint)) { + throw new IllegalArgumentException(simpleNameOfFailedConstraint + " already assigned to code and reason"); + } else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code); + } + + public int getCode(Job job) { + Multiset reasons = this.reasons.get(job.getId()); + String mostLikelyReason = getMostLikely(reasons); + return toCode(mostLikelyReason); + } + + public String getReason(Job job) { + Multiset reasons = this.reasons.get(job.getId()); + String mostLikelyReason = getMostLikely(reasons); + int code = toCode(mostLikelyReason); + if (code == -1) return mostLikelyReason; + else return codesToReason.get(code); + } + + private int toCode(String mostLikelyReason) { + if (failedConstraintNamesToCode.containsKey(mostLikelyReason)) + return failedConstraintNamesToCode.get(mostLikelyReason); + else return -1; + } + + private String getMostLikely(Multiset reasons) { + Set set = reasons.elementSet(); + int maxCount = 0; + String mostLikely = null; + for (String r : set) { + int count = reasons.count(r); + if (count > maxCount) { + mostLikely = r; + maxCount = count; + } + } + return mostLikely; + } + + +} From 0a8061845dee80c02041181321ce8340e87c012a Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 21:48:47 +0100 Subject: [PATCH 048/106] use job id instead of job - related to #180 --- .../jsprit/core/util/UnassignedJobReasonTracker.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index 49eb8cd4..137ab402 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -73,14 +73,14 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { } else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code); } - public int getCode(Job job) { - Multiset reasons = this.reasons.get(job.getId()); + public int getCode(String jobId) { + Multiset reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); return toCode(mostLikelyReason); } - public String getReason(Job job) { - Multiset reasons = this.reasons.get(job.getId()); + public String getReason(String jobId) { + Multiset reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); int code = toCode(mostLikelyReason); if (code == -1) return mostLikelyReason; From 9e9436e1abfe806d87b8b3af1e7c4c9b1df8e860 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 21:54:59 +0100 Subject: [PATCH 049/106] doc codes - related to #180 --- .../jsprit/core/util/UnassignedJobReasonTracker.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index 137ab402..c558725e 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -73,6 +73,15 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { } else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code); } + /** + * 1 --> "cannot serve required skill + * 2 --> "cannot be visited within time window" + * 3 --> "does not fit into any vehicle due to capacity" + * 4 --> "cannot be assigned due to max distance constraint of vehicle" + * + * @param jobId + * @return + */ public int getCode(String jobId) { Multiset reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); From 6dbc35e3504a74594b19f5a224686ba152ab78cf Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 6 Feb 2017 22:15:53 +0100 Subject: [PATCH 050/106] test reason tracker - related to #180 --- .../util/UnassignedJobReasonTrackerTest.java | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java new file mode 100644 index 00000000..1e43908b --- /dev/null +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java @@ -0,0 +1,140 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.util; + +import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; +import com.graphhopper.jsprit.core.algorithm.box.Jsprit; +import com.graphhopper.jsprit.core.algorithm.state.StateId; +import com.graphhopper.jsprit.core.algorithm.state.StateManager; +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; +import com.graphhopper.jsprit.core.problem.constraint.MaxDistanceConstraint; +import com.graphhopper.jsprit.core.problem.cost.TransportDistance; +import com.graphhopper.jsprit.core.problem.job.Service; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; +import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleType; +import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * Created by schroeder on 06/02/17. + */ +public class UnassignedJobReasonTrackerTest { + + Vehicle vehicle; + + @Before + public void doBefore() { + VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(0, 1); + VehicleType vehicleType = vehicleTypeBuilder.build(); + VehicleImpl.Builder vehicleBuilder = VehicleImpl.Builder.newInstance("vehicle"); + vehicleBuilder.setStartLocation(Location.newInstance(10, 10)); + vehicleBuilder.setType(vehicleType); + vehicleBuilder.setEarliestStart(0).setLatestArrival(100); + vehicle = vehicleBuilder.build(); + } + + @Test + public void shouldReturnCorrectCapacityReasonCode() { + Service service = Service.Builder.newInstance("1").addSizeDimension(0, 5).setLocation(Location.newInstance(5, 7)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service) + .build(); + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker(); + vra.addListener(reasonTracker); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + Assert.assertEquals(1, solution.getUnassignedJobs().size()); + Assert.assertEquals(3, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId())); + } + + @Test + public void shouldReturnCorrectSkillReasonCode() { + Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).addRequiredSkill("ice").setLocation(Location.newInstance(5, 7)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service) + .build(); + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker(); + vra.addListener(reasonTracker); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + Assert.assertEquals(1, solution.getUnassignedJobs().size()); + Assert.assertEquals(1, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId())); + } + + @Test + public void shouldReturnCorrectTWReasonCode() { + Service service = Service.Builder.newInstance("1").addSizeDimension(0, 1).setTimeWindow(TimeWindow.newInstance(110, 200)).setLocation(Location.newInstance(5, 7)).build(); + + VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service) + .build(); + + VehicleRoutingAlgorithm vra = Jsprit.createAlgorithm(vrp); + UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker(); + vra.addListener(reasonTracker); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + Assert.assertEquals(1, solution.getUnassignedJobs().size()); + Assert.assertEquals(2, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId())); + } + + @Test + public void shouldReturnCorrectMaxDistanceReasonCode() { + Service service = Service.Builder.newInstance("1").setLocation(Location.newInstance(51, 0)).build(); + + Vehicle vehicle = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance(0, 0)).build(); + + final VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(VehicleRoutingProblem.FleetSize.FINITE).addVehicle(vehicle).addJob(service).build(); + + StateManager stateManager = new StateManager(vrp); + ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager); + StateId maxDistance = stateManager.createStateId("max-distance"); + Map distMap = new HashMap<>(); + distMap.put(vehicle, 100d); + MaxDistanceConstraint distanceConstraint = new MaxDistanceConstraint(stateManager, maxDistance, new TransportDistance() { + @Override + public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { + return vrp.getTransportCosts().getTransportCost(from, to, departureTime, null, vehicle); + } + }, distMap); + constraintManager.addConstraint(distanceConstraint, ConstraintManager.Priority.CRITICAL); + + VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setStateAndConstraintManager(stateManager, constraintManager) + .buildAlgorithm(); + UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker(); + vra.addListener(reasonTracker); + + VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); + Assert.assertEquals(1, solution.getUnassignedJobs().size()); + Assert.assertEquals(4, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId())); + } +} From ab8741a33513d52a5334e92e1c05fdf0101b05df Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 7 Feb 2017 09:53:46 +0100 Subject: [PATCH 051/106] get rid of google guava dep --- jsprit-core/pom.xml | 6 ---- .../core/util/UnassignedJobReasonTracker.java | 30 +++++++++---------- .../util/UnassignedJobReasonTrackerTest.java | 16 ++++++++++ 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index 3ae778a0..f3d79fc0 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -42,12 +42,6 @@ ${logger.version} - - com.google.guava - guava - 21.0 - - diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index c558725e..1a07c12b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -18,22 +18,21 @@ package com.graphhopper.jsprit.core.util; -import com.google.common.collect.HashMultiset; -import com.google.common.collect.Multiset; import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobUnassignedListener; import com.graphhopper.jsprit.core.problem.job.Job; +import org.apache.commons.math3.stat.Frequency; import java.util.Collection; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; -import java.util.Set; /** * Created by schroeder on 06/02/17. */ public class UnassignedJobReasonTracker implements JobUnassignedListener { - Map> reasons = new HashMap<>(); + Map reasons = new HashMap<>(); Map codesToReason = new HashMap<>(); @@ -56,11 +55,10 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { @Override public void informJobUnassigned(Job unassigned, Collection failedConstraintNames) { if (!this.reasons.containsKey(unassigned.getId())) { - Multiset ms = HashMultiset.create(); - this.reasons.put(unassigned.getId(), ms); + this.reasons.put(unassigned.getId(), new Frequency()); } for (String r : failedConstraintNames) { - this.reasons.get(unassigned.getId()).add(r); + this.reasons.get(unassigned.getId()).addValue(r); } } @@ -83,13 +81,13 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public int getCode(String jobId) { - Multiset reasons = this.reasons.get(jobId); + Frequency reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); return toCode(mostLikelyReason); } public String getReason(String jobId) { - Multiset reasons = this.reasons.get(jobId); + Frequency reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); int code = toCode(mostLikelyReason); if (code == -1) return mostLikelyReason; @@ -102,15 +100,15 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { else return -1; } - private String getMostLikely(Multiset reasons) { - Set set = reasons.elementSet(); + private String getMostLikely(Frequency reasons) { + Iterator, Long>> entryIterator = reasons.entrySetIterator(); int maxCount = 0; String mostLikely = null; - for (String r : set) { - int count = reasons.count(r); - if (count > maxCount) { - mostLikely = r; - maxCount = count; + while (entryIterator.hasNext()) { + Map.Entry, Long> entry = entryIterator.next(); + if (entry.getValue() > maxCount) { + Comparable key = entry.getKey(); + mostLikely = key.toString(); } } return mostLikely; diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java index 1e43908b..3981eed3 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java @@ -34,11 +34,13 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; import com.graphhopper.jsprit.core.problem.vehicle.VehicleType; import com.graphhopper.jsprit.core.problem.vehicle.VehicleTypeImpl; +import org.apache.commons.math3.stat.Frequency; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; /** @@ -137,4 +139,18 @@ public class UnassignedJobReasonTrackerTest { Assert.assertEquals(1, solution.getUnassignedJobs().size()); Assert.assertEquals(4, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId())); } + + @Test + public void testFreq() { + Frequency frequency = new Frequency(); + frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint"); + frequency.addValue("b"); + frequency.addValue("VehicleDependentTimeWindowHardActivityConstraint"); + + Iterator, Long>> entryIterator = frequency.entrySetIterator(); + while (entryIterator.hasNext()) { + Map.Entry, Long> e = entryIterator.next(); + System.out.println(e.getKey().toString() + " " + e.getValue()); + } + } } From f9e000c3ff76b843f94708a945d995a9399aa1bf Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 13 Feb 2017 12:51:27 +0100 Subject: [PATCH 052/106] rename current dev to 1.7.1-SNAPSHOT --- jsprit-analysis/pom.xml | 2 +- jsprit-core/pom.xml | 2 +- jsprit-examples/pom.xml | 2 +- jsprit-instances/pom.xml | 2 +- jsprit-io/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jsprit-analysis/pom.xml b/jsprit-analysis/pom.xml index a5707f18..409ef69d 100644 --- a/jsprit-analysis/pom.xml +++ b/jsprit-analysis/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.7-SNAPSHOT + 1.7.1-SNAPSHOT 4.0.0 jsprit-analysis diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index f3d79fc0..d20a01b6 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -21,7 +21,7 @@ com.graphhopper jsprit - 1.7-SNAPSHOT + 1.7.1-SNAPSHOT 4.0.0 jsprit-core diff --git a/jsprit-examples/pom.xml b/jsprit-examples/pom.xml index 3680ba94..23457bb6 100644 --- a/jsprit-examples/pom.xml +++ b/jsprit-examples/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.7-SNAPSHOT + 1.7.1-SNAPSHOT 4.0.0 diff --git a/jsprit-instances/pom.xml b/jsprit-instances/pom.xml index 04a8e8f4..7d31f92e 100644 --- a/jsprit-instances/pom.xml +++ b/jsprit-instances/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.7-SNAPSHOT + 1.7.1-SNAPSHOT 4.0.0 diff --git a/jsprit-io/pom.xml b/jsprit-io/pom.xml index 8487e20a..257aed74 100644 --- a/jsprit-io/pom.xml +++ b/jsprit-io/pom.xml @@ -23,7 +23,7 @@ com.graphhopper jsprit - 1.7-SNAPSHOT + 1.7.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index ed207968..773d477a 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ com.graphhopper jsprit - 1.7-SNAPSHOT + 1.7.1-SNAPSHOT pom From 2953513e0fd1b1aa9353cd8bad1526ed2e3ff65f Mon Sep 17 00:00:00 2001 From: Felipe Zavan Date: Sat, 18 Feb 2017 01:30:39 -0200 Subject: [PATCH 053/106] Fix typo --- docs/Simple-Example.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Simple-Example.md b/docs/Simple-Example.md index 091e8cc6..d61aa27e 100644 --- a/docs/Simple-Example.md +++ b/docs/Simple-Example.md @@ -16,7 +16,7 @@ First, build a vehicle with its vehicle-type:

/*
  * get a vehicle type-builder and build a type with the typeId "vehicleType" and a capacity of 2
- * you are free to add an arbitrary number of capacity dimensions with .addCacpacityDimension(dimensionIndex,dimensionValue)
+ * you are free to add an arbitrary number of capacity dimensions with .addCapacityDimension(dimensionIndex,dimensionValue)
  */
 final int WEIGHT_INDEX = 0;
 VehicleTypeImpl.Builder vehicleTypeBuilder = VehicleTypeImpl.Builder.newInstance("vehicleType").addCapacityDimension(WEIGHT_INDEX,2);

From 9453f0eb06fe46e39c15dc7ccc7bb930593a533e Mon Sep 17 00:00:00 2001
From: oblonski 
Date: Tue, 14 Mar 2017 09:55:35 +0100
Subject: [PATCH 054/106] make reason frequency accessible

---
 .../core/util/UnassignedJobReasonTracker.java | 44 ++++++++++++++++---
 .../util/UnassignedJobReasonTrackerTest.java  |  8 ++--
 2 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
index 1a07c12b..630d45ba 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
@@ -22,10 +22,7 @@ import com.graphhopper.jsprit.core.algorithm.recreate.listener.JobUnassignedList
 import com.graphhopper.jsprit.core.problem.job.Job;
 import org.apache.commons.math3.stat.Frequency;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.*;
 
 /**
  * Created by schroeder on 06/02/17.
@@ -72,6 +69,35 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener {
     }
 
     /**
+     * For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map.
+     *
+     * @return
+     */
+    public Map getReasons() {
+        return Collections.unmodifiableMap(reasons);
+    }
+
+    /**
+     * Returns an unmodifiable map of codes and reason pairs.
+     *
+     * @return
+     */
+    public Map getCodesToReason() {
+        return Collections.unmodifiableMap(codesToReason);
+    }
+
+    /**
+     * Returns an unmodifiable map of constraint names (simple name of constraint) and reason code pairs.
+     *
+     * @return
+     */
+    public Map getFailedConstraintNamesToCode() {
+        return Collections.unmodifiableMap(failedConstraintNamesToCode);
+    }
+
+    /**
+     * Returns the most likely reason code i.e. the reason (failed constraint) being observed most often.
+     *
      * 1 --> "cannot serve required skill
      * 2 --> "cannot be visited within time window"
      * 3 --> "does not fit into any vehicle due to capacity"
@@ -80,13 +106,19 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener {
      * @param jobId
      * @return
      */
-    public int getCode(String jobId) {
+    public int getMostLikelyReasonCode(String jobId) {
         Frequency reasons = this.reasons.get(jobId);
         String mostLikelyReason = getMostLikely(reasons);
         return toCode(mostLikelyReason);
     }
 
-    public String getReason(String jobId) {
+    /**
+     * Returns the most likely reason i.e. the reason (failed constraint) being observed most often.
+     *
+     * @param jobId
+     * @return
+     */
+    public String getMostLikelyReason(String jobId) {
         Frequency reasons = this.reasons.get(jobId);
         String mostLikelyReason = getMostLikely(reasons);
         int code = toCode(mostLikelyReason);
diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java
index 3981eed3..aee8a95d 100644
--- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java
+++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTrackerTest.java
@@ -74,7 +74,7 @@ public class UnassignedJobReasonTrackerTest {
 
         VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
         Assert.assertEquals(1, solution.getUnassignedJobs().size());
-        Assert.assertEquals(3, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId()));
+        Assert.assertEquals(3, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
     }
 
     @Test
@@ -90,7 +90,7 @@ public class UnassignedJobReasonTrackerTest {
 
         VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
         Assert.assertEquals(1, solution.getUnassignedJobs().size());
-        Assert.assertEquals(1, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId()));
+        Assert.assertEquals(1, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
     }
 
     @Test
@@ -106,7 +106,7 @@ public class UnassignedJobReasonTrackerTest {
 
         VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
         Assert.assertEquals(1, solution.getUnassignedJobs().size());
-        Assert.assertEquals(2, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId()));
+        Assert.assertEquals(2, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
     }
 
     @Test
@@ -137,7 +137,7 @@ public class UnassignedJobReasonTrackerTest {
 
         VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions());
         Assert.assertEquals(1, solution.getUnassignedJobs().size());
-        Assert.assertEquals(4, reasonTracker.getCode(solution.getUnassignedJobs().iterator().next().getId()));
+        Assert.assertEquals(4, reasonTracker.getMostLikelyReasonCode(solution.getUnassignedJobs().iterator().next().getId()));
     }
 
     @Test

From 185980d8c0523c58e0f2205b371c249f0c72646c Mon Sep 17 00:00:00 2001
From: oblonski 
Date: Tue, 14 Mar 2017 13:09:03 +0100
Subject: [PATCH 055/106] allow constraints to be ignored

---
 .../jsprit/core/util/UnassignedJobReasonTracker.java       | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
index 630d45ba..34873590 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java
@@ -35,6 +35,8 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener {
 
     Map failedConstraintNamesToCode = new HashMap<>();
 
+    Set constraintsToBeIgnored = new HashSet<>();
+
     public UnassignedJobReasonTracker() {
         codesToReason.put(1, "cannot serve required skill");
         codesToReason.put(2, "cannot be visited within time window");
@@ -49,12 +51,17 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener {
         failedConstraintNamesToCode.put("MaxDistanceConstraint", 4);
     }
 
+    public void ignore(String simpleNameOfConstraint) {
+        constraintsToBeIgnored.add(simpleNameOfConstraint);
+    }
+
     @Override
     public void informJobUnassigned(Job unassigned, Collection failedConstraintNames) {
         if (!this.reasons.containsKey(unassigned.getId())) {
             this.reasons.put(unassigned.getId(), new Frequency());
         }
         for (String r : failedConstraintNames) {
+            if (constraintsToBeIgnored.contains(r)) continue;
             this.reasons.get(unassigned.getId()).addValue(r);
         }
     }

From 562be55ae6fc5820449561cb17c3a310ea2c76a5 Mon Sep 17 00:00:00 2001
From: oblonski 
Date: Wed, 15 Mar 2017 15:20:57 +0100
Subject: [PATCH 056/106] get no. locations

---
 ...astVehicleRoutingTransportCostsMatrix.java | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java
index 80742c4c..5e6a5d1d 100644
--- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java
+++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/FastVehicleRoutingTransportCostsMatrix.java
@@ -45,6 +45,8 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic
 
         private double[][][] matrix;
 
+        private final int noLocations;
+
         /**
          * Creates a new builder returning the matrix-builder.
          * 

If you want to consider symmetric matrices, set isSymmetric to true. @@ -59,6 +61,7 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic private Builder(int noLocations, boolean isSymmetric) { this.isSymmetric = isSymmetric; matrix = new double[noLocations][noLocations][2]; + this.noLocations = noLocations; } /** @@ -74,11 +77,11 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic return this; } - private void add(int fromIndex, int toIndex, int indicatorIndex, double distance) { + private void add(int fromIndex, int toIndex, int indicatorIndex, double value) { if (isSymmetric) { - if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = distance; - else matrix[toIndex][fromIndex][indicatorIndex] = distance; - } else matrix[fromIndex][toIndex][indicatorIndex] = distance; + if (fromIndex < toIndex) matrix[fromIndex][toIndex][indicatorIndex] = value; + else matrix[toIndex][fromIndex][indicatorIndex] = value; + } else matrix[fromIndex][toIndex][indicatorIndex] = value; } /** @@ -115,9 +118,12 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic private final double[][][] matrix; + private int noLocations; + private FastVehicleRoutingTransportCostsMatrix(Builder builder) { this.isSymmetric = builder.isSymmetric; matrix = builder.matrix; + noLocations = builder.noLocations; } /** @@ -174,4 +180,9 @@ public class FastVehicleRoutingTransportCostsMatrix extends AbstractForwardVehic return costParams.perDistanceUnit * getDistance(from.getIndex(), to.getIndex()) + costParams.perTransportTimeUnit * getTransportTime(from, to, departureTime, driver, vehicle); } + public int getNoLocations() { + return noLocations; + } + + } From b5c69ba4d0f84a2e129ab391d9c8479b8482a603 Mon Sep 17 00:00:00 2001 From: oblonski Date: Sat, 1 Apr 2017 20:38:34 +0200 Subject: [PATCH 057/106] play with string length --- .../graphhopper/jsprit/core/algorithm/ruin/RuinString.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 530f103c..1d036076 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -49,9 +49,9 @@ public final class RuinString extends AbstractRuinStrategy { private int Kmax = 6; - private int Lmin = 1; + private int Lmin = 15; - private int Lmax = 40; + private int Lmax = 100; /** * Constructs RuinRadial. From 8505d0dc4866f67f831ac29a3453ee00f5f83247 Mon Sep 17 00:00:00 2001 From: oblonski Date: Mon, 3 Apr 2017 08:52:34 +0200 Subject: [PATCH 058/106] play with string length --- .../graphhopper/jsprit/core/algorithm/ruin/RuinString.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 1d036076..6d0d23b1 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -49,9 +49,9 @@ public final class RuinString extends AbstractRuinStrategy { private int Kmax = 6; - private int Lmin = 15; + private int Lmin = 10; - private int Lmax = 100; + private int Lmax = 50; /** * Constructs RuinRadial. From 271d251c3529434ef0f2da719bff7589ccbdcca4 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 19 Apr 2017 13:31:53 +0200 Subject: [PATCH 059/106] play with string length --- .../graphhopper/jsprit/core/algorithm/ruin/RuinString.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 6d0d23b1..9aa7cf0b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -49,9 +49,9 @@ public final class RuinString extends AbstractRuinStrategy { private int Kmax = 6; - private int Lmin = 10; + private int Lmin = 30; - private int Lmax = 50; + private int Lmax = 60; /** * Constructs RuinRadial. From 933e2ca120f2b9fbb2e02318ce33fe90b192add1 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 19 Apr 2017 14:04:19 +0200 Subject: [PATCH 060/106] add location info for scheduling breaks with route builder --- .../problem/solution/route/VehicleRoute.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java index c04d1ee1..a04a58b2 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java @@ -19,6 +19,7 @@ package com.graphhopper.jsprit.core.problem.solution.route; import com.graphhopper.jsprit.core.problem.AbstractActivity; import com.graphhopper.jsprit.core.problem.JobActivityFactory; +import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.driver.DriverImpl; import com.graphhopper.jsprit.core.problem.job.*; @@ -186,6 +187,16 @@ public class VehicleRoute { return addService(service,service.getTimeWindow()); } + private Builder addBreakInternally(Break currentBreak, TimeWindow timeWindow, Location breakLocation) { + List acts = jobActivityFactory.createActivities(currentBreak); + BreakActivity act = (BreakActivity) acts.get(0); + act.setTheoreticalEarliestOperationStartTime(timeWindow.getStart()); + act.setTheoreticalLatestOperationStartTime(timeWindow.getEnd()); + act.setLocation(breakLocation); + tourActivities.addActivity(act); + return this; + } + public Builder addService(Service service, TimeWindow timeWindow) { if (service == null) throw new IllegalArgumentException("service must not be null"); List acts = jobActivityFactory.createActivities(service); @@ -196,16 +207,25 @@ public class VehicleRoute { return this; } + @Deprecated public Builder addBreak(Break currentbreak) { if (currentbreak == null) throw new IllegalArgumentException("break must not be null"); return addBreak(currentbreak, currentbreak.getTimeWindow()); } + @Deprecated public Builder addBreak(Break currentbreak, TimeWindow timeWindow) { if (currentbreak == null) throw new IllegalArgumentException("break must not be null"); return addService(currentbreak,timeWindow); } + public Builder addBreak(Break currentBreak, TimeWindow timeWindow, Location breakLocation) { + if (currentBreak == null) throw new IllegalArgumentException("break must not be null"); + return addBreakInternally(currentBreak, timeWindow, breakLocation); + } + + + /** * Adds a pickup to this route. * From 39751c8c5aeb3ac5fae4dad7ce4683a030a38e51 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 19 Apr 2017 14:10:10 +0200 Subject: [PATCH 061/106] add location info for scheduling breaks with route builder --- .../problem/solution/route/VehicleRoute.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java index c04d1ee1..7dd0c17d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java @@ -19,6 +19,7 @@ package com.graphhopper.jsprit.core.problem.solution.route; import com.graphhopper.jsprit.core.problem.AbstractActivity; import com.graphhopper.jsprit.core.problem.JobActivityFactory; +import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.driver.Driver; import com.graphhopper.jsprit.core.problem.driver.DriverImpl; import com.graphhopper.jsprit.core.problem.job.*; @@ -196,16 +197,33 @@ public class VehicleRoute { return this; } + @Deprecated public Builder addBreak(Break currentbreak) { if (currentbreak == null) throw new IllegalArgumentException("break must not be null"); return addBreak(currentbreak, currentbreak.getTimeWindow()); } + @Deprecated public Builder addBreak(Break currentbreak, TimeWindow timeWindow) { if (currentbreak == null) throw new IllegalArgumentException("break must not be null"); return addService(currentbreak,timeWindow); } + public Builder addBreak(Break currentbreak, TimeWindow timeWindow, Location location) { + if (currentbreak == null) throw new IllegalArgumentException("break must not be null"); + return addBreakInternally(currentbreak, timeWindow, location); + } + + private Builder addBreakInternally(Break currentBreak, TimeWindow timeWindow, Location breakLocation) { + List acts = jobActivityFactory.createActivities(currentBreak); + BreakActivity act = (BreakActivity) acts.get(0); + act.setTheoreticalEarliestOperationStartTime(timeWindow.getStart()); + act.setTheoreticalLatestOperationStartTime(timeWindow.getEnd()); + act.setLocation(breakLocation); + tourActivities.addActivity(act); + return this; + } + /** * Adds a pickup to this route. * From 5d56d2e09147029abdac002e3ffe6d99b09b943d Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 26 Apr 2017 15:05:28 +0200 Subject: [PATCH 062/106] make string ruin configurable --- .../jsprit/core/algorithm/box/Jsprit.java | 20 +++++++++++++++++-- .../core/algorithm/ruin/RuinString.java | 11 ++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 557bc4cd..b7d6a73e 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -121,7 +121,12 @@ public class Jsprit { FAST_REGRET("regret.fast"), MAX_TRANSPORT_COSTS("max_transport_costs"), CONSTRUCTION("construction"), - BREAK_SCHEDULING("break_scheduling"); + BREAK_SCHEDULING("break_scheduling"), + STRING_KMIN("string_kmin"), + STRING_KMAX("string_kmax"), + STRING_LMIN("string_lmin"), + STRING_LMAX("string_lmax"); + String paraName; @@ -184,10 +189,17 @@ public class Jsprit { defaults.put(Strategy.STRING_BEST.toString(), ".5"); defaults.put(Strategy.STRING_REGRET.toString(), ".5"); + defaults.put(Parameter.STRING_KMIN.toString(), "1"); + defaults.put(Parameter.STRING_KMAX.toString(), "6"); + defaults.put(Parameter.STRING_LMIN.toString(), "10"); + defaults.put(Parameter.STRING_LMAX.toString(), "30"); + defaults.put(Strategy.WORST_BEST.toString(), "0."); defaults.put(Strategy.WORST_REGRET.toString(), "1."); defaults.put(Strategy.CLUSTER_BEST.toString(), "0."); defaults.put(Strategy.CLUSTER_REGRET.toString(), "1."); + + defaults.put(Parameter.FIXED_COST_PARAM.toString(), "0."); defaults.put(Parameter.VEHICLE_SWITCH.toString(), "true"); defaults.put(Parameter.ITERATIONS.toString(), "2000"); @@ -478,7 +490,11 @@ public class Jsprit { random) ); - final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods); + int kmin = toInteger(properties.getProperty(Parameter.STRING_KMIN.toString())); + int kmax = toInteger(properties.getProperty(Parameter.STRING_KMAX.toString())); + int lmin = toInteger(properties.getProperty(Parameter.STRING_LMIN.toString())); + int lmax = toInteger(properties.getProperty(Parameter.STRING_LMAX.toString())); + final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods, kmin, kmax, lmin, lmax); stringRuin.setRandom(random); AbstractInsertionStrategy regret; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 9aa7cf0b..79f0310f 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -92,6 +92,17 @@ public final class RuinString extends AbstractRuinStrategy { logger.debug("initialise {}", this); } + public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods, int Kmin, int Kmax, int Lmin, int Lmax) { + super(vrp); + this.vrp = vrp; + this.jobNeighborhoods = jobNeighborhoods; + this.Kmin = Kmin; + this.Kmax = Kmax; + this.Lmin = Lmin; + this.Lmax = Lmax; + logger.debug("initialise {}", this); + } + @Override public String toString() { return "[name=splitRuin]"; From 9e2afa4f75b9b5d2945a335e080d65f2c373731c Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 26 Apr 2017 15:22:37 +0200 Subject: [PATCH 063/106] make string ruin configurable --- .../jsprit/core/algorithm/box/Jsprit.java | 17 +- .../core/algorithm/ruin/RuinString.java | 80 ++---- .../examples/BuildAlgorithmFromScratch2.java | 252 ------------------ 3 files changed, 36 insertions(+), 313 deletions(-) delete mode 100644 jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index b7d6a73e..438344da 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -186,8 +186,8 @@ public class Jsprit { defaults.put(Strategy.RANDOM_BEST.toString(), ".5"); defaults.put(Strategy.RANDOM_REGRET.toString(), ".5"); - defaults.put(Strategy.STRING_BEST.toString(), ".5"); - defaults.put(Strategy.STRING_REGRET.toString(), ".5"); + defaults.put(Strategy.STRING_BEST.toString(), "0.0"); + defaults.put(Strategy.STRING_REGRET.toString(), "0.0"); defaults.put(Parameter.STRING_KMIN.toString(), "1"); defaults.put(Parameter.STRING_KMAX.toString(), "6"); @@ -490,11 +490,14 @@ public class Jsprit { random) ); - int kmin = toInteger(properties.getProperty(Parameter.STRING_KMIN.toString())); - int kmax = toInteger(properties.getProperty(Parameter.STRING_KMAX.toString())); - int lmin = toInteger(properties.getProperty(Parameter.STRING_LMIN.toString())); - int lmax = toInteger(properties.getProperty(Parameter.STRING_LMAX.toString())); - final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods, kmin, kmax, lmin, lmax); + int kMin = toInteger(properties.getProperty(Parameter.STRING_KMIN.toString())); + int kMax = toInteger(properties.getProperty(Parameter.STRING_KMAX.toString())); + int lMin = toInteger(properties.getProperty(Parameter.STRING_LMIN.toString())); + int lMax = toInteger(properties.getProperty(Parameter.STRING_LMAX.toString())); + + final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods); + stringRuin.setNoRoutes(kMin, kMax); + stringRuin.setStringLength(lMin, lMax); stringRuin.setRandom(random); AbstractInsertionStrategy regret; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 79f0310f..cf19a464 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -17,7 +17,6 @@ */ package com.graphhopper.jsprit.core.algorithm.ruin; -import com.graphhopper.jsprit.core.algorithm.ruin.distance.JobDistance; import com.graphhopper.jsprit.core.problem.AbstractActivity; import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; import com.graphhopper.jsprit.core.problem.job.Job; @@ -31,9 +30,15 @@ import java.util.*; /** - * RuinStrategy that ruins the neighborhood of a randomly selected job. The size and the structure of the neighborhood is defined by - * the share of jobs to be removed and the distance between jobs (where distance not necessarily mean Euclidean distance but an arbitrary - * measure). + * RuinString is adopted from + * + * Technical report 7.11.2016 + * A Fresh Ruin & Recreate Implementation for the Capacitated Vehicle Routing Problem + * Jan Christiaens, Greet Vanden Berghe + * KU Leuven, Department of Computer Science, CODeS & iMinds-ITEC + * Gebr. De Smetstraat 1, 9000 Gent, Belgium, jan.christiaens@cs.kuleuven.be, greet.vandenberghe@cs.kuleuven.be + * + * https://lirias.kuleuven.be/bitstream/123456789/556398/1/asb_rr_2016.pdf * * @author stefan */ @@ -45,46 +50,14 @@ public final class RuinString extends AbstractRuinStrategy { private JobNeighborhoods jobNeighborhoods; - private int Kmin = 1; + private int kMin = 1; - private int Kmax = 6; + private int kMax = 6; - private int Lmin = 30; - - private int Lmax = 60; - - /** - * Constructs RuinRadial. - * - * @param vrp - * @param jobDistance i.e. a measure to define the distance between two jobs and whether they are located close or distant to eachother - * @param Kmin - * @param Kmax - * @param Lmin - * @param Lmax - */ - public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance, int Kmin, int Kmax, int Lmin, int Lmax) { - super(vrp); - this.vrp = vrp; - JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax); - jobNeighborhoodsImpl.initialise(); - jobNeighborhoods = jobNeighborhoodsImpl; - this.Kmin = Kmin; - this.Kmax = Kmax; - this.Lmin = Lmin; - this.Lmax = Lmax; - logger.debug("initialise {}", this); - } - - public RuinString(VehicleRoutingProblem vrp, JobDistance jobDistance) { - super(vrp); - this.vrp = vrp; - JobNeighborhoodsImplWithCapRestriction jobNeighborhoodsImpl = new JobNeighborhoodsImplWithCapRestriction(vrp, jobDistance, Kmax * Lmax); - jobNeighborhoodsImpl.initialise(); - jobNeighborhoods = jobNeighborhoodsImpl; - logger.debug("initialise {}", this); - } + private int lMin = 30; + private int lMax = 60; + public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) { super(vrp); this.vrp = vrp; @@ -92,15 +65,14 @@ public final class RuinString extends AbstractRuinStrategy { logger.debug("initialise {}", this); } - public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods, int Kmin, int Kmax, int Lmin, int Lmax) { - super(vrp); - this.vrp = vrp; - this.jobNeighborhoods = jobNeighborhoods; - this.Kmin = Kmin; - this.Kmax = Kmax; - this.Lmin = Lmin; - this.Lmax = Lmax; - logger.debug("initialise {}", this); + public void setNoRoutes(int kMin, int kMax) { + this.kMin = kMin; + this.kMax = kMax; + } + + public void setStringLength(int lMin, int lMax) { + this.lMin = lMin; + this.lMax = lMax; } @Override @@ -117,12 +89,12 @@ public final class RuinString extends AbstractRuinStrategy { if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) { return Collections.emptyList(); } - int noStrings = Kmin + random.nextInt((Kmax - Kmin)); + int noStrings = kMin + random.nextInt((kMax - kMin)); noStrings = Math.min(noStrings, vehicleRoutes.size()); Set unassignedJobs = new HashSet<>(); Set ruinedRoutes = new HashSet<>(); Job prevJob = RandomUtils.nextJob(vrp.getJobs().values(), random); - Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(Kmax * Lmax, prevJob); + Iterator neighborhoodIterator = jobNeighborhoods.getNearestNeighborsIterator(kMax * lMax, prevJob); while (neighborhoodIterator.hasNext() && ruinedRoutes.size() <= noStrings) { if (!unassignedJobs.contains(prevJob)) { VehicleRoute route = getRouteOf(prevJob, vehicleRoutes); @@ -149,7 +121,7 @@ public final class RuinString extends AbstractRuinStrategy { private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { int noActivities = seedRoute.getActivities().size(); - int stringLength = Lmin + random.nextInt(Lmax - Lmin); + int stringLength = lMin + random.nextInt(lMax - lMin); stringLength = Math.min(stringLength, seedRoute.getActivities().size()); int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random); @@ -204,7 +176,7 @@ public final class RuinString extends AbstractRuinStrategy { private void ruinRouteWithStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { - int stringLength = Lmin + random.nextInt(Lmax - Lmin); + int stringLength = lMin + random.nextInt(lMax - lMin); stringLength = Math.min(stringLength, seedRoute.getActivities().size()); List acts = vrp.getActivities(prevJob); AbstractActivity randomSeedAct = RandomUtils.nextItem(acts, random); diff --git a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java b/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java deleted file mode 100644 index 88544ec4..00000000 --- a/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/BuildAlgorithmFromScratch2.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.graphhopper.jsprit.examples; - - -import com.graphhopper.jsprit.analysis.toolbox.AlgorithmEventsRecorder; -import com.graphhopper.jsprit.analysis.toolbox.GraphStreamViewer; -import com.graphhopper.jsprit.core.algorithm.PrettyAlgorithmBuilder; -import com.graphhopper.jsprit.core.algorithm.SearchStrategy; -import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; -import com.graphhopper.jsprit.core.algorithm.acceptor.SchrimpfAcceptance; -import com.graphhopper.jsprit.core.algorithm.box.Jsprit; -import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener; -import com.graphhopper.jsprit.core.algorithm.module.RuinAndRecreateModule; -import com.graphhopper.jsprit.core.algorithm.recreate.*; -import com.graphhopper.jsprit.core.algorithm.ruin.RadialRuinStrategyFactory; -import com.graphhopper.jsprit.core.algorithm.ruin.RandomRuinStrategyFactory; -import com.graphhopper.jsprit.core.algorithm.ruin.RuinStrategy; -import com.graphhopper.jsprit.core.algorithm.ruin.RuinString; -import com.graphhopper.jsprit.core.algorithm.ruin.distance.AvgServiceAndShipmentDistance; -import com.graphhopper.jsprit.core.algorithm.selector.SelectBest; -import com.graphhopper.jsprit.core.algorithm.state.StateManager; -import com.graphhopper.jsprit.core.analysis.SolutionAnalyser; -import com.graphhopper.jsprit.core.problem.Location; -import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; -import com.graphhopper.jsprit.core.problem.constraint.ConstraintManager; -import com.graphhopper.jsprit.core.problem.cost.TransportDistance; -import com.graphhopper.jsprit.core.problem.job.Job; -import com.graphhopper.jsprit.core.problem.solution.SolutionCostCalculator; -import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; -import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; -import com.graphhopper.jsprit.core.problem.vehicle.FiniteFleetManagerFactory; -import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; -import com.graphhopper.jsprit.core.problem.vehicle.VehicleFleetManager; -import com.graphhopper.jsprit.core.reporting.SolutionPrinter; -import com.graphhopper.jsprit.core.util.Solutions; -import com.graphhopper.jsprit.instance.reader.CordeauReader; -import com.graphhopper.jsprit.util.Examples; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public class BuildAlgorithmFromScratch2 { - - - public static class MyBestStrategy extends AbstractInsertionStrategy { - - private JobInsertionCostsCalculatorLight insertionCalculator; - - - public MyBestStrategy(VehicleRoutingProblem vrp, VehicleFleetManager fleetManager, StateManager stateManager, ConstraintManager constraintManager) { - super(vrp); - insertionCalculator = JobInsertionCostsCalculatorLightFactory.createStandardCalculator(vrp, fleetManager, stateManager, constraintManager); - } - - @Override - public Collection insertUnassignedJobs(Collection vehicleRoutes, Collection unassignedJobs) { - List badJobs = new ArrayList(); - List unassigned = new ArrayList(unassignedJobs); - Collections.shuffle(unassigned, random); - - for (Job j : unassigned) { - - InsertionData bestInsertionData = InsertionData.createEmptyInsertionData(); - VehicleRoute bestRoute = null; - //look for inserting unassigned job into existing route - for (VehicleRoute r : vehicleRoutes) { - InsertionData insertionData = insertionCalculator.getInsertionData(j, r, bestInsertionData.getInsertionCost()); - if (insertionData instanceof InsertionData.NoInsertionFound) continue; - if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) { - bestInsertionData = insertionData; - bestRoute = r; - } - } - //try whole new route - VehicleRoute empty = VehicleRoute.emptyRoute(); - InsertionData insertionData = insertionCalculator.getInsertionData(j, empty, bestInsertionData.getInsertionCost()); - if (!(insertionData instanceof InsertionData.NoInsertionFound)) { - if (insertionData.getInsertionCost() < bestInsertionData.getInsertionCost()) { - vehicleRoutes.add(empty); - insertJob(j, insertionData, empty); - } - } else { - if (bestRoute != null) insertJob(j, bestInsertionData, bestRoute); - else badJobs.add(j); - } - } - return badJobs; - } - - - } - - - public static void main(String[] args) { - Examples.createOutputFolder(); - - VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance(); - new CordeauReader(vrpBuilder).read("input/p11"); - final VehicleRoutingProblem vrp = vrpBuilder.build(); - -// VehicleRoutingAlgorithm vra = createAlgorithm(vrp); - VehicleRoutingAlgorithm vra = Jsprit.Builder.newInstance(vrp).setProperty(Jsprit.Parameter.FAST_REGRET, "true") - .setProperty(Jsprit.Parameter.THREADS, "4") - .setProperty(Jsprit.Parameter.REGRET_DISTANCE_SCORER, "0.0001") - .setProperty(Jsprit.Strategy.STRING_BEST, "0.2") - .setProperty(Jsprit.Strategy.STRING_REGRET, "0.2") - .buildAlgorithm(); - - vra.setMaxIterations(15000); - AlgorithmEventsRecorder eventsRecorder = new AlgorithmEventsRecorder(vrp, "output/events.dgs.gz"); - eventsRecorder.setRecordingRange(40, 100); -// vra.addListener(eventsRecorder); - - VehicleRoutingProblemSolution solution = Solutions.bestOf(vra.searchSolutions()); - SolutionPrinter.print(vrp, solution, SolutionPrinter.Print.VERBOSE); - - new GraphStreamViewer(vrp, solution).display(); -// AlgorithmEventsViewer viewer = new AlgorithmEventsViewer(); -// viewer.setRuinDelay(6); -// viewer.setRecreationDelay(1); -// viewer.display("output/events.dgs.gz"); - - } - - - public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp) { - - VehicleFleetManager fleetManager = new FiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); - StateManager stateManager = new StateManager(vrp); - ConstraintManager constraintManager = new ConstraintManager(vrp, stateManager); - - /* - * insertion strategies - */ - //my custom best insertion - MyBestStrategy best = new MyBestStrategy(vrp, fleetManager, stateManager, constraintManager); - - //regret insertion - InsertionBuilder iBuilder = new InsertionBuilder(vrp, fleetManager, stateManager, constraintManager); - iBuilder.setInsertionStrategy(InsertionBuilder.Strategy.REGRET); - iBuilder.setFastRegret(true); - - RegretInsertionFast regret = (RegretInsertionFast) iBuilder.build(); - DefaultScorer scoringFunction = new DefaultScorer(vrp); - scoringFunction.setDepotDistanceParam(0.00001); - scoringFunction.setTimeWindowParam(0); - regret.setScoringFunction(scoringFunction); - - /* - * ruin strategies - */ - RuinStrategy randomRuin = new RandomRuinStrategyFactory(0.5).createStrategy(vrp); - RuinStrategy radialRuin = new RadialRuinStrategyFactory(0.3, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())).createStrategy(vrp); - - /* - * objective function - */ - - RuinStrategy stringRuin = new RuinString(vrp, new AvgServiceAndShipmentDistance(vrp.getTransportCosts())); - - SolutionCostCalculator objectiveFunction = getObjectiveFunction(vrp); - - final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, 0.15); - IterationStartsListener schrimpfThreshold = new IterationStartsListener() { - @Override - public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { - if (i == 1) { - double initialThreshold = Solutions.bestOf(solutions).getCost() * 0.03; - schrimpfAcceptance.setInitialThreshold(initialThreshold); - } - } - }; - - SearchStrategy firstStrategy = new SearchStrategy("firstStrategy", new SelectBest(), schrimpfAcceptance, objectiveFunction); - firstStrategy.addModule(new RuinAndRecreateModule("randRuinRegretIns", regret, stringRuin)); - -// SearchStrategy secondStrategy = new SearchStrategy("secondStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction); -// secondStrategy.addModule(new RuinAndRecreateModule("radRuinRegretIns", regret, radialRuin)); - -// SearchStrategy thirdStrategy = new SearchStrategy("thirdStrategy", new SelectBest(), new GreedyAcceptance(1), objectiveFunction); -// secondStrategy.addModule(new RuinAndRecreateModule("radRuinBestIns", regret, radialRuin)); - - PrettyAlgorithmBuilder prettyAlgorithmBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fleetManager, stateManager, constraintManager); - final VehicleRoutingAlgorithm vra = prettyAlgorithmBuilder - .withStrategy(firstStrategy, 0.5) -// .withStrategy(secondStrategy, 0.5).withStrategy(thirdStrategy, 0.2) - .addCoreStateAndConstraintStuff() - .constructInitialSolutionWith(regret, objectiveFunction) - .build(); - - //if you want to switch on/off strategies or adapt their weight within the search, you can do the following - //e.g. from iteration 50 on, switch off first strategy - //switch on again at iteration 90 with slightly higher weight -// IterationStartsListener strategyAdaptor = new IterationStartsListener() { -// @Override -// public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { -// if (i == 50) { -// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.0); -// System.out.println("switched off firstStrategy"); -// } -// if (i == 90) { -// vra.getSearchStrategyManager().informStrategyWeightChanged("firstStrategy", 0.7); -// System.out.println("switched on firstStrategy again with higher weight"); -// } -// } -// }; -// vra.addListener(strategyAdaptor); - vra.addListener(schrimpfThreshold); - vra.addListener(schrimpfAcceptance); - return vra; - - } - - private static SolutionCostCalculator getObjectiveFunction(final VehicleRoutingProblem vrp) { - return new SolutionCostCalculator() { - - - @Override - public double getCosts(VehicleRoutingProblemSolution solution) { - SolutionAnalyser analyser = new SolutionAnalyser(vrp, solution, new TransportDistance() { - @Override - public double getDistance(Location from, Location to, double departureTime, Vehicle vehicle) { - return vrp.getTransportCosts().getTransportCost(from, to, 0., null, null); - } - }); - return analyser.getVariableTransportCosts() + solution.getUnassignedJobs().size() * 500.; - } - - }; - } - - -} From 3b24adc8fae16ecaa5b271f70b9e9679596c90fb Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 26 Apr 2017 15:36:09 +0200 Subject: [PATCH 064/106] make string ruin configurable --- .../com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index cf19a464..ce9dfd34 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -57,7 +57,7 @@ public final class RuinString extends AbstractRuinStrategy { private int lMin = 30; private int lMax = 60; - + public RuinString(VehicleRoutingProblem vrp, JobNeighborhoods jobNeighborhoods) { super(vrp); this.vrp = vrp; From 2d9be8304aafc0feb54aad5e616e656255f8a1cd Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 26 Apr 2017 15:39:27 +0200 Subject: [PATCH 065/106] Merge branch 'routebuilder-break-location' # Conflicts: # jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/solution/route/VehicleRoute.java --- .../jsprit/core/algorithm/box/Jsprit.java | 24 +++++++++---------- .../core/algorithm/ruin/RuinString.java | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 438344da..9c3c4080 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -122,10 +122,10 @@ public class Jsprit { MAX_TRANSPORT_COSTS("max_transport_costs"), CONSTRUCTION("construction"), BREAK_SCHEDULING("break_scheduling"), - STRING_KMIN("string_kmin"), - STRING_KMAX("string_kmax"), - STRING_LMIN("string_lmin"), - STRING_LMAX("string_lmax"); + STRING_K_MIN("string_kmin"), + STRING_K_MAX("string_kmax"), + STRING_L_MIN("string_lmin"), + STRING_L_MAX("string_lmax"); String paraName; @@ -189,10 +189,10 @@ public class Jsprit { defaults.put(Strategy.STRING_BEST.toString(), "0.0"); defaults.put(Strategy.STRING_REGRET.toString(), "0.0"); - defaults.put(Parameter.STRING_KMIN.toString(), "1"); - defaults.put(Parameter.STRING_KMAX.toString(), "6"); - defaults.put(Parameter.STRING_LMIN.toString(), "10"); - defaults.put(Parameter.STRING_LMAX.toString(), "30"); + defaults.put(Parameter.STRING_K_MIN.toString(), "1"); + defaults.put(Parameter.STRING_K_MAX.toString(), "6"); + defaults.put(Parameter.STRING_L_MIN.toString(), "10"); + defaults.put(Parameter.STRING_L_MAX.toString(), "30"); defaults.put(Strategy.WORST_BEST.toString(), "0."); defaults.put(Strategy.WORST_REGRET.toString(), "1."); @@ -490,10 +490,10 @@ public class Jsprit { random) ); - int kMin = toInteger(properties.getProperty(Parameter.STRING_KMIN.toString())); - int kMax = toInteger(properties.getProperty(Parameter.STRING_KMAX.toString())); - int lMin = toInteger(properties.getProperty(Parameter.STRING_LMIN.toString())); - int lMax = toInteger(properties.getProperty(Parameter.STRING_LMAX.toString())); + int kMin = toInteger(properties.getProperty(Parameter.STRING_K_MIN.toString())); + int kMax = toInteger(properties.getProperty(Parameter.STRING_K_MAX.toString())); + int lMin = toInteger(properties.getProperty(Parameter.STRING_L_MIN.toString())); + int lMax = toInteger(properties.getProperty(Parameter.STRING_L_MAX.toString())); final RuinString stringRuin = new RuinString(vrp, jobNeighborhoods); stringRuin.setNoRoutes(kMin, kMax); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index ce9dfd34..8341ddd4 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -31,13 +31,13 @@ import java.util.*; /** * RuinString is adopted from - * + *

* Technical report 7.11.2016 * A Fresh Ruin & Recreate Implementation for the Capacitated Vehicle Routing Problem * Jan Christiaens, Greet Vanden Berghe * KU Leuven, Department of Computer Science, CODeS & iMinds-ITEC * Gebr. De Smetstraat 1, 9000 Gent, Belgium, jan.christiaens@cs.kuleuven.be, greet.vandenberghe@cs.kuleuven.be - * + *

* https://lirias.kuleuven.be/bitstream/123456789/556398/1/asb_rr_2016.pdf * * @author stefan From b694c32d41eeb5e21e1dbc545bf78b0951663689 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 26 Apr 2017 17:03:42 +0200 Subject: [PATCH 066/106] streamline RuinString --- .../graphhopper/jsprit/core/algorithm/ruin/RuinString.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index 8341ddd4..ff6155ee 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -44,11 +44,11 @@ import java.util.*; */ public final class RuinString extends AbstractRuinStrategy { - private Logger logger = LoggerFactory.getLogger(RuinString.class); + private static Logger logger = LoggerFactory.getLogger(RuinString.class); - private VehicleRoutingProblem vrp; + private final VehicleRoutingProblem vrp; - private JobNeighborhoods jobNeighborhoods; + private final JobNeighborhoods jobNeighborhoods; private int kMin = 1; From 7a8d9ee841933db9f145731545faa2f7101e1129 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 27 Apr 2017 20:16:33 +0200 Subject: [PATCH 067/106] extend Jsprit.Builder to easily add custom search strategies --- .../jsprit/core/algorithm/box/Jsprit.java | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 9c3c4080..724c989b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -46,9 +46,7 @@ import com.graphhopper.jsprit.core.util.NoiseMaker; import com.graphhopper.jsprit.core.util.RandomNumberGeneration; import com.graphhopper.jsprit.core.util.Solutions; -import java.util.Collection; -import java.util.Properties; -import java.util.Random; +import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -170,6 +168,10 @@ public class Jsprit { private ScoringFunction regretScorer = null; + private Map customStrategies = new HashMap<>(); + + private VehicleFleetManager fleetManager = null; + public static Builder newInstance(VehicleRoutingProblem vrp) { return new Builder(vrp); } @@ -234,6 +236,16 @@ public class Jsprit { } + public Builder addSearchStrategy(SearchStrategy searchStrategy, double weight) { + customStrategies.put(searchStrategy, weight); + return this; + } + + public Builder setVehicleFleetManager(VehicleFleetManager fleetManager) { + this.fleetManager = fleetManager; + return this; + } + public Builder setExecutorService(ExecutorService es, int noThreads) { this.es = es; this.noThreads = noThreads; @@ -355,6 +367,10 @@ public class Jsprit { private ScoringFunction regretScorer; + private final Map customStrategies = new HashMap<>(); + + private VehicleFleetManager vehicleFleetManager; + private Jsprit(Builder builder) { this.stateManager = builder.stateManager; this.constraintManager = builder.constraintManager; @@ -367,6 +383,8 @@ public class Jsprit { this.activityInsertion = builder.activityInsertionCalculator; this.acceptor = builder.solutionAcceptor; regretScorer = builder.regretScorer; + customStrategies.putAll(builder.customStrategies); + vehicleFleetManager = builder.fleetManager; } private void ini(VehicleRoutingProblem vrp) { @@ -375,13 +393,14 @@ public class Jsprit { private VehicleRoutingAlgorithm create(final VehicleRoutingProblem vrp) { ini(vrp); - VehicleFleetManager fm; - if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) { - fm = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); - } else { - FiniteFleetManagerFactory finiteFleetManagerFactory = new FiniteFleetManagerFactory(vrp.getVehicles()); - finiteFleetManagerFactory.setRandom(random); - fm = finiteFleetManagerFactory.createFleetManager(); + if (vehicleFleetManager == null) { + if (vrp.getFleetSize().equals(VehicleRoutingProblem.FleetSize.INFINITE)) { + vehicleFleetManager = new InfiniteFleetManagerFactory(vrp.getVehicles()).createFleetManager(); + } else { + FiniteFleetManagerFactory finiteFleetManagerFactory = new FiniteFleetManagerFactory(vrp.getVehicles()); + finiteFleetManagerFactory.setRandom(random); + vehicleFleetManager = finiteFleetManagerFactory.createFleetManager(); + } } if (stateManager == null) { @@ -506,7 +525,7 @@ public class Jsprit { boolean fastRegret = Boolean.parseBoolean(getProperty(Parameter.FAST_REGRET.toString())); if (es != null) { if(fastRegret){ - RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager) + RegretInsertionConcurrentFast regretInsertion = (RegretInsertionConcurrentFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setConcurrentMode(es, noThreads) .setFastRegret(true) @@ -520,7 +539,7 @@ public class Jsprit { regret = regretInsertion; } else { - RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager) + RegretInsertionConcurrent regretInsertion = (RegretInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setConcurrentMode(es, noThreads) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) @@ -533,7 +552,7 @@ public class Jsprit { } } else { if(fastRegret) { - RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, fm, stateManager, constraintManager) + RegretInsertionFast regretInsertion = (RegretInsertionFast) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setFastRegret(true) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) @@ -546,7 +565,7 @@ public class Jsprit { regret = regretInsertion; } else{ - RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager) + RegretInsertion regretInsertion = (RegretInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) .setInsertionStrategy(InsertionBuilder.Strategy.REGRET) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) .considerFixedCosts(toDouble(getProperty(Parameter.FIXED_COST_PARAM.toString()))) @@ -561,7 +580,7 @@ public class Jsprit { AbstractInsertionStrategy best; if (vrp.getJobs().size() < 250 || es == null) { - BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, fm, stateManager, constraintManager) + BestInsertion bestInsertion = (BestInsertion) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) .setInsertionStrategy(InsertionBuilder.Strategy.BEST) .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) @@ -569,7 +588,7 @@ public class Jsprit { .build(); best = bestInsertion; } else { - BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, fm, stateManager, constraintManager) + BestInsertionConcurrent bestInsertion = (BestInsertionConcurrent) new InsertionBuilder(vrp, vehicleFleetManager, stateManager, constraintManager) .setInsertionStrategy(InsertionBuilder.Strategy.BEST) .considerFixedCosts(Double.valueOf(properties.getProperty(Parameter.FIXED_COST_PARAM.toString()))) .setAllowVehicleSwitch(toBoolean(getProperty(Parameter.VEHICLE_SWITCH.toString()))) @@ -626,7 +645,7 @@ public class Jsprit { SearchStrategy stringBest = new SearchStrategy(Strategy.STRING_BEST.toString(), new SelectBest(), acceptor, objectiveFunction); stringBest.addModule(new RuinAndRecreateModule(Strategy.STRING_BEST.toString(), best, stringRuin)); - PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, fm, stateManager, constraintManager); + PrettyAlgorithmBuilder prettyBuilder = PrettyAlgorithmBuilder.newInstance(vrp, vehicleFleetManager, stateManager, constraintManager); prettyBuilder.setRandom(random); if (addCoreConstraints) { prettyBuilder.addCoreStateAndConstraintStuff(); @@ -642,6 +661,10 @@ public class Jsprit { .withStrategy(stringBest, toDouble(getProperty(Strategy.STRING_BEST.toString()))) .withStrategy(stringRegret, toDouble(getProperty(Strategy.STRING_REGRET.toString()))); + for (SearchStrategy customStrategy : customStrategies.keySet()) { + prettyBuilder.withStrategy(customStrategy, customStrategies.get(customStrategy)); + } + if (getProperty(Parameter.CONSTRUCTION.toString()).equals(Construction.BEST_INSERTION.toString())) { prettyBuilder.constructInitialSolutionWith(best, objectiveFunction); } else { From 4b9501bf257cb77489a1d9e3d2922369e0ecca6a Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 27 Apr 2017 20:17:13 +0200 Subject: [PATCH 068/106] remove unnecessary public --- .../jsprit/core/algorithm/recreate/ScoringFunction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoringFunction.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoringFunction.java index 63c44a35..d3c6e103 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoringFunction.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/ScoringFunction.java @@ -25,6 +25,6 @@ import com.graphhopper.jsprit.core.problem.job.Job; */ public interface ScoringFunction { - public double score(InsertionData best, Job job); + double score(InsertionData best, Job job); } From 99bcbcf1e1495a8607aa9ab53e2313f0adb6821f Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 27 Apr 2017 21:36:39 +0200 Subject: [PATCH 069/106] remove unnecessary stuff --- .../toolbox/ComputationalLaboratory.java | 475 ------------------ .../jsprit/analysis/util/BenchmarkWriter.java | 26 - .../util/HtmlBenchmarkTableWriter.java | 257 ---------- 3 files changed, 758 deletions(-) delete mode 100644 jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/ComputationalLaboratory.java delete mode 100644 jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/BenchmarkWriter.java delete mode 100644 jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/HtmlBenchmarkTableWriter.java diff --git a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/ComputationalLaboratory.java b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/ComputationalLaboratory.java deleted file mode 100644 index c1a46be9..00000000 --- a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/ComputationalLaboratory.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.graphhopper.jsprit.analysis.toolbox; - -import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithm; -import com.graphhopper.jsprit.core.algorithm.VehicleRoutingAlgorithmFactory; -import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; -import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; -import com.graphhopper.jsprit.core.util.BenchmarkInstance; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - - -public class ComputationalLaboratory { - - public static interface LabListener { - - } - - /** - * Listener-interface to listen to calculation. - *

- *

Note that calculations are run concurrently, i.e. a unique task that is distributed to an available thread is - * {algorithm, instance, run}. - * - * @author schroeder - */ - 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 solutions); - - } - - public static interface LabStartsAndEndsListener extends LabListener { - - public void labStarts(List instances, int noAlgorithms, int runs); - - 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 data = new ConcurrentHashMap(); - - private ConcurrentHashMap solutions = new ConcurrentHashMap(); - - /** - * Adds a single date by instanceName, algorithmName, run and indicatorName. - *

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 getData(String instanceName, String algorithmName, String indicator) { - List values = new ArrayList(); - 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 getDataKeySet() { - return data.keySet(); - } - - public Set getSolutionKeySet() { - return solutions.keySet(); - } - - public VehicleRoutingProblemSolution getSolution(Key solutionKey) { - return solutions.get(solutionKey); - } - - public Collection 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 benchmarkInstances = new ArrayList(); - - private int runs = 1; - - private Collection listeners = new ArrayList(); - - private Collection startsAndEndslisteners = new ArrayList(); - - private List algorithms = new ArrayList(); - - private Set algorithmNames = new HashSet(); - - private Set instanceNames = new HashSet(); - - 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 getAlgorithmNames() { - return algorithmNames; - } - - public Collection 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 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. - *

Default is 1 - * - * @param runs - */ - public void setNuOfRuns(int runs) { - this.runs = runs; - } - - /** - * Runs experiments. - *

- *

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. - *

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. - *

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; - try { - executor.submit(new Runnable() { - - @Override - public void run() { - runAlgorithm(p, algorithm, r + 1); - } - - }); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - } - try { - executor.shutdown(); - executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MINUTES); - - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - System.out.println("benchmarking done [time=" + (System.currentTimeMillis() - startTime) / 1000 + "sec]"); - informEnd(); - } - - private void informEnd() { - for (LabStartsAndEndsListener l : startsAndEndslisteners) { - l.labEnds(); - } - } - - private void informStart() { - for (LabStartsAndEndsListener l : startsAndEndslisteners) { - l.labStarts(benchmarkInstances, algorithms.size(), runs); - } - } - - /** - * Sets number of threads. - *

By default: nuThreads = Runtime.getRuntime().availableProcessors()+1 - * - * @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]"); - VehicleRoutingAlgorithm vra = algorithm.factory.createAlgorithm(p.vrp); - informCalculationStarts(p, algorithm.name, vra, run); - Collection solutions = vra.searchSolutions(); - System.out.println("[algorithm=" + algorithm.name + "][instance=" + p.name + "][run=" + run + "][status=finished]"); - informCalculationsEnds(p, algorithm.name, vra, run, solutions); - } - - private void informCalculationStarts(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run) { - for (CalculationListener l : listeners) l.calculationStarts(p, name, vra, run); - } - - private void informCalculationsEnds(BenchmarkInstance p, String name, VehicleRoutingAlgorithm vra, int run, - Collection solutions) { - for (CalculationListener l : listeners) l.calculationEnds(p, name, vra, run, solutions); - } - -} diff --git a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/BenchmarkWriter.java b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/BenchmarkWriter.java deleted file mode 100644 index 7555f8cc..00000000 --- a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/BenchmarkWriter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.graphhopper.jsprit.analysis.util; - -import com.graphhopper.jsprit.core.util.BenchmarkResult; - -import java.util.Collection; - -public interface BenchmarkWriter { - public void write(Collection results); -} diff --git a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/HtmlBenchmarkTableWriter.java b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/HtmlBenchmarkTableWriter.java deleted file mode 100644 index b8520e7e..00000000 --- a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/util/HtmlBenchmarkTableWriter.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Licensed to GraphHopper GmbH under one or more contributor - * license agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * - * GraphHopper GmbH licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.graphhopper.jsprit.analysis.util; - -import com.graphhopper.jsprit.core.util.BenchmarkResult; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.Collection; - -public class HtmlBenchmarkTableWriter implements BenchmarkWriter { - - private String filename; - - public HtmlBenchmarkTableWriter(String filename) { - this.filename = filename; - } - - @Override - public void write(Collection 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("Ø 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("Ø") + 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 "" + string + ""; - } - - 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 "" + head + ""; - } - - private String closeTable() { - return ""; - } - - private String openTable() { - return ""; - } - - private String closeRow() { - return ""; - } - - private String date(String date) { - return ""; - } - - private String date(String date, String metaData) { - return ""; - } - - private String newline() { - return "\n"; - } - - private String openRow() { - return ""; - } - - -} From 3213765b50d771e895a2003230f8cb51441fa8b5 Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 5 May 2017 16:37:11 +0200 Subject: [PATCH 070/106] improve RuinString --- .../jsprit/core/algorithm/ruin/RuinString.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java index ff6155ee..8452dde2 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/ruin/RuinString.java @@ -89,7 +89,9 @@ public final class RuinString extends AbstractRuinStrategy { if (vehicleRoutes.isEmpty() || vrp.getJobs().isEmpty()) { return Collections.emptyList(); } - int noStrings = kMin + random.nextInt((kMax - kMin)); + int noStrings; + if (kMin == kMax) noStrings = kMax; + else noStrings = kMin + random.nextInt((kMax - kMin)); noStrings = Math.min(noStrings, vehicleRoutes.size()); Set unassignedJobs = new HashSet<>(); Set ruinedRoutes = new HashSet<>(); @@ -121,7 +123,9 @@ public final class RuinString extends AbstractRuinStrategy { private void ruinRouteWithSplitStringRuin(VehicleRoute seedRoute, Job prevJob, Set unassignedJobs) { int noActivities = seedRoute.getActivities().size(); - int stringLength = lMin + random.nextInt(lMax - lMin); + int stringLength; + if (lMin == lMax) stringLength = lMin; + else stringLength = lMin + random.nextInt(lMax - lMin); stringLength = Math.min(stringLength, seedRoute.getActivities().size()); int preservedSubstringLength = StringUtil.determineSubstringLength(stringLength, noActivities, random); From c1c140e683921bc1b8794579b9ca19f157916dd8 Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 5 May 2017 16:37:50 +0200 Subject: [PATCH 071/106] analyse effects of strategies --- .../analysis/toolbox/StrategyAnalyser.java | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/StrategyAnalyser.java diff --git a/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/StrategyAnalyser.java b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/StrategyAnalyser.java new file mode 100644 index 00000000..522df545 --- /dev/null +++ b/jsprit-analysis/src/main/java/com/graphhopper/jsprit/analysis/toolbox/StrategyAnalyser.java @@ -0,0 +1,162 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.analysis.toolbox; + +import com.graphhopper.jsprit.core.algorithm.SearchStrategy; +import com.graphhopper.jsprit.core.algorithm.listener.AlgorithmEndsListener; +import com.graphhopper.jsprit.core.algorithm.listener.IterationStartsListener; +import com.graphhopper.jsprit.core.algorithm.listener.StrategySelectedListener; +import com.graphhopper.jsprit.core.problem.VehicleRoutingProblem; +import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.*; + +/** + * Created by schroeder on 27/04/17. + */ +public class StrategyAnalyser implements AlgorithmEndsListener, StrategySelectedListener, IterationStartsListener { + + + public static class Strategy { + + private final String id; + + private int selected = 0; + + private int improved = 0; + + private int countNewSolution = 0; + + private List improvements = new ArrayList<>(); + + public Strategy(String id) { + this.id = id; + } + + public void selected() { + selected++; + } + + public void improvedSolution(double improvement) { + improved++; + improvements.add(improvement); + } + + public void newSolution() { + countNewSolution++; + } + + public String getId() { + return id; + } + + public int getCountSelected() { + return selected; + } + + public int getCountImproved() { + return improved; + } + + public int getCountNewSolution() { + return countNewSolution; + } + + public List getImprovements() { + return improvements; + } + } + + private Map strategyMap = new HashMap<>(); + + private Collection last; + + private Writer out; + + @Override + public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { + last = new ArrayList<>(solutions); + } + + @Override + public void informSelectedStrategy(SearchStrategy.DiscoveredSolution discoveredSolution, VehicleRoutingProblem vehicleRoutingProblem, Collection vehicleRoutingProblemSolutions) { + String strategyId = discoveredSolution.getStrategyId(); + if (!strategyMap.containsKey(strategyId)) { + strategyMap.put(strategyId, new Strategy(strategyId)); + } + Strategy strategy = strategyMap.get(strategyId); + strategy.selected(); + if (discoveredSolution.isAccepted()) strategy.newSolution(); + if (isBetter(vehicleRoutingProblemSolutions, last)) { + strategy.improvedSolution(getImprovement(vehicleRoutingProblemSolutions, last)); + + } + } + + public void setOutWriter(Writer out) { + this.out = out; + } + + @Override + public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection solutions) { + if (out == null) out = new PrintWriter(System.out); + try { + for (String stratId : strategyMap.keySet()) { + StrategyAnalyser.Strategy strategy = strategyMap.get(stratId); + out.write("id: " + stratId + ", #selected: " + strategy.getCountSelected() + ", #newSolutions: " + strategy.getCountNewSolution() + + ", #improvedSolutions: " + strategy.getCountImproved() + ", improvements: " + strategy.getImprovements().toString() + "\n"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + try { + out.flush(); + out.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private double getImprovement(Collection vehicleRoutingProblemSolutions, Collection last) { + for (VehicleRoutingProblemSolution solution : vehicleRoutingProblemSolutions) { + for (VehicleRoutingProblemSolution lastSolution : last) { + if (solution.getCost() < lastSolution.getCost()) + return Math.round(lastSolution.getCost() - solution.getCost()); + } + } + return 0; + } + + private boolean isBetter(Collection vehicleRoutingProblemSolutions, Collection last) { + for (VehicleRoutingProblemSolution solution : vehicleRoutingProblemSolutions) { + for (VehicleRoutingProblemSolution lastSolution : last) { + if (solution.getCost() < lastSolution.getCost()) return true; + } + } + return false; + } + + public Map getStrategies() { + return strategyMap; + } +} From da9b6029351e898a64b7908892559da8e3b1d25a Mon Sep 17 00:00:00 2001 From: Jitendra Singh Date: Wed, 10 May 2017 21:22:04 +0530 Subject: [PATCH 072/106] markdown syntax correct --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 574004a7..c4d58af5 100644 --- a/README.md +++ b/README.md @@ -18,19 +18,19 @@ It is lightweight, flexible and easy-to-use, and based on a single all-purpose < Setting up the problem, defining additional constraints, modifying the algorithms and visualising the discovered solutions is as easy and handy as reading classical VRP instances to benchmark your algorithm. It is fit for change and extension due to a modular design and a comprehensive set of unit and integration-tests. [More features ...](https://github.com/jsprit/jsprit/wiki/features) -##Getting Started and Documentation +## Getting Started and Documentation Please visit [docs](https://github.com/graphhopper/jsprit/blob/master/docs/Home.md) to learn more. For older versions (jsprit then it is easier to keep track of your topic. -####Issue Tracker: +#### Issue Tracker: For bugs, feature requests or similar use the [issue tracker](https://github.com/jsprit/jsprit/issues). -####Email: +#### Email: If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, contact us via https://graphhopper.com/#contact -##About +## About The jsprit-project has been created by [Stefan Schröder](https://github.com/oblonski) and is maintained by [GraphHopper](https://graphhopper.com/). It is motivated by two issues. First, you can find vehicle routing problems **everywhere** in the world of distributing and moving things and people. This probably explains why there is an almost endless list of papers and algorithms to tackle these problems. However, there are only [very few open source implementations](https://github.com/graphhopper/jsprit/blob/master/docs/Other-Projects.md) and even fewer projects that can deal with real world problems that usually have many side-constraints. From 2a1665720e9af64926d1826ccf1e888af8be6a2a Mon Sep 17 00:00:00 2001 From: Jitendra Singh Date: Wed, 10 May 2017 21:23:11 +0530 Subject: [PATCH 073/106] one more fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4d58af5..27b2fedf 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Any contribution is welcome. Feel free to improve jsprit and make pull requests. See who has contributed [here](https://github.com/jsprit/jsprit/blob/master/CONTRIBUTORS.md). -##Acknowledgement +## Acknowledgement Developing this would be much more difficult without the help of [these companies](https://github.com/graphhopper/jsprit/blob/master/docs/Acknowledgement.md). ## Contact From 69537d109c866c36ec920f65652150b6a264685e Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 11 May 2017 16:42:48 +0200 Subject: [PATCH 074/106] add option to set abs. initial threshold --- .../jsprit/core/algorithm/box/Jsprit.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java index 724c989b..14e33fd3 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/box/Jsprit.java @@ -112,6 +112,7 @@ public class Jsprit { WORST_MAX_SHARE("worst.max_share"), THRESHOLD_ALPHA("threshold.alpha"), THRESHOLD_INI("threshold.ini"), + THRESHOLD_INI_ABS("threshold.ini_abs"), INSERTION_NOISE_LEVEL("insertion.noise_level"), INSERTION_NOISE_PROB("insertion.noise_prob"), RUIN_WORST_NOISE_LEVEL("worst.noise_level"), @@ -602,15 +603,19 @@ public class Jsprit { IterationStartsListener schrimpfThreshold = null; if(acceptor == null) { final SchrimpfAcceptance schrimpfAcceptance = new SchrimpfAcceptance(1, toDouble(getProperty(Parameter.THRESHOLD_ALPHA.toString()))); - schrimpfThreshold = new IterationStartsListener() { - @Override - public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { - if (i == 1) { - double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString())); - schrimpfAcceptance.setInitialThreshold(initialThreshold); + if (properties.containsKey(Parameter.THRESHOLD_INI_ABS.toString())) { + schrimpfAcceptance.setInitialThreshold(Double.valueOf(properties.getProperty(Parameter.THRESHOLD_INI_ABS.toString()))); + } else { + schrimpfThreshold = new IterationStartsListener() { + @Override + public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { + if (i == 1) { + double initialThreshold = Solutions.bestOf(solutions).getCost() * toDouble(getProperty(Parameter.THRESHOLD_INI.toString())); + schrimpfAcceptance.setInitialThreshold(initialThreshold); + } } - } - }; + }; + } acceptor = schrimpfAcceptance; } From 8ca85f13ba3ededef3d232fd604611e71e8362f8 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 11 May 2017 16:43:28 +0200 Subject: [PATCH 075/106] add unassignedReason tests --- .../core/algorithm/UnassignedJobListTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/UnassignedJobListTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/UnassignedJobListTest.java index ce7eed83..49c524b6 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/UnassignedJobListTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/algorithm/UnassignedJobListTest.java @@ -26,14 +26,17 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; import com.graphhopper.jsprit.core.problem.vehicle.VehicleImpl; import com.graphhopper.jsprit.core.util.Solutions; +import com.graphhopper.jsprit.core.util.UnassignedJobReasonTracker; import org.junit.Test; import java.util.Collection; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class UnassignedJobListTest { + @Test public void job2ShouldBeInBadJobList_dueToTimeWindow() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); @@ -46,11 +49,17 @@ public class UnassignedJobListTest { VehicleRoutingProblem vrp = builder.build(); VehicleRoutingAlgorithm algorithm = new GreedySchrimpfFactory().createAlgorithm(vrp); algorithm.setMaxIterations(10); + + UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker(); + algorithm.addListener(reasonTracker); + Collection solutions = algorithm.searchSolutions(); VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); + assertTrue(!solution.getUnassignedJobs().contains(job1)); assertTrue(solution.getUnassignedJobs().contains(job2)); + assertEquals(2, reasonTracker.getMostLikelyReasonCode("job2")); } @Test @@ -63,13 +72,19 @@ public class UnassignedJobListTest { builder.addJob(job2); VehicleRoutingProblem vrp = builder.build(); + VehicleRoutingAlgorithm algorithm = new GreedySchrimpfFactory().createAlgorithm(vrp); algorithm.setMaxIterations(10); + + UnassignedJobReasonTracker reasonTracker = new UnassignedJobReasonTracker(); + algorithm.addListener(reasonTracker); + Collection solutions = algorithm.searchSolutions(); VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions); assertTrue(!solution.getUnassignedJobs().contains(job1)); assertTrue(solution.getUnassignedJobs().contains(job2)); + assertEquals(3, reasonTracker.getMostLikelyReasonCode("job2")); } } From a7c0766488e4aedc7b1da4adf0d7b7f0eef3bde5 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 11 May 2017 16:57:54 +0200 Subject: [PATCH 076/106] change dev version --- jsprit-analysis/pom.xml | 2 +- jsprit-core/pom.xml | 2 +- jsprit-examples/pom.xml | 2 +- jsprit-instances/pom.xml | 2 +- jsprit-io/pom.xml | 2 +- pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/jsprit-analysis/pom.xml b/jsprit-analysis/pom.xml index 409ef69d..eda298d3 100644 --- a/jsprit-analysis/pom.xml +++ b/jsprit-analysis/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT 4.0.0 jsprit-analysis diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml index d20a01b6..059d59f4 100644 --- a/jsprit-core/pom.xml +++ b/jsprit-core/pom.xml @@ -21,7 +21,7 @@ com.graphhopper jsprit - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT 4.0.0 jsprit-core diff --git a/jsprit-examples/pom.xml b/jsprit-examples/pom.xml index 23457bb6..2aec0c75 100644 --- a/jsprit-examples/pom.xml +++ b/jsprit-examples/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT 4.0.0 diff --git a/jsprit-instances/pom.xml b/jsprit-instances/pom.xml index 7d31f92e..777a8124 100644 --- a/jsprit-instances/pom.xml +++ b/jsprit-instances/pom.xml @@ -20,7 +20,7 @@ com.graphhopper jsprit - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT 4.0.0 diff --git a/jsprit-io/pom.xml b/jsprit-io/pom.xml index 257aed74..509374ae 100644 --- a/jsprit-io/pom.xml +++ b/jsprit-io/pom.xml @@ -23,7 +23,7 @@ com.graphhopper jsprit - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 773d477a..388731a9 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ com.graphhopper jsprit - 1.7.1-SNAPSHOT + 1.7.2-SNAPSHOT pom From 1f4f9a0e58cb339469db0d7b751b934672e21846 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 11 May 2017 17:05:08 +0200 Subject: [PATCH 077/106] v1.7.1 --- CHANGELOG.md | 3 +++ WHATS_NEW.md | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd6636b6..ddfd80ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ Change-log ========== +**v1.7.1** @ 2017-05-11 +- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md) + **v1.7** @ 2017-01-12 - see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md) diff --git a/WHATS_NEW.md b/WHATS_NEW.md index 04e27c30..44d2a30a 100644 --- a/WHATS_NEW.md +++ b/WHATS_NEW.md @@ -1,6 +1,11 @@ WHATS NEW ========== ------------------------------ +2017-05-11 new release **v1.7.1** +- determine [reasons for unassigned jobs](https://github.com/graphhopper/jsprit/issues/180) +- extend priority levels from 3 to 10 levels +- a number of minor improvements + 2017-01-12 new release **v1.7** - move packages to [graphhopper.com](https://graphhopper.com/) - change license from GPLv3 to [Apache v2](https://github.com/graphhopper/jsprit/blob/master/LICENSE.md) to make it even more attractive for other developers and their commercial applications From 8eab987c1f0a4a8bbe2cabec86e10ec9de75dffa Mon Sep 17 00:00:00 2001 From: jsroyal Date: Mon, 15 May 2017 00:39:03 +0530 Subject: [PATCH 078/106] fixed the broken link --- docs/Classical-Problems-Examples.md | 18 +++++++++--------- docs/Getting-Started.md | 17 +++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/Classical-Problems-Examples.md b/docs/Classical-Problems-Examples.md index 67e44f95..2ae34087 100644 --- a/docs/Classical-Problems-Examples.md +++ b/docs/Classical-Problems-Examples.md @@ -1,9 +1,9 @@ -- Capacitated VRP -- Multiple Depot VRP -- VRP with Time Windows -- VRP with Backhauls (Deliveries first) -- VRP with Backhauls (mixed Pickups and Deliveries) -- VRP with Pickups and Deliveries -- VRP with Heterogeneous Fleet -- Traveling Salesman Problem -- Dial-a-Ride Problem \ No newline at end of file +- Capacitated VRP +- Multiple Depot VRP +- VRP with Time Windows +- VRP with Backhauls (Deliveries first) +- VRP with Backhauls (mixed Pickups and Deliveries) +- VRP with Pickups and Deliveries +- VRP with Heterogeneous Fleet +- Traveling Salesman Problem +- Dial-a-Ride Problem \ No newline at end of file diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index ac5af692..492c2697 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -1,7 +1,7 @@ -####Requirements +#### Requirements jsprit requires Java 1.7.0 or later. -####Modules +#### Modules jsprit is a multi-module project and consists of: - jsprit-core - jsprit-analysis @@ -9,19 +9,20 @@ jsprit is a multi-module project and consists of: - jsprit-examples - jsprit-io -####Maven way +#### Maven way If you want to use the latest release of jsprit-core, add the following lines to your pom: -
<dependency>
+```
+<dependency>
    <groupId>com.graphhopper</groupId>
    <artifactId>jsprit-core</artifactId>
    <version>{version}</version>
 </dependency>
-
+``` -Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core). +Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core) -####Build yourself +#### Build yourself If you want to build the master branch yourself, do this: ``` @@ -30,7 +31,7 @@ cd jsprit mvn clean install ``` -####If you do not have an IDE and you want to use Maven +#### If you do not have an IDE and you want to use Maven the following documentation is recommended: From b9da9b9a06e5e333bfb0700197f89c84f9529325 Mon Sep 17 00:00:00 2001 From: oblonski Date: Tue, 16 May 2017 20:50:08 +0200 Subject: [PATCH 079/106] make reason tracker more robust --- .../jsprit/core/util/UnassignedJobReasonTracker.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index 34873590..0a999953 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -114,6 +114,7 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public int getMostLikelyReasonCode(String jobId) { + if (!this.reasons.containsKey(jobId)) return -1; Frequency reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); return toCode(mostLikelyReason); @@ -126,6 +127,7 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public String getMostLikelyReason(String jobId) { + if (!this.reasons.containsKey(jobId)) return "no reason found"; Frequency reasons = this.reasons.get(jobId); String mostLikelyReason = getMostLikely(reasons); int code = toCode(mostLikelyReason); @@ -140,6 +142,7 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { } private String getMostLikely(Frequency reasons) { + if (reasons == null) return "no reason found"; Iterator, Long>> entryIterator = reasons.entrySetIterator(); int maxCount = 0; String mostLikely = null; From bc752634451b97905d169565b3a7ccb224d2d851 Mon Sep 17 00:00:00 2001 From: Jitendra Singh Date: Sat, 20 May 2017 15:10:42 +0530 Subject: [PATCH 080/106] link fixed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 27b2fedf..d1f57293 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ jsprit [![Build Status](https://travis-ci.org/graphhopper/jsprit.svg?branch=master)](https://travis-ci.org/graphhopper/jsprit) jsprit is a java based, open source toolkit for solving rich traveling salesman (TSP) and vehicle routing problems (VRP). -It is lightweight, flexible and easy-to-use, and based on a single all-purpose meta-heuristic currently solving +It is lightweight, flexible and easy-to-use, and based on a single all-purpose meta-heuristic currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows From 770b4f8bda5429ca1f85f97fb149160d1e5ecef2 Mon Sep 17 00:00:00 2001 From: Jitendra Singh Date: Mon, 22 May 2017 13:38:53 +0530 Subject: [PATCH 081/106] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1f57293..6f4bb8ea 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ jsprit [![Build Status](https://travis-ci.org/graphhopper/jsprit.svg?branch=master)](https://travis-ci.org/graphhopper/jsprit) jsprit is a java based, open source toolkit for solving rich traveling salesman (TSP) and vehicle routing problems (VRP). -It is lightweight, flexible and easy-to-use, and based on a single all-purpose meta-heuristic currently solving +It is lightweight, flexible and easy-to-use, and based on a single all-purpose meta-heuristic currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows From c109fe676fe66afec56a097612365d517522f3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Vissy?= Date: Wed, 31 May 2017 22:51:56 +0200 Subject: [PATCH 082/106] #347 - Custom properties --- .../jsprit/core/problem/AbstractJob.java | 13 ++ .../jsprit/core/problem/AbstractVehicle.java | 41 +++- .../jsprit/core/problem/Location.java | 30 +++ .../jsprit/core/problem/job/Service.java | 49 ++-- .../jsprit/core/problem/job/Shipment.java | 29 ++- .../jsprit/core/problem/vehicle/Vehicle.java | 8 + .../core/problem/vehicle/VehicleImpl.java | 59 +++-- .../core/problem/vehicle/VehicleType.java | 9 + .../core/problem/vehicle/VehicleTypeImpl.java | 52 ++++- .../jsprit/core/problem/LocationTest.java | 23 +- .../jsprit/core/problem/job/DeliveryTest.java | 45 ++-- .../jsprit/core/problem/job/PickupTest.java | 44 ++-- .../jsprit/core/problem/job/ServiceTest.java | 209 ++++++++++-------- .../jsprit/core/problem/job/ShipmentTest.java | 162 ++++++++------ .../core/problem/vehicle/VehicleImplTest.java | 40 +++- .../problem/vehicle/VehicleTypeImplTest.java | 33 ++- 16 files changed, 583 insertions(+), 263 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractJob.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractJob.java index 81ef63e7..85a37e80 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractJob.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractJob.java @@ -26,7 +26,9 @@ import com.graphhopper.jsprit.core.problem.job.Job; public abstract class AbstractJob implements Job { private int index; + private Object userData; + @Override public int getIndex() { return index; } @@ -35,4 +37,15 @@ public abstract class AbstractJob implements Job { this.index = index; } + /** + * @return User-specific domain data associated by the job + */ + public Object getUserData() { + return userData; + } + + protected void setUserData(Object userData) { + this.userData = userData; + } + } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractVehicle.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractVehicle.java index bd259b4e..c8f69d2b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractVehicle.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/AbstractVehicle.java @@ -30,6 +30,7 @@ public abstract class AbstractVehicle implements Vehicle { private int index; + @Override public int getIndex() { return index; } @@ -44,19 +45,35 @@ public abstract class AbstractVehicle implements Vehicle { private VehicleTypeKey vehicleIdentifier; - public int getIndex() { - return index; - } + private Object userData; - protected void setIndex(int index) { - this.index = index; - } + /** + * @return User-specific domain data associated with the vehicle + */ + @Override + public Object getUserData() { + return userData; + } - public VehicleTypeKey getVehicleTypeIdentifier() { - return vehicleIdentifier; - } + protected void setUserData(Object userData) { + this.userData = userData; + } - protected void setVehicleIdentifier(VehicleTypeKey vehicleTypeIdentifier) { - this.vehicleIdentifier = vehicleTypeIdentifier; - } + @Override + public int getIndex() { + return index; + } + + protected void setIndex(int index) { + this.index = index; + } + + @Override + public VehicleTypeKey getVehicleTypeIdentifier() { + return vehicleIdentifier; + } + + protected void setVehicleIdentifier(VehicleTypeKey vehicleTypeIdentifier) { + this.vehicleIdentifier = vehicleTypeIdentifier; + } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java index f9721e15..233a71a9 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/Location.java @@ -66,10 +66,30 @@ public final class Location implements HasIndex, HasId { private String name = ""; + private Object userData; + public static Builder newInstance() { return new Builder(); } + /** + * Sets user specific domain data associated with the object. + * + *

+ * The user data is a black box for the framework, it only stores it, + * but never interacts with it in any way. + *

+ * + * @param userData + * any object holding the domain specific user data + * associated with the object. + * @return builder + */ + public Builder setUserData(Object userData) { + this.userData = userData; + return this; + } + /** * Sets location index * @@ -140,13 +160,23 @@ public final class Location implements HasIndex, HasId { private final String name; + private Object userData; + private Location(Builder builder) { + this.userData = builder.userData; this.index = builder.index; this.coordinate = builder.coordinate; this.id = builder.id; this.name = builder.name; } + /** + * @return User-specific domain data associated by the job + */ + public Object getUserData() { + return userData; + } + @Override public String getId() { return id; diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java index 11be0994..57ed0639 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Service.java @@ -17,6 +17,8 @@ */ package com.graphhopper.jsprit.core.problem.job; +import java.util.Collection; + import com.graphhopper.jsprit.core.problem.AbstractJob; import com.graphhopper.jsprit.core.problem.Capacity; import com.graphhopper.jsprit.core.problem.Location; @@ -26,8 +28,6 @@ import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindows; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl; import com.graphhopper.jsprit.core.util.Coordinate; -import java.util.Collection; - /** * Service implementation of a job. *

@@ -86,15 +86,16 @@ public class Service extends AbstractJob { protected TimeWindowsImpl timeWindows; - private boolean twAdded = false; + private boolean twAdded = false; private int priority = 2; + protected Object userData; - Builder(String id){ - this.id = id; - timeWindows = new TimeWindowsImpl(); - timeWindows.add(timeWindow); - } + Builder(String id){ + this.id = id; + timeWindows = new TimeWindowsImpl(); + timeWindows.add(timeWindow); + } /** * Protected method to set the type-name of the service. @@ -137,6 +138,24 @@ public class Service extends AbstractJob { return this; } + /** + * Sets user specific domain data associated with the object. + * + *

+ * The user data is a black box for the framework, it only stores it, + * but never interacts with it in any way. + *

+ * + * @param userData + * any object holding the domain specific user data + * associated with the object. + * @return builder + */ + public Builder setUserData(Object userData) { + this.userData = userData; + return this; + } + /** * Adds capacity dimension. * @@ -247,7 +266,8 @@ public class Service extends AbstractJob { private final int priority; - Service(Builder builder) { + Service(Builder builder) { + setUserData(builder.userData); id = builder.id; serviceTime = builder.serviceTime; timeWindow = builder.timeWindow; @@ -256,13 +276,13 @@ public class Service extends AbstractJob { skills = builder.skills; name = builder.name; location = builder.location; - timeWindowManager = builder.timeWindows; + timeWindowManager = builder.timeWindows; priority = builder.priority; - } + } - public Collection getTimeWindows(){ - return timeWindowManager.getTimeWindows(); - } + public Collection getTimeWindows(){ + return timeWindowManager.getTimeWindows(); + } @Override public String getId() { @@ -367,6 +387,7 @@ public class Service extends AbstractJob { * * @return priority */ + @Override public int getPriority() { return priority; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java index 6b8bde5d..b2281fe2 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/job/Shipment.java @@ -17,6 +17,8 @@ */ package com.graphhopper.jsprit.core.problem.job; +import java.util.Collection; + import com.graphhopper.jsprit.core.problem.AbstractJob; import com.graphhopper.jsprit.core.problem.Capacity; import com.graphhopper.jsprit.core.problem.Location; @@ -24,8 +26,6 @@ import com.graphhopper.jsprit.core.problem.Skills; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindowsImpl; -import java.util.Collection; - /** * Shipment is an implementation of Job and consists of a pickup and a delivery of something. @@ -89,6 +89,8 @@ public class Shipment extends AbstractJob { private int priority = 2; + public Object userData; + /** * Returns new instance of this builder. * @@ -108,10 +110,29 @@ public class Shipment extends AbstractJob { deliveryTimeWindows.add(deliveryTimeWindow); } + /** + * Sets user specific domain data associated with the object. + * + *

+ * The user data is a black box for the framework, it only stores it, + * but never interacts with it in any way. + *

+ * + * @param userData + * any object holding the domain specific user data + * associated with the object. + * @return builder + */ + public Builder setUserData(Object userData) { + this.userData = userData; + return this; + } + /** * Sets pickup location. * - * @param pickupLocation pickup location + * @param pickupLocation + * pickup location * @return builder */ public Builder setPickupLocation(Location pickupLocation) { @@ -311,6 +332,7 @@ public class Shipment extends AbstractJob { private final int priority; Shipment(Builder builder) { + setUserData(builder.userData); this.id = builder.id; this.pickupServiceTime = builder.pickupServiceTime; this.pickupTimeWindow = builder.pickupTimeWindow; @@ -438,6 +460,7 @@ public class Shipment extends AbstractJob { * * @return priority */ + @Override public int getPriority() { return priority; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/Vehicle.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/Vehicle.java index 27210957..fd19feac 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/Vehicle.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/Vehicle.java @@ -72,6 +72,14 @@ public interface Vehicle extends HasId, HasIndex { public abstract VehicleTypeKey getVehicleTypeIdentifier(); public abstract Skills getSkills(); + /** + * @return User-specific domain data associated with the vehicle + */ + public Object getUserData(); public abstract Break getBreak(); + // Switch to this as soon as we switct to Java 8: + // default Object getUserData() { + // return null; + // }; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java index 4930fef0..143cd6a7 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImpl.java @@ -17,12 +17,13 @@ */ package com.graphhopper.jsprit.core.problem.vehicle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.graphhopper.jsprit.core.problem.AbstractVehicle; import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.Skills; import com.graphhopper.jsprit.core.problem.job.Break; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** @@ -130,6 +131,8 @@ public class VehicleImpl extends AbstractVehicle { private Break aBreak; + private Object userData; + private Builder(String id) { super(); this.id = id; @@ -148,16 +151,39 @@ public class VehicleImpl extends AbstractVehicle { return this; } + /** + * Sets user specific domain data associated with the object. + * + *

+ * The user data is a black box for the framework, it only stores it, + * but never interacts with it in any way. + *

+ * + * @param userData + * any object holding the domain specific user data + * associated with the object. + * @return builder + */ + public Builder setUserData(Object userData) { + this.userData = userData; + return this; + } + /** * Sets the flag whether the vehicle must return to depot or not. *

- *

If returnToDepot is true, the vehicle must return to specified end-location. If you - * omit specifying the end-location, vehicle returns to start-location (that must to be set). If - * you specify it, it returns to specified end-location. *

- *

If returnToDepot is false, the end-location of the vehicle is endogenous. + * If returnToDepot is true, the vehicle must return to specified + * end-location. If you omit specifying the end-location, vehicle + * returns to start-location (that must to be set). If you specify it, + * it returns to specified end-location. + *

+ *

+ * If returnToDepot is false, the end-location of the vehicle is + * endogenous. * - * @param returnToDepot true if vehicle need to return to depot, otherwise false + * @param returnToDepot + * true if vehicle need to return to depot, otherwise false * @return this builder */ public Builder setReturnToDepot(boolean returnToDepot) { @@ -234,14 +260,13 @@ public class VehicleImpl extends AbstractVehicle { if (startLocation != null && endLocation != null) { if (!startLocation.getId().equals(endLocation.getId()) && !returnToDepot) throw new IllegalArgumentException("this must not be. you specified both endLocationId and open-routes. this is contradictory.
" + - "if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified."); + "if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified."); } if (startLocation != null && endLocation == null) { endLocation = startLocation; } - if (startLocation == null && endLocation == null) { + if (startLocation == null && endLocation == null) throw new IllegalArgumentException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set"); - } skills = skillBuilder.build(); return new VehicleImpl(this); } @@ -297,6 +322,7 @@ public class VehicleImpl extends AbstractVehicle { private final Break aBreak; private VehicleImpl(Builder builder) { + setUserData(builder.userData); id = builder.id; type = builder.type; earliestDeparture = builder.earliestStart; @@ -306,7 +332,7 @@ public class VehicleImpl extends AbstractVehicle { endLocation = builder.endLocation; startLocation = builder.startLocation; aBreak = builder.aBreak; -// setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills)); + // setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(),startLocation.getId(),endLocation.getId(),earliestDeparture,latestArrival,skills)); setVehicleIdentifier(new VehicleTypeKey(type.getTypeId(), startLocation.getId(), endLocation.getId(), earliestDeparture, latestArrival, skills, returnToDepot)); } @@ -318,11 +344,11 @@ public class VehicleImpl extends AbstractVehicle { @Override public String toString() { return "[id=" + id + "]" + - "[type=" + type + "]" + - "[startLocation=" + startLocation + "]" + - "[endLocation=" + endLocation + "]" + - "[isReturnToDepot=" + isReturnToDepot() + "]" + - "[skills=" + skills + "]"; + "[type=" + type + "]" + + "[startLocation=" + startLocation + "]" + + "[endLocation=" + endLocation + "]" + + "[isReturnToDepot=" + isReturnToDepot() + "]" + + "[skills=" + skills + "]"; } @@ -346,6 +372,7 @@ public class VehicleImpl extends AbstractVehicle { return id; } + @Override public boolean isReturnToDepot() { return returnToDepot; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleType.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleType.java index 9847f4ba..e2eee81d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleType.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleType.java @@ -56,4 +56,13 @@ public interface VehicleType { public String getProfile(); + /** + * @return User-specific domain data associated with the vehicle type + */ + public Object getUserData(); + + // Switch to this as soon as we switct to Java 8: + // default Object getUserData() { + // return null; + // }; } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java index 864d978c..7f033e5c 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImpl.java @@ -116,16 +116,39 @@ public class VehicleTypeImpl implements VehicleType { private boolean dimensionAdded = false; + private Object userData; + private Builder(String id) { this.id = id; } + /** - * Sets the maximum velocity this vehicle-type can go [in meter per seconds]. + * Sets user specific domain data associated with the object. + * + *

+ * The user data is a black box for the framework, it only stores it, + * but never interacts with it in any way. + *

+ * + * @param userData + * any object holding the domain specific user data + * associated with the object. + * @return builder + */ + public Builder setUserData(Object userData) { + this.userData = userData; + return this; + } + + /** + * Sets the maximum velocity this vehicle-type can go [in meter per + * seconds]. * * @param inMeterPerSeconds * @return this builder - * @throws IllegalArgumentException if velocity is smaller than zero + * @throws IllegalArgumentException + * if velocity is smaller than zero */ public VehicleTypeImpl.Builder setMaxVelocity(double inMeterPerSeconds) { if (inMeterPerSeconds < 0.0) throw new IllegalArgumentException("velocity cannot be smaller than zero"); @@ -240,8 +263,8 @@ public class VehicleTypeImpl implements VehicleType { if (dimVal < 0) throw new IllegalArgumentException("capacity value cannot be negative"); if (capacityDimensions != null) throw new IllegalArgumentException("either build your dimension with build your dimensions with " + - "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." + - "You used both methods."); + "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." + + "You used both methods."); dimensionAdded = true; capacityBuilder.addDimension(dimIndex, dimVal); return this; @@ -261,8 +284,8 @@ public class VehicleTypeImpl implements VehicleType { public Builder setCapacityDimensions(Capacity capacity) { if (dimensionAdded) throw new IllegalArgumentException("either build your dimension with build your dimensions with " + - "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." + - "You used both methods."); + "addCapacityDimension(int dimIndex, int dimVal) or set the already built dimensions with .setCapacityDimensions(Capacity capacity)." + + "You used both methods."); this.capacityDimensions = capacity; return this; } @@ -278,7 +301,7 @@ public class VehicleTypeImpl implements VehicleType { final int prime = 31; int result = 1; result = prime * result - + ((typeId == null) ? 0 : typeId.hashCode()); + + ((typeId == null) ? 0 : typeId.hashCode()); return result; } @@ -314,12 +337,15 @@ public class VehicleTypeImpl implements VehicleType { private final double maxVelocity; + private Object userData; + /** * priv constructor constructing vehicle-type * * @param builder */ private VehicleTypeImpl(VehicleTypeImpl.Builder builder) { + this.userData = builder.userData; typeId = builder.id; capacity = builder.capacity; maxVelocity = builder.maxVelo; @@ -328,6 +354,14 @@ public class VehicleTypeImpl implements VehicleType { profile = builder.profile; } + /** + * @return User-specific domain data associated with the vehicle + */ + @Override + public Object getUserData() { + return userData; + } + /* (non-Javadoc) * @see basics.route.VehicleType#getTypeId() */ @@ -347,8 +381,8 @@ public class VehicleTypeImpl implements VehicleType { @Override public String toString() { return "[typeId=" + typeId + "]" + - "[capacity=" + capacityDimensions + "]" + - "[costs=" + vehicleCostParams + "]"; + "[capacity=" + capacityDimensions + "]" + + "[costs=" + vehicleCostParams + "]"; } @Override diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java index edcd76ff..00e41666 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/LocationTest.java @@ -18,11 +18,18 @@ package com.graphhopper.jsprit.core.problem; -import com.graphhopper.jsprit.core.util.Coordinate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; import org.junit.Assert; import org.junit.Test; +import com.graphhopper.jsprit.core.util.Coordinate; + /** * Created by schroeder on 16.12.14. */ @@ -82,7 +89,7 @@ public class LocationTest { @Test public void whenCoordinateSetWithFactory_returnCorrectLocation() { -// Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build(); + // Location l = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10,20)).build(); Location l = Location.newInstance(10, 20); Assert.assertEquals(10., l.getCoordinate().getX(),0.001); Assert.assertEquals(20., l.getCoordinate().getY(),0.001); @@ -90,4 +97,16 @@ public class LocationTest { } + @Test + public void whenSettingUserData_itIsAssociatedWithTheLocation() { + Location one = Location.Builder.newInstance().setCoordinate(Coordinate.newInstance(10, 20)) + .setUserData(new HashMap()).build(); + Location two = Location.Builder.newInstance().setIndex(1).setUserData(42).build(); + Location three = Location.Builder.newInstance().setIndex(2).build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } + } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java index 0ab568c6..3eb0b141 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/DeliveryTest.java @@ -17,11 +17,18 @@ */ package com.graphhopper.jsprit.core.problem.job; -import com.graphhopper.jsprit.core.problem.Location; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.*; +import com.graphhopper.jsprit.core.problem.Location; public class DeliveryTest { @@ -33,9 +40,9 @@ public class DeliveryTest { @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) - .addSizeDimension(0, 2) - .addSizeDimension(1, 4) - .build(); + .addSizeDimension(0, 2) + .addSizeDimension(1, 4) + .build(); assertEquals(2, one.getSize().getNuOfDimensions()); assertEquals(2, one.getSize().get(0)); assertEquals(4, one.getSize().get(1)); @@ -45,7 +52,7 @@ public class DeliveryTest { @Test public void whenPickupIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() { Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) - .build(); + .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(0, one.getSize().get(0)); } @@ -53,7 +60,7 @@ public class DeliveryTest { @Test public void whenPickupIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() { Delivery one = Delivery.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) - .build(); + .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(1, one.getSize().get(0)); } @@ -61,7 +68,7 @@ public class DeliveryTest { @Test public void whenAddingSkills_theyShouldBeAddedCorrectly() { Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); + .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); } @@ -69,7 +76,7 @@ public class DeliveryTest { @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() { Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); + .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drilL")); } @@ -77,7 +84,7 @@ public class DeliveryTest { @Test public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("screwDriver").build(); + .addRequiredSkill("screwDriver").build(); assertFalse(s.getRequiredSkills().containsSkill("drill")); assertFalse(s.getRequiredSkills().containsSkill("drilL")); } @@ -85,23 +92,35 @@ public class DeliveryTest { @Test public void nameShouldBeAssigned() { Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setName("name").build(); + .setName("name").build(); assertEquals("name", s.getName()); } @Test public void whenSettingPriorities_itShouldBeSetCorrectly(){ Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(3).build(); + .setPriority(3).build(); Assert.assertEquals(3, s.getPriority()); } @Test public void whenNotSettingPriorities_defaultShouldBe(){ Delivery s = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .build(); + .build(); Assert.assertEquals(2, s.getPriority()); } + @Test + public void whenSettingUserData_itIsAssociatedWithTheJob() { + Delivery one = Delivery.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setUserData(new HashMap()).build(); + Delivery two = Delivery.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42) + .build(); + Delivery three = Delivery.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java index 6236536c..9f36a40f 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/PickupTest.java @@ -17,11 +17,18 @@ */ package com.graphhopper.jsprit.core.problem.job; -import com.graphhopper.jsprit.core.problem.Location; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + import org.junit.Assert; import org.junit.Test; -import static org.junit.Assert.*; +import com.graphhopper.jsprit.core.problem.Location; public class PickupTest { @@ -33,9 +40,9 @@ public class PickupTest { @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) - .addSizeDimension(0, 2) - .addSizeDimension(1, 4) - .build(); + .addSizeDimension(0, 2) + .addSizeDimension(1, 4) + .build(); assertEquals(2, one.getSize().getNuOfDimensions()); assertEquals(2, one.getSize().get(0)); assertEquals(4, one.getSize().get(1)); @@ -45,7 +52,7 @@ public class PickupTest { @Test public void whenPickupIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() { Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) - .build(); + .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(0, one.getSize().get(0)); } @@ -53,7 +60,7 @@ public class PickupTest { @Test public void whenPickupIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() { Pickup one = Pickup.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) - .build(); + .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(1, one.getSize().get(0)); } @@ -61,7 +68,7 @@ public class PickupTest { @Test public void whenAddingSkills_theyShouldBeAddedCorrectly() { Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); + .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); @@ -70,7 +77,7 @@ public class PickupTest { @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() { Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); + .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drilL")); } @@ -78,7 +85,7 @@ public class PickupTest { @Test public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("screwDriver").build(); + .addRequiredSkill("screwDriver").build(); assertFalse(s.getRequiredSkills().containsSkill("drill")); assertFalse(s.getRequiredSkills().containsSkill("drilL")); } @@ -86,7 +93,7 @@ public class PickupTest { @Test public void nameShouldBeAssigned() { Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setName("name").build(); + .setName("name").build(); assertEquals("name", s.getName()); } @@ -94,15 +101,26 @@ public class PickupTest { @Test public void whenSettingPriorities_itShouldBeSetCorrectly(){ Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(3).build(); + .setPriority(3).build(); Assert.assertEquals(3, s.getPriority()); } @Test public void whenNotSettingPriorities_defaultShouldBe(){ Pickup s = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .build(); + .build(); Assert.assertEquals(2, s.getPriority()); } + @Test + public void whenSettingUserData_itIsAssociatedWithTheJob() { + Pickup one = Pickup.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setUserData(new HashMap()).build(); + Pickup two = Pickup.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42).build(); + Pickup three = Pickup.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java index f1efce37..6b051e84 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ServiceTest.java @@ -17,17 +17,25 @@ */ package com.graphhopper.jsprit.core.problem.job; -import com.graphhopper.jsprit.core.problem.Location; -import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + import org.junit.Assert; import org.junit.Test; -import java.util.HashSet; -import java.util.Set; - -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsCollectionContaining.hasItem; -import static org.junit.Assert.*; +import com.graphhopper.jsprit.core.problem.Location; +import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; public class ServiceTest { @@ -53,7 +61,7 @@ public class ServiceTest { Service one = Service.Builder.newInstance("service").addSizeDimension(0, 10).setLocation(Location.newInstance("foo")).build(); Service two = Service.Builder.newInstance("service").addSizeDimension(0, 10).setLocation(Location.newInstance("fo")).build(); serviceSet.add(one); -// assertTrue(serviceSet.contains(two)); + // assertTrue(serviceSet.contains(two)); serviceSet.remove(two); assertTrue(serviceSet.isEmpty()); } @@ -67,16 +75,16 @@ public class ServiceTest { @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) - .addSizeDimension(0, 2) - .addSizeDimension(1, 4) - .build(); + .addSizeDimension(0, 2) + .addSizeDimension(1, 4) + .build(); assertEquals(2, one.getSize().getNuOfDimensions()); } @Test public void whenShipmentIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() { Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("foofoo")) - .build(); + .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(0, one.getSize().get(0)); } @@ -84,7 +92,7 @@ public class ServiceTest { @Test public void whenShipmentIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() { Service one = Service.Builder.newInstance("s").addSizeDimension(0, 1).setLocation(Location.newInstance("foofoo")) - .build(); + .build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(1, one.getSize().get(0)); } @@ -116,71 +124,71 @@ public class ServiceTest { } - @Test - public void whenSettingLocationCoord_itShouldBeSetCorrectly(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance(1, 2)).build(); - assertEquals(1.0,s.getLocation().getCoordinate().getX(),0.01); - assertEquals(2.0,s.getLocation().getCoordinate().getY(),0.01); + @Test + public void whenSettingLocationCoord_itShouldBeSetCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance(1, 2)).build(); assertEquals(1.0,s.getLocation().getCoordinate().getX(),0.01); assertEquals(2.0,s.getLocation().getCoordinate().getY(),0.01); - } + assertEquals(1.0,s.getLocation().getCoordinate().getX(),0.01); + assertEquals(2.0,s.getLocation().getCoordinate().getY(),0.01); + } - @Test(expected=IllegalArgumentException.class) - public void whenSettingNeitherLocationIdNorCoord_throwsException(){ - @SuppressWarnings("unused") - Service s = Service.Builder.newInstance("s").build(); - } + @Test(expected=IllegalArgumentException.class) + public void whenSettingNeitherLocationIdNorCoord_throwsException(){ + @SuppressWarnings("unused") + Service s = Service.Builder.newInstance("s").build(); + } - @Test(expected=IllegalArgumentException.class) - public void whenServiceTimeSmallerZero_throwIllegalStateException(){ - @SuppressWarnings("unused") - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(-1).build(); - } + @Test(expected=IllegalArgumentException.class) + public void whenServiceTimeSmallerZero_throwIllegalStateException(){ + @SuppressWarnings("unused") + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(-1).build(); + } - @Test - public void whenSettingServiceTime_itShouldBeSetCorrectly(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(1).build(); - assertEquals(1.0,s.getServiceDuration(),0.01); - } + @Test + public void whenSettingServiceTime_itShouldBeSetCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setServiceTime(1).build(); + assertEquals(1.0,s.getServiceDuration(),0.01); + } - @Test(expected=IllegalArgumentException.class) - public void whenTimeWindowIsNull_throwException(){ - @SuppressWarnings("unused") - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(null).build(); - } + @Test(expected=IllegalArgumentException.class) + public void whenTimeWindowIsNull_throwException(){ + @SuppressWarnings("unused") + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(null).build(); + } - @Test - public void whenSettingTimeWindow_itShouldBeSetCorrectly(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build(); - assertEquals(1.0,s.getTimeWindow().getStart(),0.01); - assertEquals(2.0,s.getTimeWindow().getEnd(),0.01); - } + @Test + public void whenSettingTimeWindow_itShouldBeSetCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")).setTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build(); + assertEquals(1.0,s.getTimeWindow().getStart(),0.01); + assertEquals(2.0,s.getTimeWindow().getEnd(),0.01); + } - @Test - public void whenAddingSkills_theyShouldBeAddedCorrectly(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); - assertTrue(s.getRequiredSkills().containsSkill("drill")); - assertTrue(s.getRequiredSkills().containsSkill("drill")); - assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); - } + @Test + public void whenAddingSkills_theyShouldBeAddedCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); + } - @Test - public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); - assertTrue(s.getRequiredSkills().containsSkill("drill")); - assertTrue(s.getRequiredSkills().containsSkill("drilL")); - } + @Test + public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); + assertTrue(s.getRequiredSkills().containsSkill("drill")); + assertTrue(s.getRequiredSkills().containsSkill("drilL")); + } @Test public void whenAddingSeveralTimeWindows_itShouldBeSetCorrectly(){ TimeWindow tw1 = TimeWindow.newInstance(1.0, 2.0); TimeWindow tw2 = TimeWindow.newInstance(3.0, 5.0); Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addTimeWindow(tw1) - .addTimeWindow(tw2) - .build(); + .addTimeWindow(tw1) + .addTimeWindow(tw2) + .build(); assertEquals(2, s.getTimeWindows().size()); assertThat(s.getTimeWindows(),hasItem(is(tw1))); assertThat(s.getTimeWindows(),hasItem(is(tw2))); @@ -189,7 +197,7 @@ public class ServiceTest { @Test public void whenAddingTimeWindow_itShouldBeSetCorrectly(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build(); + .addTimeWindow(TimeWindow.newInstance(1.0, 2.0)).build(); assertEquals(1.0, s.getTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getTimeWindow().getEnd(), 0.01); } @@ -200,7 +208,7 @@ public class ServiceTest { @Test public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addRequiredSkill("screwDriver").build(); + .addRequiredSkill("screwDriver").build(); assertFalse(s.getRequiredSkills().containsSkill("drill")); assertFalse(s.getRequiredSkills().containsSkill("drilL")); } @@ -208,74 +216,87 @@ public class ServiceTest { @Test public void nameShouldBeAssigned() { Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setName("name").build(); + .setName("name").build(); assertEquals("name", s.getName()); } - @Test - public void shouldKnowMultipleTimeWindows(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addTimeWindow(TimeWindow.newInstance(0., 10.)).addTimeWindow(TimeWindow.newInstance(20., 30.)) - .setName("name").build(); - assertEquals(2,s.getTimeWindows().size()); - } + @Test + public void shouldKnowMultipleTimeWindows(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addTimeWindow(TimeWindow.newInstance(0., 10.)).addTimeWindow(TimeWindow.newInstance(20., 30.)) + .setName("name").build(); + assertEquals(2,s.getTimeWindows().size()); + } - @Test(expected = IllegalArgumentException.class) - public void whenMultipleTWOverlap_throwEx(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addTimeWindow(TimeWindow.newInstance(0.,10.)) - .addTimeWindow(TimeWindow.newInstance(5., 30.)) - .setName("name").build(); - } + @Test(expected = IllegalArgumentException.class) + public void whenMultipleTWOverlap_throwEx(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addTimeWindow(TimeWindow.newInstance(0.,10.)) + .addTimeWindow(TimeWindow.newInstance(5., 30.)) + .setName("name").build(); + } - @Test(expected = IllegalArgumentException.class) - public void whenMultipleTWOverlap2_throwEx(){ - Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .addTimeWindow(TimeWindow.newInstance(20., 30.)) - .addTimeWindow(TimeWindow.newInstance(0., 25.)) - .setName("name").build(); - } + @Test(expected = IllegalArgumentException.class) + public void whenMultipleTWOverlap2_throwEx(){ + Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .addTimeWindow(TimeWindow.newInstance(20., 30.)) + .addTimeWindow(TimeWindow.newInstance(0., 25.)) + .setName("name").build(); + } @Test public void whenSettingPriorities_itShouldBeSetCorrectly(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(1).build(); + .setPriority(1).build(); Assert.assertEquals(1, s.getPriority()); } @Test public void whenSettingPriorities_itShouldBeSetCorrectly2(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(3).build(); + .setPriority(3).build(); Assert.assertEquals(3, s.getPriority()); } @Test public void whenSettingPriorities_itShouldBeSetCorrectly3() { Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(10).build(); + .setPriority(10).build(); Assert.assertEquals(10, s.getPriority()); } @Test public void whenNotSettingPriorities_defaultShouldBe2(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .build(); + .build(); Assert.assertEquals(2, s.getPriority()); } @Test(expected = IllegalArgumentException.class) public void whenSettingIncorrectPriorities_itShouldThrowException(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(30).build(); + .setPriority(30).build(); } @Test(expected = IllegalArgumentException.class) public void whenSettingIncorrectPriorities_itShouldThrowException2(){ Service s = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) - .setPriority(0).build(); + .setPriority(0).build(); } + + @Test + public void whenSettingUserData_itIsAssociatedWithTheJob() { + Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc")) + .setUserData(new HashMap()).build(); + Service two = Service.Builder.newInstance("s2").setLocation(Location.newInstance("loc")).setUserData(42) + .build(); + Service three = Service.Builder.newInstance("s3").setLocation(Location.newInstance("loc")).build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java index cbfa1f26..e7caf2c1 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/job/ShipmentTest.java @@ -17,25 +17,34 @@ */ package com.graphhopper.jsprit.core.problem.job; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsCollectionContaining.hasItem; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; + import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; import com.graphhopper.jsprit.core.util.Coordinate; import com.graphhopper.jsprit.core.util.TestUtils; -import org.junit.Assert; -import org.junit.Test; - -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsCollectionContaining.hasItem; -import static org.junit.Assert.*; public class ShipmentTest { @Test public void whenTwoShipmentsHaveTheSameId_theyReferencesShouldBeUnEqual() { Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()). - setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); + setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); Shipment two = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()). - setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); + setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); assertTrue(one != two); } @@ -43,9 +52,9 @@ public class ShipmentTest { @Test public void whenTwoShipmentsHaveTheSameId_theyShouldBeEqual() { Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()). - setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); + setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); Shipment two = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()). - setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); + setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); assertTrue(one.equals(two)); } @@ -53,7 +62,7 @@ public class ShipmentTest { @Test public void whenShipmentIsInstantiatedWithASizeOf10_theSizeShouldBe10() { Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 10).setPickupLocation(Location.Builder.newInstance().setId("foo").build()). - setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); + setDeliveryLocation(TestUtils.loc("foofoo")).setPickupServiceTime(10).setDeliveryServiceTime(20).build(); assertEquals(10, one.getSize().get(0)); } @@ -61,24 +70,24 @@ public class ShipmentTest { public void whenShipmentIsBuiltWithNegativeDemand_itShouldThrowException() { @SuppressWarnings("unused") Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, -10) - .setPickupLocation(Location.Builder.newInstance().setId("foo").build()) - .setDeliveryLocation(TestUtils.loc("foofoo")).build(); + .setPickupLocation(Location.Builder.newInstance().setId("foo").build()) + .setDeliveryLocation(TestUtils.loc("foofoo")).build(); } @Test(expected = IllegalArgumentException.class) public void whenShipmentIsBuiltWithNegativeDemand_itShouldThrowException_v2() { @SuppressWarnings("unused") Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, -10) - .setPickupLocation(Location.Builder.newInstance().setId("foo").build()) - .setDeliveryLocation(TestUtils.loc("foofoo")).build(); + .setPickupLocation(Location.Builder.newInstance().setId("foo").build()) + .setDeliveryLocation(TestUtils.loc("foofoo")).build(); } @Test(expected = IllegalArgumentException.class) public void whenIdIsNull_itShouldThrowException() { @SuppressWarnings("unused") Shipment one = Shipment.Builder.newInstance(null).addSizeDimension(0, 10) - .setPickupLocation(Location.Builder.newInstance().setId("foo").build()) - .setDeliveryLocation(TestUtils.loc("foofoo")).build(); + .setPickupLocation(Location.Builder.newInstance().setId("foo").build()) + .setDeliveryLocation(TestUtils.loc("foofoo")).build(); } @Test @@ -115,7 +124,7 @@ public class ShipmentTest { @Test public void whenPickupCoordIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s") - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").setCoordinate(Coordinate.newInstance(1, 2)).build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").setCoordinate(Coordinate.newInstance(1, 2)).build()).build(); assertEquals(1.0, s.getPickupLocation().getCoordinate().getX(), 0.01); assertEquals(2.0, s.getPickupLocation().getCoordinate().getY(), 0.01); assertEquals(1.0, s.getPickupLocation().getCoordinate().getX(), 0.01); @@ -126,7 +135,7 @@ public class ShipmentTest { @Test public void whenDeliveryLocationIdIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s") - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals("delLoc", s.getDeliveryLocation().getId()); assertEquals("delLoc", s.getDeliveryLocation().getId()); } @@ -135,8 +144,8 @@ public class ShipmentTest { @Test public void whenDeliveryCoordIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(1, 2))) - .setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()) - .build(); + .setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()) + .build(); assertEquals(1.0, s.getDeliveryLocation().getCoordinate().getX(), 0.01); assertEquals(2.0, s.getDeliveryLocation().getCoordinate().getY(), 0.01); assertEquals(1.0, s.getDeliveryLocation().getCoordinate().getX(), 0.01); @@ -146,22 +155,22 @@ public class ShipmentTest { @Test public void whenPickupServiceTimeIsNotSet_itShouldBeZero() { Shipment s = Shipment.Builder.newInstance("s") - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(0.0, s.getPickupServiceTime(), 0.01); } @Test public void whenDeliveryServiceTimeIsNotSet_itShouldBeZero() { Shipment s = Shipment.Builder.newInstance("s") - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(0.0, s.getDeliveryServiceTime(), 0.01); } @Test public void whenPickupServiceTimeIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s") - .setPickupServiceTime(2.0) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setPickupServiceTime(2.0) + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(2.0, s.getPickupServiceTime(), 0.01); } @@ -169,13 +178,13 @@ public class ShipmentTest { public void whenPickupServiceIsSmallerThanZero_itShouldThrowException() { @SuppressWarnings("unused") Shipment s = Shipment.Builder.newInstance("s").setPickupServiceTime(-2.0) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); } @Test public void whenDeliveryServiceTimeIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").setDeliveryServiceTime(2.0) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(2.0, s.getDeliveryServiceTime(), 0.01); } @@ -201,7 +210,7 @@ public class ShipmentTest { @Test public void whenPickupTimeWindowIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").setPickupTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01); } @@ -222,7 +231,7 @@ public class ShipmentTest { @Test public void whenDeliveryTimeWindowIsSet_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").setDeliveryTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01); } @@ -230,7 +239,7 @@ public class ShipmentTest { @Test public void whenUsingAddDeliveryTimeWindow_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01); } @@ -238,7 +247,7 @@ public class ShipmentTest { @Test public void whenUsingAddDeliveryTimeWindow2_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(1, 2) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01); } @@ -248,7 +257,7 @@ public class ShipmentTest { TimeWindow tw1 = TimeWindow.newInstance(1,2); TimeWindow tw2 = TimeWindow.newInstance(4,5); Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(tw1).addDeliveryTimeWindow(tw2) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(s.getDeliveryTimeWindows().size(),2); assertThat(s.getDeliveryTimeWindows(),hasItem(is(tw1))); assertThat(s.getDeliveryTimeWindows(),hasItem(is(tw2))); @@ -257,7 +266,7 @@ public class ShipmentTest { @Test(expected = IllegalArgumentException.class) public void whenAddingMultipleOverlappingDeliveryTimeWindows_itShouldThrowException() { Shipment s = Shipment.Builder.newInstance("s").addDeliveryTimeWindow(1, 3).addDeliveryTimeWindow(2,5) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getDeliveryTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getDeliveryTimeWindow().getEnd(), 0.01); } @@ -267,7 +276,7 @@ public class ShipmentTest { @Test public void whenUsingAddPickupTimeWindow_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01); } @@ -275,7 +284,7 @@ public class ShipmentTest { @Test public void whenUsingAddPickupTimeWindow2_itShouldBeDoneCorrectly() { Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(1, 2) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01); } @@ -285,7 +294,7 @@ public class ShipmentTest { TimeWindow tw1 = TimeWindow.newInstance(1,2); TimeWindow tw2 = TimeWindow.newInstance(4,5); Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(tw1).addPickupTimeWindow(tw2) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(s.getPickupTimeWindows().size(),2); assertThat(s.getPickupTimeWindows(), hasItem(is(tw1))); assertThat(s.getPickupTimeWindows(), hasItem(is(tw2))); @@ -294,7 +303,7 @@ public class ShipmentTest { @Test(expected = IllegalArgumentException.class) public void whenAddingMultipleOverlappingPickupTimeWindows_itShouldThrowException() { Shipment s = Shipment.Builder.newInstance("s").addPickupTimeWindow(1, 3).addPickupTimeWindow(2,5) - .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); + .setDeliveryLocation(TestUtils.loc("delLoc")).setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()).build(); assertEquals(1.0, s.getPickupTimeWindow().getStart(), 0.01); assertEquals(2.0, s.getPickupTimeWindow().getEnd(), 0.01); } @@ -305,26 +314,26 @@ public class ShipmentTest { public void whenShipmentHasNegativeCapacityVal_throwIllegalStateExpception() { @SuppressWarnings("unused") Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("foo").build()) - .setDeliveryLocation(TestUtils.loc("foofoo")) - .addSizeDimension(0, -2) - .build(); + .setDeliveryLocation(TestUtils.loc("foofoo")) + .addSizeDimension(0, -2) + .build(); } @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("foo").build()) - .setDeliveryLocation(TestUtils.loc("foofoo")) - .addSizeDimension(0, 2) - .addSizeDimension(1, 4) - .build(); + .setDeliveryLocation(TestUtils.loc("foofoo")) + .addSizeDimension(0, 2) + .addSizeDimension(1, 4) + .build(); assertEquals(2, one.getSize().getNuOfDimensions()); } @Test public void whenShipmentIsBuiltWithoutSpecifyingCapacity_itShouldHvCapWithOneDimAndDimValOfZero() { Shipment one = Shipment.Builder.newInstance("s") - .setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build()) - .setDeliveryLocation(TestUtils.loc("foofoo")).build(); + .setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build()) + .setDeliveryLocation(TestUtils.loc("foofoo")).build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(0, one.getSize().get(0)); } @@ -332,8 +341,8 @@ public class ShipmentTest { @Test public void whenShipmentIsBuiltWithConstructorWhereSizeIsSpecified_capacityShouldBeSetCorrectly() { Shipment one = Shipment.Builder.newInstance("s").addSizeDimension(0, 1) - .setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build()) - .setDeliveryLocation(TestUtils.loc("foofoo")).build(); + .setPickupLocation(Location.Builder.newInstance().setId("foo").setCoordinate(Coordinate.newInstance(0, 0)).build()) + .setDeliveryLocation(TestUtils.loc("foofoo")).build(); assertEquals(1, one.getSize().getNuOfDimensions()); assertEquals(1, one.getSize().get(0)); } @@ -341,8 +350,8 @@ public class ShipmentTest { @Test public void whenAddingSkills_theyShouldBeAddedCorrectly() { Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build()) - .setDeliveryLocation(TestUtils.loc("delLoc")) - .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); + .setDeliveryLocation(TestUtils.loc("delLoc")) + .addRequiredSkill("drill").addRequiredSkill("screwdriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("ScrewDriver")); @@ -351,9 +360,9 @@ public class ShipmentTest { @Test public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() { Shipment s = Shipment.Builder.newInstance("s") - .setPickupLocation(Location.Builder.newInstance().setId("pick").build()) - .setDeliveryLocation(TestUtils.loc("del")) - .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); + .setPickupLocation(Location.Builder.newInstance().setId("pick").build()) + .setDeliveryLocation(TestUtils.loc("del")) + .addRequiredSkill("DriLl").addRequiredSkill("screwDriver").build(); assertTrue(s.getRequiredSkills().containsSkill("drill")); assertTrue(s.getRequiredSkills().containsSkill("drilL")); } @@ -361,8 +370,8 @@ public class ShipmentTest { @Test public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build()) - .setDeliveryLocation(TestUtils.loc("del")) - .addRequiredSkill("screwDriver").build(); + .setDeliveryLocation(TestUtils.loc("del")) + .addRequiredSkill("screwDriver").build(); assertFalse(s.getRequiredSkills().containsSkill("drill")); assertFalse(s.getRequiredSkills().containsSkill("drilL")); } @@ -370,15 +379,15 @@ public class ShipmentTest { @Test public void nameShouldBeAssigned() { Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build()) - .setDeliveryLocation(TestUtils.loc("del")) - .setName("name").build(); + .setDeliveryLocation(TestUtils.loc("del")) + .setName("name").build(); assertEquals("name", s.getName()); } @Test public void whenSettingLocation_itShouldWork() { Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.Builder.newInstance().setId("loc").build()) - .setDeliveryLocation(Location.Builder.newInstance().setId("del").build()).build(); + .setDeliveryLocation(Location.Builder.newInstance().setId("del").build()).build(); assertEquals("loc", s.getPickupLocation().getId()); assertEquals("loc", s.getPickupLocation().getId()); assertEquals("del", s.getDeliveryLocation().getId()); @@ -388,49 +397,62 @@ public class ShipmentTest { @Test public void whenSettingPriorities_itShouldBeSetCorrectly(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) - .setDeliveryLocation(Location.newInstance("loc")) - .setPriority(1).build(); + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(1).build(); Assert.assertEquals(1, s.getPriority()); } @Test public void whenSettingPriorities_itShouldBeSetCorrectly2(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) - .setDeliveryLocation(Location.newInstance("loc")) - .setPriority(3).build(); + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(3).build(); Assert.assertEquals(3, s.getPriority()); } @Test public void whenSettingPriorities_itShouldBeSetCorrectly3() { Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) - .setDeliveryLocation(Location.newInstance("loc")) - .setPriority(10).build(); + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(10).build(); Assert.assertEquals(10, s.getPriority()); } @Test public void whenNotSettingPriorities_defaultShouldBe2(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) - .setDeliveryLocation(Location.newInstance("loc")) - .build(); + .setDeliveryLocation(Location.newInstance("loc")) + .build(); Assert.assertEquals(2, s.getPriority()); } @Test(expected = IllegalArgumentException.class) public void whenSettingIncorrectPriorities_itShouldThrowException(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) - .setDeliveryLocation(Location.newInstance("loc")) - .setPriority(30).build(); + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(30).build(); } @Test(expected = IllegalArgumentException.class) public void whenSettingIncorrectPriorities_itShouldThrowException2(){ Shipment s = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) - .setDeliveryLocation(Location.newInstance("loc")) - .setPriority(0).build(); + .setDeliveryLocation(Location.newInstance("loc")) + .setPriority(0).build(); } + @Test + public void whenSettingUserData_itIsAssociatedWithTheJob() { + Shipment one = Shipment.Builder.newInstance("s").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")).setUserData(new HashMap()).build(); + Shipment two = Shipment.Builder.newInstance("s2").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")).setUserData(42).build(); + Shipment three = Shipment.Builder.newInstance("s3").setPickupLocation(Location.newInstance("loc")) + .setDeliveryLocation(Location.newInstance("loc")).build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImplTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImplTest.java index cd3f7e48..99ac6ab7 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImplTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleImplTest.java @@ -18,12 +18,20 @@ package com.graphhopper.jsprit.core.problem.vehicle; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; + import com.graphhopper.jsprit.core.problem.Location; import com.graphhopper.jsprit.core.problem.job.Break; import com.graphhopper.jsprit.core.problem.solution.route.activity.TimeWindow; -import org.junit.Test; - -import static org.junit.Assert.*; public class VehicleImplTest { @@ -39,10 +47,10 @@ public class VehicleImplTest { @Test public void whenAddingDriverBreak_itShouldBeAddedCorrectly() { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); - Break aBreak = (Break) Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build(); + Break aBreak = Break.Builder.newInstance("break").setTimeWindow(TimeWindow.newInstance(100, 200)).setServiceTime(30).build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")) - .setType(type1).setEndLocation(Location.newInstance("start")) - .setBreak(aBreak).build(); + .setType(type1).setEndLocation(Location.newInstance("start")) + .setBreak(aBreak).build(); assertNotNull(v.getBreak()); assertEquals(100., v.getBreak().getTimeWindow().getStart(), 0.1); assertEquals(200., v.getBreak().getTimeWindow().getEnd(), 0.1); @@ -54,7 +62,7 @@ public class VehicleImplTest { public void whenAddingSkills_theyShouldBeAddedCorrectly() { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")).setType(type1).setEndLocation(Location.newInstance("start")) - .addSkill("drill").addSkill("screwdriver").build(); + .addSkill("drill").addSkill("screwdriver").build(); assertTrue(v.getSkills().containsSkill("drill")); assertTrue(v.getSkills().containsSkill("drill")); assertTrue(v.getSkills().containsSkill("screwdriver")); @@ -64,7 +72,7 @@ public class VehicleImplTest { public void whenAddingSkillsCaseSens_theyShouldBeAddedCorrectly() { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")).setType(type1).setEndLocation(Location.newInstance("start")) - .addSkill("drill").addSkill("screwdriver").build(); + .addSkill("drill").addSkill("screwdriver").build(); assertTrue(v.getSkills().containsSkill("drill")); assertTrue(v.getSkills().containsSkill("dRill")); assertTrue(v.getSkills().containsSkill("ScrewDriver")); @@ -233,9 +241,23 @@ public class VehicleImplTest { public void whenAddingSkillsCaseSensV2_theyShouldBeAddedCorrectly() { VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); Vehicle v = VehicleImpl.Builder.newInstance("v").setStartLocation(Location.newInstance("start")).setType(type1).setEndLocation(Location.newInstance("start")) - .addSkill("drill").build(); + .addSkill("drill").build(); assertFalse(v.getSkills().containsSkill("ScrewDriver")); } + @Test + public void whenSettingUserData_itIsAssociatedWithTheVehicle() { + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("type").build(); + Vehicle one = VehicleImpl.Builder.newInstance("v").setType(type1) + .setStartLocation(Location.newInstance("start")).setUserData(new HashMap()).build(); + Vehicle two = VehicleImpl.Builder.newInstance("v").setType(type1) + .setStartLocation(Location.newInstance("start")).setUserData(42).build(); + Vehicle three = VehicleImpl.Builder.newInstance("v").setType(type1) + .setStartLocation(Location.newInstance("start")).build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } } diff --git a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImplTest.java b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImplTest.java index 85478347..f0159376 100644 --- a/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImplTest.java +++ b/jsprit-core/src/test/java/com/graphhopper/jsprit/core/problem/vehicle/VehicleTypeImplTest.java @@ -17,9 +17,15 @@ */ package com.graphhopper.jsprit.core.problem.vehicle; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; -import static org.junit.Assert.*; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; public class VehicleTypeImplTest { @@ -32,18 +38,18 @@ public class VehicleTypeImplTest { @Test public void whenAddingTwoCapDimension_nuOfDimsShouldBeTwo() { VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t") - .addCapacityDimension(0, 2) - .addCapacityDimension(1, 4) - .build(); + .addCapacityDimension(0, 2) + .addCapacityDimension(1, 4) + .build(); assertEquals(2, type.getCapacityDimensions().getNuOfDimensions()); } @Test public void whenAddingTwoCapDimension_dimValuesMustBeCorrect() { VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("t") - .addCapacityDimension(0, 2) - .addCapacityDimension(1, 4) - .build(); + .addCapacityDimension(0, 2) + .addCapacityDimension(1, 4) + .build(); assertEquals(2, type.getCapacityDimensions().get(0)); assertEquals(4, type.getCapacityDimensions().get(1)); } @@ -152,4 +158,15 @@ public class VehicleTypeImplTest { } + @Test + public void whenSettingUserData_itIsAssociatedWithTheVehicleType() { + VehicleType one = VehicleTypeImpl.Builder.newInstance("type").setUserData(new HashMap()) + .build(); + VehicleType two = VehicleTypeImpl.Builder.newInstance("type").setUserData(42).build(); + VehicleType three = VehicleTypeImpl.Builder.newInstance("type").build(); + + assertTrue(one.getUserData() instanceof Map); + assertEquals(42, two.getUserData()); + assertNull(three.getUserData()); + } } From 32aa164afc695df0472ea7b013d343dada4f2681 Mon Sep 17 00:00:00 2001 From: jsroyal Date: Sun, 4 Jun 2017 00:03:30 +0530 Subject: [PATCH 083/106] fixed broken link and correct syntax with md --- README.md | 14 +++---- docs/Dial-a-ride-problem.md | 2 +- docs/Getting-Started.md | 11 ++--- docs/VRP-with-time-windows-example.md | 2 +- .../test/resources/infiniteWriterV2Test.xml | 41 +++++++++++++++++++ 5 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 jsprit-io/src/test/resources/infiniteWriterV2Test.xml diff --git a/README.md b/README.md index 27b2fedf..228f6c56 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ jsprit ====== [![Build Status](https://travis-ci.org/graphhopper/jsprit.svg?branch=master)](https://travis-ci.org/graphhopper/jsprit) -jsprit is a java based, open source toolkit for solving rich traveling salesman (TSP) and vehicle routing problems (VRP). -It is lightweight, flexible and easy-to-use, and based on a single all-purpose meta-heuristic currently solving +jsprit is a java based, open source toolkit for solving rich [Traveling Salesman Problems(TSP)](http://en.wikipedia.org/wiki/Travelling_salesman_problem") and [Vehicle Routing Problems(VRP)](http://neo.lcc.uma.es/vrp/vehicle-routing-problem/). +It is lightweight, flexible and easy-to-use, and based on a single all-purpose [meta-heuristic](../docs/Meta-Heuristic.md) currently solving - Capacitated VRP - Multiple Depot VRP - VRP with Time Windows @@ -16,10 +16,10 @@ It is lightweight, flexible and easy-to-use, and based on a single all-purpose < - Various combination of these types Setting up the problem, defining additional constraints, modifying the algorithms and visualising the discovered solutions is as easy and handy as -reading classical VRP instances to benchmark your algorithm. It is fit for change and extension due to a modular design and a comprehensive set of unit and integration-tests. [More features ...](https://github.com/jsprit/jsprit/wiki/features) +reading classical VRP instances to benchmark your algorithm. It is fit for change and extension due to a modular design and a comprehensive set of unit and integration-tests. [More features ...](../docs/Features.textile) -## Getting Started and Documentation -Please visit [docs](https://github.com/graphhopper/jsprit/blob/master/docs/Home.md) to learn more. For older versions (jsprit then it is easier to keep track of your topic. @@ -51,7 +51,7 @@ You can also use [stackoverflow](http://stackoverflow.com/questions/tagged/jspri For bugs, feature requests or similar use the [issue tracker](https://github.com/jsprit/jsprit/issues). #### Email: -If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, contact us via https://graphhopper.com/#contact +If you cannot get help in the mailing list or you just do not want to discuss your topic publicly, [contact us via mail](https://graphhopper.com/#contact) ## About diff --git a/docs/Dial-a-ride-problem.md b/docs/Dial-a-ride-problem.md index 6b678523..b94a5f3e 100644 --- a/docs/Dial-a-ride-problem.md +++ b/docs/Dial-a-ride-problem.md @@ -1 +1 @@ -You model a dial-a-ride problem much like a vehicle routing problem with pickups and deliveries. The capacity of vehicles can be interpreted as number of seats available. A shipment is here understood as a ride from one location to another (probably you want the shipment to have a capacity-demand of 1). See [VRP with pickups and deliveries](https://github.com/jsprit/jsprit/wiki/VRP-with-pickups-and-deliveries). \ No newline at end of file +You model a dial-a-ride problem much like a vehicle routing problem with pickups and deliveries. The capacity of vehicles can be interpreted as number of seats available. A shipment is here understood as a ride from one location to another (probably you want the shipment to have a capacity-demand of 1). See [VRP with pickups and deliveries](../docs/Vrp-with-pickups-and-deliveries.md). \ No newline at end of file diff --git a/docs/Getting-Started.md b/docs/Getting-Started.md index ac5af692..58fad257 100644 --- a/docs/Getting-Started.md +++ b/docs/Getting-Started.md @@ -1,7 +1,7 @@ -####Requirements +#### Requirements jsprit requires Java 1.7.0 or later. -####Modules +#### Modules jsprit is a multi-module project and consists of: - jsprit-core - jsprit-analysis @@ -9,7 +9,7 @@ jsprit is a multi-module project and consists of: - jsprit-examples - jsprit-io -####Maven way +#### Maven way If you want to use the latest release of jsprit-core, add the following lines to your pom:
<dependency>
@@ -21,7 +21,7 @@ If you want to use the latest release of jsprit-core, add the following lines to
 
 Find the latest versions here: [mvn repository](https://mvnrepository.com/artifact/com.graphhopper/jsprit-core).
 
-####Build yourself
+#### Build yourself
 If you want to build the master branch yourself, do this:
 
 ```
@@ -30,7 +30,7 @@ cd jsprit
 mvn clean install
 ```
 
-####If you do not have an IDE and you want to use Maven
+#### If you do not have an IDE and you want to use Maven
 
 the following documentation is recommended:
 
@@ -39,6 +39,7 @@ the following documentation is recommended:
 Here you learn to setup the Java environment and an Integrated Development Environment (IDE). In the subsection Adding Jars to your Project you learn to integrate external libraries in your project. Just copy/paste the above jsprit releases/snapshots to your pom.xml instead of the GeoTools-artifacts.
 
 #### If you do not want Maven
+
 to manage your dependencies, go to [maven central](https://search.maven.org/), search for jsprit and download the latest binaries to put them into your classpath.
 
 Go ahead and show me a [simple example](Simple-Example.md) of how to setup and solve a vehicle routing problem.
diff --git a/docs/VRP-with-time-windows-example.md b/docs/VRP-with-time-windows-example.md
index 5a768916..68fc33d0 100644
--- a/docs/VRP-with-time-windows-example.md
+++ b/docs/VRP-with-time-windows-example.md
@@ -108,4 +108,4 @@ Collection solutions = algorithm.searchSolutions(
 VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions);
 
-Please visit Simple Example to get to know how you can analyse the solution. \ No newline at end of file +Please visit [Simple Example](Simple-Example.md) to get to know how you can analyse the solution. \ No newline at end of file diff --git a/jsprit-io/src/test/resources/infiniteWriterV2Test.xml b/jsprit-io/src/test/resources/infiniteWriterV2Test.xml new file mode 100644 index 00000000..9d863897 --- /dev/null +++ b/jsprit-io/src/test/resources/infiniteWriterV2Test.xml @@ -0,0 +1,41 @@ + + + + INFINITE + + + + + + [x=1.0][y=2.0] + + + 100.0 + + + 1.0 + 2.0 + + + + + + delLoc + + + 50.0 + + + 3.0 + 4.0 + + + + + 10 + + skill3, skill1, skill2 + + + From 6eebb5b86623cf0b584a528df37fa340171e9127 Mon Sep 17 00:00:00 2001 From: jsroyal Date: Sun, 4 Jun 2017 00:10:12 +0530 Subject: [PATCH 084/106] link fixed --- docs/VRP-with-time-windows-example.md | 2 +- docs/Walkthrough Constraints.md | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/VRP-with-time-windows-example.md b/docs/VRP-with-time-windows-example.md index 68fc33d0..5c5a4e6d 100644 --- a/docs/VRP-with-time-windows-example.md +++ b/docs/VRP-with-time-windows-example.md @@ -108,4 +108,4 @@ Collection solutions = algorithm.searchSolutions( VehicleRoutingProblemSolution bestSolution = Solutions.bestOf(solutions); -Please visit [Simple Example](Simple-Example.md) to get to know how you can analyse the solution. \ No newline at end of file +Please visit [Simple Example](https://github.com/graphhopper/jsprit/blob/master/jsprit-examples/src/main/java/com/graphhopper/jsprit/examples/SimpleExample.java) to get to know how you can analyse the solution. \ No newline at end of file diff --git a/docs/Walkthrough Constraints.md b/docs/Walkthrough Constraints.md index d37d2e4e..f48fc701 100644 --- a/docs/Walkthrough Constraints.md +++ b/docs/Walkthrough Constraints.md @@ -2,8 +2,11 @@ It is assumed that you know the basics of the [applied algorithm](Meta-Heuristic removed job is re-inserted into the ruined solution again (one after another). To actually insert a job, the algorithm calculates its "best" insertion position. This implies also to check the feasibility of the insertion step which is in turn dependent on constraints (such as capacity constraints). -jsprit knows hard and soft constraints. Whereas hard constraints must be met and cannot be broken, soft constraints -are always fulfilled but uses penalties to express "good" and "bad" insertions. + +## jsprit knows hard and soft constraints. + +- Hard constraints must be met and cannot be broken +- soft constraints are always fulfilled but uses penalties to express "good" and "bad" insertions. jsprit comes with built-in or default constraints (such as capacity and time-window constraints) and allows you to add custom constraints. However, you can also disable the default constraints. To add custom constraints use @@ -44,7 +47,7 @@ There are hard constraints at two different levels: at route and activity level. A route is basically a sequence of activities. Each route has a start- and an end-activity, and in between other activities of type core.problem.solution.route.activity.TourActivity. -###core.problem.constraint.HardRouteConstraint +### core.problem.constraint.HardRouteConstraint A HardRouteConstraint indicates whether a specified job can be inserted into an existing route (along with a specified vehicle). To define it you need to implement the HardRouteConstraint-interface:
HardRouteConstraint constraint = new HardRouteConstraint(){
@@ -61,7 +64,7 @@ The JobInsertionContext tells you the context of the insertion step, i.e. the sp
 a specified route (iContext.getRoute()) as well as the vehicle
 that should be employed on that route (iContext.getNewVehicle()).
 
-####Example:
+#### Example:
 Assume a vehicle with id="1" is not allowed to serve a job with id="job1" (since it is for example too big to access the customer location). Such a constraint can be easily defined as follows:
 
 
final Job jobWithAccessConstraint = routingProblem.getJobs().get("job1");

From adefbbdc604df6a25ab61fd71230abcaf6555763 Mon Sep 17 00:00:00 2001
From: oblonski 
Date: Thu, 8 Jun 2017 12:33:33 +0200
Subject: [PATCH 085/106] 1.7.3-SNAPSHOT

---
 jsprit-analysis/pom.xml  | 2 +-
 jsprit-core/pom.xml      | 2 +-
 jsprit-examples/pom.xml  | 2 +-
 jsprit-instances/pom.xml | 2 +-
 jsprit-io/pom.xml        | 2 +-
 pom.xml                  | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/jsprit-analysis/pom.xml b/jsprit-analysis/pom.xml
index eda298d3..e4dd3e4b 100644
--- a/jsprit-analysis/pom.xml
+++ b/jsprit-analysis/pom.xml
@@ -20,7 +20,7 @@
     
         com.graphhopper
         jsprit
-        1.7.2-SNAPSHOT
+        1.7.3-SNAPSHOT
     
     4.0.0
     jsprit-analysis
diff --git a/jsprit-core/pom.xml b/jsprit-core/pom.xml
index 059d59f4..d925760b 100644
--- a/jsprit-core/pom.xml
+++ b/jsprit-core/pom.xml
@@ -21,7 +21,7 @@
     
         com.graphhopper
         jsprit
-        1.7.2-SNAPSHOT
+        1.7.3-SNAPSHOT
     
     4.0.0
     jsprit-core
diff --git a/jsprit-examples/pom.xml b/jsprit-examples/pom.xml
index 2aec0c75..11a1b637 100644
--- a/jsprit-examples/pom.xml
+++ b/jsprit-examples/pom.xml
@@ -20,7 +20,7 @@
     
         com.graphhopper
         jsprit
-        1.7.2-SNAPSHOT
+        1.7.3-SNAPSHOT
     
     4.0.0
 
diff --git a/jsprit-instances/pom.xml b/jsprit-instances/pom.xml
index 777a8124..5f657739 100644
--- a/jsprit-instances/pom.xml
+++ b/jsprit-instances/pom.xml
@@ -20,7 +20,7 @@
     
         com.graphhopper
         jsprit
-        1.7.2-SNAPSHOT
+        1.7.3-SNAPSHOT
     
     4.0.0
 
diff --git a/jsprit-io/pom.xml b/jsprit-io/pom.xml
index 509374ae..1886f762 100644
--- a/jsprit-io/pom.xml
+++ b/jsprit-io/pom.xml
@@ -23,7 +23,7 @@
     
         com.graphhopper
         jsprit
-        1.7.2-SNAPSHOT
+        1.7.3-SNAPSHOT
     
     4.0.0
 
diff --git a/pom.xml b/pom.xml
index 388731a9..2a1147c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@
 
     com.graphhopper
     jsprit
-    1.7.2-SNAPSHOT
+    1.7.3-SNAPSHOT
 
     pom
 

From 873173dad145429042eb894b303c57ade25fbb16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= 
Date: Thu, 8 Jun 2017 12:35:11 +0200
Subject: [PATCH 086/106] v1.7.2

---
 CHANGELOG.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ddfd80ce..7a7da75f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,9 @@
 Change-log
 ==========
 
+**v1.7.2** @ 2017-06-08
+- see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md)
+
 **v1.7.1** @ 2017-05-11
 - see [Whats new](https://github.com/graphhopper/jsprit/blob/master/WHATS_NEW.md)
 

From 5fc12d48ecefea37352e4c05049273fc76b2e176 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= 
Date: Thu, 8 Jun 2017 12:42:40 +0200
Subject: [PATCH 087/106] Create WHATS_NEW.md

---
 WHATS_NEW.md | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/WHATS_NEW.md b/WHATS_NEW.md
index 44d2a30a..dfee9455 100644
--- a/WHATS_NEW.md
+++ b/WHATS_NEW.md
@@ -1,6 +1,14 @@
 WHATS NEW
 ==========
 ------------------------------
+2017-06-08 new release **v1.7.2**
+- one can now set custom properties/user defined data (see pr: https://github.com/graphhopper/jsprit/pull/348)
+
+For example, if one wants to enrich a service with an arbitrary number of custom properties, set a map like this:
+
+
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
+    .setUserData(new HashMap()).build();
+ 2017-05-11 new release **v1.7.1** - determine [reasons for unassigned jobs](https://github.com/graphhopper/jsprit/issues/180) - extend priority levels from 3 to 10 levels From 1c9ad79371750f1c5657ac182c98a84cef0d8536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Schr=C3=B6der?= Date: Thu, 8 Jun 2017 12:46:31 +0200 Subject: [PATCH 088/106] Create WHATS_NEW.md --- WHATS_NEW.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WHATS_NEW.md b/WHATS_NEW.md index dfee9455..cba7d625 100644 --- a/WHATS_NEW.md +++ b/WHATS_NEW.md @@ -7,7 +7,7 @@ WHATS NEW For example, if one wants to enrich a service with an arbitrary number of custom properties, set a map like this:
Service one = Service.Builder.newInstance("s").setLocation(Location.newInstance("loc"))
-    .setUserData(new HashMap()).build();
+ .setUserData(new HashMap<String, Object>()).build();
2017-05-11 new release **v1.7.1** - determine [reasons for unassigned jobs](https://github.com/graphhopper/jsprit/issues/180) From eb78625e1fec64d3cb19685f93fc9b82b5b8656d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Vissy?= Date: Mon, 12 Jun 2017 22:26:28 +0200 Subject: [PATCH 089/106] #354 - partial solution: adding new jobs as unassigned --- .../algorithm/VehicleRoutingAlgorithm.java | 84 +++++++++++++------ 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index 7bdeae78..cea9975b 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -17,6 +17,14 @@ */ package com.graphhopper.jsprit.core.algorithm; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.graphhopper.jsprit.core.algorithm.SearchStrategy.DiscoveredSolution; import com.graphhopper.jsprit.core.algorithm.listener.SearchStrategyListener; import com.graphhopper.jsprit.core.algorithm.listener.SearchStrategyModuleListener; @@ -30,11 +38,6 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio import com.graphhopper.jsprit.core.problem.solution.route.VehicleRoute; import com.graphhopper.jsprit.core.problem.solution.route.activity.TourActivity; import com.graphhopper.jsprit.core.util.Solutions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collection; /** @@ -57,9 +60,8 @@ public class VehicleRoutingAlgorithm { @Override public boolean isPrematureBreak(DiscoveredSolution discoveredSolution) { for (PrematureAlgorithmTermination termination : terminationCriteria) { - if (termination.isPrematureBreak(discoveredSolution)) { + if (termination.isPrematureBreak(discoveredSolution)) return true; - } } return false; } @@ -145,25 +147,41 @@ public class VehicleRoutingAlgorithm { } private void verify(VehicleRoutingProblemSolution solution) { - int nuJobs = 0; + Set allJobs = new HashSet(problem.getJobs().values()); + allJobs.removeAll(solution.getUnassignedJobs()); for (VehicleRoute route : solution.getRoutes()) { - nuJobs += route.getTourActivities().getJobs().size(); + allJobs.removeAll(route.getTourActivities().getJobs()); 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 " + - " 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()) { - 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." + - " 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" + - " then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem"); - } + " 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" + + " then the activities that are created to build the route are identical to the ones used in VehicleRoutingProblem"); } } -// if (nuJobs != 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.", nuJobs, problem.getJobs().values().size()); -// } + + solution.getUnassignedJobs().addAll(allJobs); + + // Doesn't work + // for (Vehicle v : problem.getVehicles()) { + // boolean found = false; + // for (VehicleRoute vr : solution.getRoutes()) + // if (vr.getVehicle().getId().equals(v.getId())) { + // found = true; + // break; + // } + // if (!found) { + // solution.getRoutes().add(VehicleRoute.Builder.newInstance(v).build()); + // } + // } + + // if (nuJobs != 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.", nuJobs, problem.getJobs().values().size()); + // } } /** @@ -214,7 +232,9 @@ public class VehicleRoutingAlgorithm { Collection solutions = new ArrayList(initialSolutions); algorithmStarts(problem, solutions); bestEver = Solutions.bestOf(solutions); - if (logger.isTraceEnabled()) log(solutions); + if (logger.isTraceEnabled()) { + log(solutions); + } logger.info("iterations start"); for (int i = 0; i < maxIterations; i++) { iterationStarts(i + 1, problem, solutions); @@ -222,7 +242,9 @@ public class VehicleRoutingAlgorithm { counter.incCounter(); SearchStrategy strategy = searchStrategyManager.getRandomStrategy(); DiscoveredSolution discoveredSolution = strategy.run(problem, solutions); - if (logger.isTraceEnabled()) log(discoveredSolution); + if (logger.isTraceEnabled()) { + log(discoveredSolution); + } memorizeIfBestEver(discoveredSolution); selectedStrategy(discoveredSolution, problem, solutions); if (terminationManager.isPrematureBreak(discoveredSolution)) { @@ -240,11 +262,15 @@ public class VehicleRoutingAlgorithm { } private void addBestEver(Collection solutions) { - if (bestEver != null) solutions.add(bestEver); + if (bestEver != null) { + solutions.add(bestEver); + } } private void log(Collection solutions) { - for (VehicleRoutingProblemSolution sol : solutions) log(sol); + for (VehicleRoutingProblemSolution sol : solutions) { + log(sol); + } } private void log(VehicleRoutingProblemSolution solution) { @@ -277,9 +303,11 @@ public class VehicleRoutingAlgorithm { private void memorizeIfBestEver(DiscoveredSolution discoveredSolution) { if (discoveredSolution == null) return; - if (bestEver == null) bestEver = discoveredSolution.getSolution(); - else if (discoveredSolution.getSolution().getCost() < bestEver.getCost()) + if (bestEver == null) { bestEver = discoveredSolution.getSolution(); + } else if (discoveredSolution.getSolution().getCost() < bestEver.getCost()) { + bestEver = discoveredSolution.getSolution(); + } } @@ -297,10 +325,12 @@ public class VehicleRoutingAlgorithm { public void addListener(VehicleRoutingAlgorithmListener l) { algoListeners.addListener(l); - if (l instanceof SearchStrategyListener) + if (l instanceof SearchStrategyListener) { searchStrategyManager.addSearchStrategyListener((SearchStrategyListener) l); - if (l instanceof SearchStrategyModuleListener) + } + if (l instanceof SearchStrategyModuleListener) { searchStrategyManager.addSearchStrategyModuleListener((SearchStrategyModuleListener) l); + } } private void iterationEnds(int i, VehicleRoutingProblem problem, Collection solutions) { From 1af75329396cfb66b12fa6d57386e05b8d918442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Vissy?= Date: Mon, 12 Jun 2017 22:38:35 +0200 Subject: [PATCH 090/106] #354 - fixed - Cost recalculated for solution after jobs added (also a copy is made from the solution) --- .../core/algorithm/VehicleRoutingAlgorithm.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java index cea9975b..b60fae9f 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/VehicleRoutingAlgorithm.java @@ -142,6 +142,8 @@ public class VehicleRoutingAlgorithm { * @param solution the solution to be added */ public void addInitialSolution(VehicleRoutingProblemSolution solution) { + // We will make changes so let's make a copy + solution = VehicleRoutingProblemSolution.copyOf(solution); verify(solution); initialSolutions.add(solution); } @@ -164,19 +166,7 @@ public class VehicleRoutingAlgorithm { } solution.getUnassignedJobs().addAll(allJobs); - - // Doesn't work - // for (Vehicle v : problem.getVehicles()) { - // boolean found = false; - // for (VehicleRoute vr : solution.getRoutes()) - // if (vr.getVehicle().getId().equals(v.getId())) { - // found = true; - // break; - // } - // if (!found) { - // solution.getRoutes().add(VehicleRoute.Builder.newInstance(v).build()); - // } - // } + solution.setCost(getObjectiveFunction().getCosts(solution)); // if (nuJobs != problem.getJobs().values().size()) { // logger.warn("number of jobs in initial solution ({}) is not equal nuJobs in vehicle routing problem ({})" + From dc52d9b2d89d604120cd922d681c1e90ea05b235 Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Tue, 27 Jun 2017 23:21:07 +0200 Subject: [PATCH 091/106] Add createTwoVehicleTypeAndInstancesBuilder method --- .../jsprit/io/problem/VrpXMLWriterTest.java | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index e75e1ba8..83f984e4 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -774,17 +774,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingVehicleV2_readingItsLocationsAgainReturnsCorrectLocations() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setReturnToDepot(false).setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2") - .setStartLocation(TestUtils.loc("startLoc", Coordinate.newInstance(1, 2))) - .setEndLocation(TestUtils.loc("endLoc", Coordinate.newInstance(4, 5))).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = createTwoVehicleTypeAndInstancesBuilder(); Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); @@ -803,18 +793,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingVehicleV2_readingItsLocationsCoordsAgainReturnsCorrectLocationsCoords() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setReturnToDepot(false) - .setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2") - .setStartLocation(TestUtils.loc("startLoc", Coordinate.newInstance(1, 2))) - .setEndLocation(TestUtils.loc("endLoc", Coordinate.newInstance(4, 5))).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = createTwoVehicleTypeAndInstancesBuilder(); Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); @@ -834,6 +813,22 @@ public class VrpXMLWriterTest { Assert.assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01); } + private VehicleRoutingProblem.Builder createTwoVehicleTypeAndInstancesBuilder() { + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); + VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); + VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setReturnToDepot(false) + .setStartLocation(TestUtils.loc("loc")).setType(type1).build(); + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2") + .setStartLocation(TestUtils.loc("startLoc", Coordinate.newInstance(1, 2))) + .setEndLocation(TestUtils.loc("endLoc", Coordinate.newInstance(4, 5))).setType(type2).build(); + + builder.addVehicle(v1); + builder.addVehicle(v2); + return builder; + } + @Test public void whenWritingVehicleWithSeveralCapacityDimensions_itShouldBeWrittenAndRereadCorrectly() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); From 6d0f0c38b399253685063ae7bd77a5ae60798ad5 Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Wed, 28 Jun 2017 00:11:05 +0200 Subject: [PATCH 092/106] Extract method to write and re-read the XML Also combine skill check tests into one with multiple assertions --- .../jsprit/io/problem/VrpXMLWriterTest.java | 253 ++++-------------- 1 file changed, 57 insertions(+), 196 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index 83f984e4..ae48e513 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -84,22 +84,19 @@ public class VrpXMLWriterTest { VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); builder.addVehicle(v1); builder.addVehicle(v2); - VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); + VehicleRoutingProblem vrp = builder.build(); + writeAndRereadXml(vrp); + } @Test public void whenWritingServices_itWritesThemCorrectly() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - builder.addVehicle(v1); builder.addVehicle(v2); @@ -108,11 +105,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Service s1_read = (Service) vrp.getJobs().get("1"); @@ -128,11 +121,7 @@ public class VrpXMLWriterTest { Service s1 = Service.Builder.newInstance("1").setName("cleaning").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Service s1_read = (Service) readVrp.getJobs().get("1"); assertTrue(s1_read.getName().equals("cleaning")); } @@ -146,11 +135,7 @@ public class VrpXMLWriterTest { .setDeliveryLocation(TestUtils.loc("del")).build(); VehicleRoutingProblem vrp = builder.addJob(s1).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Shipment s1_read = (Shipment) readVrp.getJobs().get("1"); assertTrue(s1_read.getName().equals("cleaning")); Assert.assertEquals(1, s1_read.getPickupLocation().getIndex()); @@ -167,11 +152,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Service s1_read = (Service) vrp.getJobs().get("1"); @@ -205,11 +186,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Assert.assertEquals("pickLoc", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId()); @@ -240,11 +217,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Assert.assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getStart(), 0.01); @@ -276,11 +249,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Assert.assertEquals(3.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getStart(), 0.01); @@ -311,11 +280,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); assertEquals(100.0, ((Shipment) readVrp.getJobs().get("1")).getPickupServiceTime(), 0.01); @@ -345,11 +310,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Assert.assertEquals("[x=1.0][y=2.0]", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId()); @@ -364,11 +325,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh1 = getVehicle("v1", readVrp); Assert.assertEquals(3, veh1.getSkills().values().size()); @@ -383,11 +340,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh1 = getVehicle("v1", readVrp); assertTrue(veh1.getSkills().containsSkill("skill5")); @@ -402,11 +355,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh1 = getVehicle("v1", readVrp); assertTrue(veh1.getSkills().containsSkill("skill1")); @@ -421,11 +370,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh1 = getVehicle("v1", readVrp); assertTrue(veh1.getSkills().containsSkill("skill2")); @@ -439,11 +384,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh = getVehicle("v1", readVrp); Assert.assertEquals(0, veh.getSkills().values().size()); @@ -468,11 +409,7 @@ public class VrpXMLWriterTest { .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Assert.assertEquals(3, readVrp.getJobs().get("1").getRequiredSkills().values().size()); } @@ -489,11 +426,7 @@ public class VrpXMLWriterTest { .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill1")); } @@ -510,11 +443,7 @@ public class VrpXMLWriterTest { .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill2")); } @@ -531,11 +460,7 @@ public class VrpXMLWriterTest { .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill3")); } @@ -564,11 +489,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); Assert.assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getX(), 0.01); @@ -597,11 +518,7 @@ public class VrpXMLWriterTest { .setDeliveryTimeWindow(TimeWindow.newInstance(7, 8)).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Assert.assertEquals(3, (readVrp.getJobs().get("1")).getSize().getNuOfDimensions()); Assert.assertEquals(10, (readVrp.getJobs().get("1")).getSize().get(0)); @@ -628,11 +545,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v1", readVrp.getVehicles()); Assert.assertEquals("loc", v.getStartLocation().getId()); @@ -641,56 +554,23 @@ public class VrpXMLWriterTest { } @Test - public void whenWritingService_itShouldHaveTheCorrectNuSkills() { + public void whenWritingService_itShouldContain_bothSkills() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - Service s = Service.Builder.newInstance("1").addRequiredSkill("sKill1").addRequiredSkill("skill2").addSizeDimension(0, 1) - .setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); + //skill names are case-insensitive + Service s = Service.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("SKILL2").addSizeDimension(0, 1) + .setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); - - Assert.assertEquals(2, readVrp.getJobs().get("1").getRequiredSkills().values().size()); - } - - @Test - public void whenWritingService_itShouldContain_skill1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - Service s = Service.Builder.newInstance("1").addRequiredSkill("sKill1").addRequiredSkill("skill2").addSizeDimension(0, 1) - .setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); - - VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); + assertEquals(2, readVrp.getJobs().get("1").getRequiredSkills().values().size()); assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill1")); - } - - @Test - public void whenWritingService_itShouldContain_skill2() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - Service s = Service.Builder.newInstance("1").addRequiredSkill("sKill1").addRequiredSkill("skill2").addSizeDimension(0, 1) - .setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); - - VehicleRoutingProblem vrp = builder.addJob(s).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); - assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill2")); } + @Test public void whenWritingVehicleV1_itDoesNotReturnToDepotMustBeWrittenCorrectly() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); @@ -708,11 +588,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v1", readVrp.getVehicles()); assertFalse(v.isReturnToDepot()); @@ -734,11 +610,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v1", readVrp.getVehicles()); assertEquals("vehType", v.getType().getTypeId()); @@ -760,11 +632,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v2", readVrp.getVehicles()); assertEquals("vehType2", v.getType().getTypeId()); @@ -780,11 +648,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v2", readVrp.getVehicles()); Assert.assertEquals("startLoc", v.getStartLocation().getId()); @@ -799,11 +663,7 @@ public class VrpXMLWriterTest { Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v2", readVrp.getVehicles()); Assert.assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01); @@ -845,11 +705,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v2); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v", readVrp.getVehicles()); Assert.assertEquals(3, v.getType().getCapacityDimensions().getNuOfDimensions()); @@ -874,11 +730,7 @@ public class VrpXMLWriterTest { builder.addVehicle(v2); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); - VehicleRoutingProblem readVrp = vrpToReadBuilder.build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v", readVrp.getVehicles()); Assert.assertEquals(11, v.getType().getCapacityDimensions().getNuOfDimensions()); @@ -911,11 +763,7 @@ public class VrpXMLWriterTest { List solutions = new ArrayList(); solutions.add(solution); - new VrpXMLWriter(vrp, solutions).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - List solutionsToRead = new ArrayList(); - new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(infileName); + List solutionsToRead = writeAndRereadXmlWithSolutions(vrp, solutions); assertEquals(1, solutionsToRead.size()); Assert.assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01); @@ -943,11 +791,7 @@ public class VrpXMLWriterTest { List solutions = new ArrayList(); solutions.add(solution); - new VrpXMLWriter(vrp, solutions).write(infileName); - - VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - List solutionsToRead = new ArrayList(); - new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(infileName); + List solutionsToRead = writeAndRereadXmlWithSolutions(vrp, solutions); assertEquals(1, solutionsToRead.size()); Assert.assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01); @@ -955,4 +799,21 @@ public class VrpXMLWriterTest { Assert.assertEquals("2", Solutions.bestOf(solutionsToRead).getUnassignedJobs().iterator().next().getId()); } + private VehicleRoutingProblem writeAndRereadXml(VehicleRoutingProblem vrp) { + new VrpXMLWriter(vrp, null).write(infileName); + + VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); + new VrpXMLReader(vrpToReadBuilder, null).read(infileName); + return vrpToReadBuilder.build(); + } + + private List writeAndRereadXmlWithSolutions(VehicleRoutingProblem vrp, List solutions) { + new VrpXMLWriter(vrp, solutions).write(infileName); + + VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); + List solutionsToRead = new ArrayList(); + new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(infileName); + return solutionsToRead; + } + } From 69aee1660acadc666dce0954311d30df4727a5d4 Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Wed, 28 Jun 2017 00:14:53 +0200 Subject: [PATCH 093/106] Make static Assert accessors uniform --- .../jsprit/io/problem/VrpXMLWriterTest.java | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index ae48e513..e0f83644 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -157,9 +157,9 @@ public class VrpXMLWriterTest { Service s1_read = (Service) vrp.getJobs().get("1"); - Assert.assertEquals(2, s1_read.getSize().getNuOfDimensions()); - Assert.assertEquals(20, s1_read.getSize().get(0)); - Assert.assertEquals(200, s1_read.getSize().get(1)); + assertEquals(2, s1_read.getSize().getNuOfDimensions()); + assertEquals(20, s1_read.getSize().get(0)); + assertEquals(200, s1_read.getSize().get(1)); } @@ -189,8 +189,8 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); - Assert.assertEquals("pickLoc", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId()); - Assert.assertEquals("delLoc", ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getId()); + assertEquals("pickLoc", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId()); + assertEquals("delLoc", ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getId()); } @@ -220,8 +220,8 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); - Assert.assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getStart(), 0.01); - Assert.assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getEnd(), 0.01); + assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getStart(), 0.01); + assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupTimeWindow().getEnd(), 0.01); } @@ -252,8 +252,8 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); - Assert.assertEquals(3.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getStart(), 0.01); - Assert.assertEquals(4.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getEnd(), 0.01); + assertEquals(3.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getStart(), 0.01); + assertEquals(4.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryTimeWindow().getEnd(), 0.01); } @@ -313,7 +313,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); - Assert.assertEquals("[x=1.0][y=2.0]", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId()); + assertEquals("[x=1.0][y=2.0]", ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getId()); } @Test @@ -328,7 +328,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh1 = getVehicle("v1", readVrp); - Assert.assertEquals(3, veh1.getSkills().values().size()); + assertEquals(3, veh1.getSkills().values().size()); } @Test @@ -387,7 +387,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle veh = getVehicle("v1", readVrp); - Assert.assertEquals(0, veh.getSkills().values().size()); + assertEquals(0, veh.getSkills().values().size()); } private Vehicle getVehicle(String v1, VehicleRoutingProblem readVrp) { @@ -411,7 +411,7 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s).build(); VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - Assert.assertEquals(3, readVrp.getJobs().get("1").getRequiredSkills().values().size()); + assertEquals(3, readVrp.getJobs().get("1").getRequiredSkills().values().size()); } @Test @@ -492,11 +492,11 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(2, readVrp.getJobs().size()); - Assert.assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getX(), 0.01); - Assert.assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getY(), 0.01); + assertEquals(1.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getX(), 0.01); + assertEquals(2.0, ((Shipment) readVrp.getJobs().get("1")).getPickupLocation().getCoordinate().getY(), 0.01); - Assert.assertEquals(5.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getX(), 0.01); - Assert.assertEquals(6.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getY(), 0.01); + assertEquals(5.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getX(), 0.01); + assertEquals(6.0, ((Shipment) readVrp.getJobs().get("1")).getDeliveryLocation().getCoordinate().getY(), 0.01); } @Test @@ -520,13 +520,13 @@ public class VrpXMLWriterTest { VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - Assert.assertEquals(3, (readVrp.getJobs().get("1")).getSize().getNuOfDimensions()); - Assert.assertEquals(10, (readVrp.getJobs().get("1")).getSize().get(0)); - Assert.assertEquals(0, (readVrp.getJobs().get("1")).getSize().get(1)); - Assert.assertEquals(100, (readVrp.getJobs().get("1")).getSize().get(2)); + assertEquals(3, (readVrp.getJobs().get("1")).getSize().getNuOfDimensions()); + assertEquals(10, (readVrp.getJobs().get("1")).getSize().get(0)); + assertEquals(0, (readVrp.getJobs().get("1")).getSize().get(1)); + assertEquals(100, (readVrp.getJobs().get("1")).getSize().get(2)); - Assert.assertEquals(1, (readVrp.getJobs().get("2")).getSize().getNuOfDimensions()); - Assert.assertEquals(20, (readVrp.getJobs().get("2")).getSize().get(0)); + assertEquals(1, (readVrp.getJobs().get("2")).getSize().getNuOfDimensions()); + assertEquals(20, (readVrp.getJobs().get("2")).getSize().get(0)); } @Test @@ -548,8 +548,8 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v1", readVrp.getVehicles()); - Assert.assertEquals("loc", v.getStartLocation().getId()); - Assert.assertEquals("loc", v.getEndLocation().getId()); + assertEquals("loc", v.getStartLocation().getId()); + assertEquals("loc", v.getEndLocation().getId()); } @@ -636,7 +636,7 @@ public class VrpXMLWriterTest { Vehicle v = getVehicle("v2", readVrp.getVehicles()); assertEquals("vehType2", v.getType().getTypeId()); - Assert.assertEquals(200, v.getType().getCapacityDimensions().get(0)); + assertEquals(200, v.getType().getCapacityDimensions().get(0)); } @@ -651,8 +651,8 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v2", readVrp.getVehicles()); - Assert.assertEquals("startLoc", v.getStartLocation().getId()); - Assert.assertEquals("endLoc", v.getEndLocation().getId()); + assertEquals("startLoc", v.getStartLocation().getId()); + assertEquals("endLoc", v.getEndLocation().getId()); } @Test @@ -666,11 +666,11 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v2", readVrp.getVehicles()); - Assert.assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01); - Assert.assertEquals(2.0, v.getStartLocation().getCoordinate().getY(), 0.01); + assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01); + assertEquals(2.0, v.getStartLocation().getCoordinate().getY(), 0.01); - Assert.assertEquals(4.0, v.getEndLocation().getCoordinate().getX(), 0.01); - Assert.assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01); + assertEquals(4.0, v.getEndLocation().getCoordinate().getX(), 0.01); + assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01); } private VehicleRoutingProblem.Builder createTwoVehicleTypeAndInstancesBuilder() { @@ -708,10 +708,10 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v", readVrp.getVehicles()); - Assert.assertEquals(3, v.getType().getCapacityDimensions().getNuOfDimensions()); - Assert.assertEquals(100, v.getType().getCapacityDimensions().get(0)); - Assert.assertEquals(1000, v.getType().getCapacityDimensions().get(1)); - Assert.assertEquals(10000, v.getType().getCapacityDimensions().get(2)); + assertEquals(3, v.getType().getCapacityDimensions().getNuOfDimensions()); + assertEquals(100, v.getType().getCapacityDimensions().get(0)); + assertEquals(1000, v.getType().getCapacityDimensions().get(1)); + assertEquals(10000, v.getType().getCapacityDimensions().get(2)); } @Test @@ -733,9 +733,9 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); Vehicle v = getVehicle("v", readVrp.getVehicles()); - Assert.assertEquals(11, v.getType().getCapacityDimensions().getNuOfDimensions()); - Assert.assertEquals(0, v.getType().getCapacityDimensions().get(9)); - Assert.assertEquals(10000, v.getType().getCapacityDimensions().get(10)); + assertEquals(11, v.getType().getCapacityDimensions().getNuOfDimensions()); + assertEquals(0, v.getType().getCapacityDimensions().get(9)); + assertEquals(10000, v.getType().getCapacityDimensions().get(10)); } private Vehicle getVehicle(String string, Collection vehicles) { @@ -766,7 +766,7 @@ public class VrpXMLWriterTest { List solutionsToRead = writeAndRereadXmlWithSolutions(vrp, solutions); assertEquals(1, solutionsToRead.size()); - Assert.assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01); + assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01); assertTrue(Solutions.bestOf(solutionsToRead).getUnassignedJobs().isEmpty()); } @@ -794,9 +794,9 @@ public class VrpXMLWriterTest { List solutionsToRead = writeAndRereadXmlWithSolutions(vrp, solutions); assertEquals(1, solutionsToRead.size()); - Assert.assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01); - Assert.assertEquals(1, Solutions.bestOf(solutionsToRead).getUnassignedJobs().size()); - Assert.assertEquals("2", Solutions.bestOf(solutionsToRead).getUnassignedJobs().iterator().next().getId()); + assertEquals(10., Solutions.bestOf(solutionsToRead).getCost(), 0.01); + assertEquals(1, Solutions.bestOf(solutionsToRead).getUnassignedJobs().size()); + assertEquals("2", Solutions.bestOf(solutionsToRead).getUnassignedJobs().iterator().next().getId()); } private VehicleRoutingProblem writeAndRereadXml(VehicleRoutingProblem vrp) { From 06afdb6e15243142d709abefbc54af55f114a338 Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Tue, 27 Jun 2017 23:11:13 +0200 Subject: [PATCH 094/106] Combine test for writing and then reading finite Vrp --- .../jsprit/io/problem/VrpXMLWriterTest.java | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index e0f83644..140b1daa 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -61,21 +61,7 @@ public class VrpXMLWriterTest { } @Test - public void whenWritingFiniteVrp_itWritesCorrectly() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - builder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - builder.addVehicle(v1); - builder.addVehicle(v2); - VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - } - - @Test - public void t() { + public void whenWritingFiniteVrp_itWritesAndReadsCorrectly() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); builder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); @@ -90,6 +76,7 @@ public class VrpXMLWriterTest { } + @Test public void whenWritingServices_itWritesThemCorrectly() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); From b5b4b67400dfdbb60bab82391a95a7d86e7f99d0 Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Wed, 28 Jun 2017 00:37:25 +0200 Subject: [PATCH 095/106] Extract method to create common builder for 2 Vechicle type and impls --- .../jsprit/io/problem/VrpXMLWriterTest.java | 149 +++++------------- 1 file changed, 37 insertions(+), 112 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index 140b1daa..a9b9d4f4 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -62,31 +62,17 @@ public class VrpXMLWriterTest { @Test public void whenWritingFiniteVrp_itWritesAndReadsCorrectly() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); builder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - builder.addVehicle(v1); - builder.addVehicle(v2); VehicleRoutingProblem vrp = builder.build(); writeAndRereadXml(vrp); - } @Test public void whenWritingServices_itWritesThemCorrectly() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - builder.addVehicle(v1); - builder.addVehicle(v2); - + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); @@ -152,15 +138,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingShipments_readingThemAgainMustReturnTheWrittenLocationIdsOfS1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10) .setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()) @@ -183,15 +161,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingShipments_readingThemAgainMustReturnTheWrittenPickupTimeWindowsOfS1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10) .setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()) @@ -215,15 +185,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingShipments_readingThemAgainMustReturnTheWrittenDeliveryTimeWindowsOfS1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10) .setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()) @@ -246,15 +208,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingShipments_readingThemAgainMustReturnTheWrittenDeliveryServiceTimeOfS1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10) .setPickupLocation(Location.Builder.newInstance().setId("pickLoc").build()) @@ -277,15 +231,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingShipments_readingThemAgainMustReturnTheWrittenLocationIdOfS1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10) .setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2))).setDeliveryLocation(TestUtils.loc("delLoc")).setPickupTimeWindow(TimeWindow.newInstance(1, 2)) @@ -454,15 +400,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingShipments_readingThemAgainMustReturnTheWrittenLocationCoordinateOfS1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Shipment s1 = Shipment.Builder.newInstance("1").addSizeDimension(0, 10).setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2))) .setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6))) @@ -518,15 +456,7 @@ public class VrpXMLWriterTest { @Test public void whenWritingVehicleV1_itsStartLocationMustBeWrittenCorrectly() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); - VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); - - builder.addVehicle(v1); - builder.addVehicle(v2); + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); @@ -540,6 +470,19 @@ public class VrpXMLWriterTest { } + private VehicleRoutingProblem.Builder twoVehicleTypesAndImpls() { + VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); + + VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); + VehicleTypeImpl type2 = VehicleTypeImpl.Builder.newInstance("vehType2").addCapacityDimension(0, 200).build(); + VehicleImpl v1 = VehicleImpl.Builder.newInstance("v1").setStartLocation(TestUtils.loc("loc")).setType(type1).build(); + VehicleImpl v2 = VehicleImpl.Builder.newInstance("v2").setStartLocation(TestUtils.loc("loc")).setType(type2).build(); + + builder.addVehicle(v1); + builder.addVehicle(v2); + return builder; + } + @Test public void whenWritingService_itShouldContain_bothSkills() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); @@ -629,38 +572,6 @@ public class VrpXMLWriterTest { @Test public void whenWritingVehicleV2_readingItsLocationsAgainReturnsCorrectLocations() { - VehicleRoutingProblem.Builder builder = createTwoVehicleTypeAndInstancesBuilder(); - - Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); - Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); - - VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - - Vehicle v = getVehicle("v2", readVrp.getVehicles()); - assertEquals("startLoc", v.getStartLocation().getId()); - assertEquals("endLoc", v.getEndLocation().getId()); - } - - @Test - public void whenWritingVehicleV2_readingItsLocationsCoordsAgainReturnsCorrectLocationsCoords() { - VehicleRoutingProblem.Builder builder = createTwoVehicleTypeAndInstancesBuilder(); - - Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); - Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); - - VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - - Vehicle v = getVehicle("v2", readVrp.getVehicles()); - assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01); - assertEquals(2.0, v.getStartLocation().getCoordinate().getY(), 0.01); - - assertEquals(4.0, v.getEndLocation().getCoordinate().getX(), 0.01); - assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01); - } - - private VehicleRoutingProblem.Builder createTwoVehicleTypeAndInstancesBuilder() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); @@ -673,9 +584,23 @@ public class VrpXMLWriterTest { builder.addVehicle(v1); builder.addVehicle(v2); - return builder; + + Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc")).setServiceTime(2.0).build(); + Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(TestUtils.loc("loc2")).setServiceTime(4.0).build(); + + VehicleRoutingProblem vrp = builder.addJob(s1).addJob(s2).build(); + VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); + + Vehicle v = getVehicle("v2", readVrp.getVehicles()); + assertEquals("startLoc", v.getStartLocation().getId()); + assertEquals("endLoc", v.getEndLocation().getId()); + assertEquals(1.0, v.getStartLocation().getCoordinate().getX(), 0.01); + assertEquals(2.0, v.getStartLocation().getCoordinate().getY(), 0.01); + assertEquals(4.0, v.getEndLocation().getCoordinate().getX(), 0.01); + assertEquals(5.0, v.getEndLocation().getCoordinate().getY(), 0.01); } + @Test public void whenWritingVehicleWithSeveralCapacityDimensions_itShouldBeWrittenAndRereadCorrectly() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); From 4f0936526799e661c7dff5b5bbef91302adc6ee0 Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Wed, 28 Jun 2017 00:40:03 +0200 Subject: [PATCH 096/106] Consolidate skills assertions for shipments into one test --- .../jsprit/io/problem/VrpXMLWriterTest.java | 48 ------------------- 1 file changed, 48 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index a9b9d4f4..ec4d7a2c 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -345,56 +345,8 @@ public class VrpXMLWriterTest { VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); assertEquals(3, readVrp.getJobs().get("1").getRequiredSkills().values().size()); - } - - @Test - public void whenWritingShipments_shipmentShouldContain_skill1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - Shipment s = Shipment.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("skill2").addRequiredSkill("skill3") - .addSizeDimension(0, 10) - .setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2))) - .setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6))) - .setPickupTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); - - VehicleRoutingProblem vrp = builder.addJob(s).build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill1")); - } - - @Test - public void whenWritingShipments_shipmentShouldContain_skill2() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - Shipment s = Shipment.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("Skill2").addRequiredSkill("skill3") - .addSizeDimension(0, 10) - .setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2))) - .setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6))) - .setPickupTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); - - VehicleRoutingProblem vrp = builder.addJob(s).build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill2")); - } - - @Test - public void whenWritingShipments_shipmentShouldContain_skill3() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - - Shipment s = Shipment.Builder.newInstance("1").addRequiredSkill("skill1").addRequiredSkill("Skill2").addRequiredSkill("skill3") - .addSizeDimension(0, 10) - .setPickupLocation(TestUtils.loc(Coordinate.newInstance(1, 2))) - .setDeliveryLocation(TestUtils.loc("delLoc", Coordinate.newInstance(5, 6))) - .setPickupTimeWindow(TimeWindow.newInstance(1, 2)) - .setDeliveryTimeWindow(TimeWindow.newInstance(3, 4)).setPickupServiceTime(100).setDeliveryServiceTime(50).build(); - - VehicleRoutingProblem vrp = builder.addJob(s).build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - assertTrue(readVrp.getJobs().get("1").getRequiredSkills().containsSkill("skill3")); } From bf40087b222decb95073722ccc2e6cf0f01d673e Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Wed, 28 Jun 2017 00:43:19 +0200 Subject: [PATCH 097/106] Consolidate skills assertions for vehicles into one test --- .../jsprit/io/problem/VrpXMLWriterTest.java | 44 +------------------ 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index ec4d7a2c..5783f398 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -250,7 +250,7 @@ public class VrpXMLWriterTest { } @Test - public void whenWritingVehicles_vehShouldHave2Skills() { + public void whenWritingVehicles_vehShouldHave3Skills() { VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2") @@ -262,50 +262,8 @@ public class VrpXMLWriterTest { Vehicle veh1 = getVehicle("v1", readVrp); assertEquals(3, veh1.getSkills().values().size()); - } - - @Test - public void whenWritingVehicles_vehShouldContain_skill5() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2") - .setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - builder.addVehicle(v); - - VehicleRoutingProblem vrp = builder.build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - Vehicle veh1 = getVehicle("v1", readVrp); - assertTrue(veh1.getSkills().containsSkill("skill5")); - } - - @Test - public void whenWritingVehicles_vehShouldContain_skill1() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2") - .setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - builder.addVehicle(v); - - VehicleRoutingProblem vrp = builder.build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - Vehicle veh1 = getVehicle("v1", readVrp); - assertTrue(veh1.getSkills().containsSkill("skill1")); - } - - @Test - public void whenWritingVehicles_vehShouldContain_skill2() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - VehicleTypeImpl type1 = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleImpl v = VehicleImpl.Builder.newInstance("v1").addSkill("SKILL5").addSkill("skill1").addSkill("Skill2") - .setStartLocation(TestUtils.loc("loc")).setType(type1).build(); - builder.addVehicle(v); - - VehicleRoutingProblem vrp = builder.build(); - VehicleRoutingProblem readVrp = writeAndRereadXml(vrp); - Vehicle veh1 = getVehicle("v1", readVrp); - assertTrue(veh1.getSkills().containsSkill("skill2")); } From bab1f7d6a84c5cc45cfe165a732ec24420d0ad2b Mon Sep 17 00:00:00 2001 From: Heinrich Filter Date: Tue, 27 Jun 2017 23:12:32 +0200 Subject: [PATCH 098/106] Add VrpXMLWrite method that returns OutputStream Add test to check that two outputs are the same --- .../jsprit/io/problem/VrpXMLWriter.java | 55 +++++++++++++------ .../jsprit/io/problem/VrpXMLWriterTest.java | 17 ++++++ 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java b/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java index 024d4958..57ba77f2 100644 --- a/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java +++ b/jsprit-io/src/main/java/com/graphhopper/jsprit/io/problem/VrpXMLWriter.java @@ -41,9 +41,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; +import java.io.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -94,8 +92,36 @@ public class VrpXMLWriter { public void write(String filename) { if (!filename.endsWith(".xml")) filename += ".xml"; log.info("write vrp: " + filename); + XMLConf xmlConfig = createXMLConfiguration(); + + try { + xmlConfig.setFileName(filename); + Writer out = new FileWriter(filename); + XMLSerializer serializer = new XMLSerializer(out, createOutputFormat()); + serializer.serialize(xmlConfig.getDocument()); + out.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public OutputStream write() { + XMLConf xmlConfig = createXMLConfiguration(); + OutputStream out = new ByteArrayOutputStream(); + + try { + XMLSerializer serializer = new XMLSerializer(out, createOutputFormat()); + serializer.serialize(xmlConfig.getDocument()); + out.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + return out; + } + + private XMLConf createXMLConfiguration() { XMLConf xmlConfig = new XMLConf(); - xmlConfig.setFileName(filename); xmlConfig.setRootElementName("problem"); xmlConfig.setAttributeSplittingDisabled(true); xmlConfig.setDelimiterParsingDisabled(true); @@ -123,10 +149,6 @@ public class VrpXMLWriter { writeSolutions(xmlConfig); - OutputFormat format = new OutputFormat(); - format.setIndenting(true); - format.setIndent(5); - try { Document document = xmlConfig.createDoc(); @@ -138,17 +160,14 @@ public class VrpXMLWriter { } catch (ConfigurationException e) { throw new RuntimeException(e); } + return xmlConfig; + } - try { - Writer out = new FileWriter(filename); - XMLSerializer serializer = new XMLSerializer(out, format); - serializer.serialize(xmlConfig.getDocument()); - out.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - - + private OutputFormat createOutputFormat() { + OutputFormat format = new OutputFormat(); + format.setIndenting(true); + format.setIndent(5); + return format; } private void writeInitialRoutes(XMLConf xmlConfig) { diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index 5783f398..54ea122f 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -34,6 +34,10 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -621,6 +625,19 @@ public class VrpXMLWriterTest { assertEquals("2", Solutions.bestOf(solutionsToRead).getUnassignedJobs().iterator().next().getId()); } + @Test + public void outputStreamAndFileContentsAreEqual() throws IOException { + VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); + VehicleRoutingProblem vrp = builder.build(); + + new VrpXMLWriter(vrp, null).write(infileName); + String outputStringFromFile = new String(Files.readAllBytes(Paths.get(infileName))); + String outputStringFromStream = new VrpXMLWriter(vrp, null).write().toString(); + + assertEquals(outputStringFromFile, outputStringFromStream); + + } + private VehicleRoutingProblem writeAndRereadXml(VehicleRoutingProblem vrp) { new VrpXMLWriter(vrp, null).write(infileName); From f54241144ccd7900604382d189fb4b08ae110675 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 28 Jun 2017 23:19:15 +0200 Subject: [PATCH 099/106] prio improvement --- .../jsprit/core/algorithm/recreate/BestInsertion.java | 4 ++-- .../core/algorithm/recreate/BestInsertionConcurrent.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java index 329a05ff..9ae1a2cd 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java @@ -100,14 +100,14 @@ public final class BestInsertion extends AbstractInsertionStrategy { private void sometimesSortPriorities(List unassignedJobList) { - if(random.nextDouble() < 0.5){ +// if(random.nextDouble() < 0.5){ Collections.sort(unassignedJobList, new Comparator() { @Override public int compare(Job o1, Job o2) { return o1.getPriority() - o2.getPriority(); } }); - } + //} } } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java index 2b014df0..bb7c11eb 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java @@ -150,14 +150,14 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { } private void sometimesSortPriorities(List unassignedJobList) { - if(random.nextDouble() < 0.5){ + // if(random.nextDouble() < 0.5){ Collections.sort(unassignedJobList, new Comparator() { @Override public int compare(Job o1, Job o2) { return o1.getPriority() - o2.getPriority(); } }); - } + // } } private Insertion getBestInsertion(Batch batch, Job unassignedJob) { From 49c8ade5c42842c87038a63367f4f19a21aa8216 Mon Sep 17 00:00:00 2001 From: oblonski Date: Wed, 28 Jun 2017 23:30:14 +0200 Subject: [PATCH 100/106] continuous delivery of snapshots --- .travis.settings.xml | 27 +++++++++++++++++++++++++++ .travis.yml | 17 +++++++++++++++++ pom.xml | 18 ++++++++++++++++-- 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 .travis.settings.xml diff --git a/.travis.settings.xml b/.travis.settings.xml new file mode 100644 index 00000000..fd37913e --- /dev/null +++ b/.travis.settings.xml @@ -0,0 +1,27 @@ + + + + + + packagecloud-graphhopper + ${env.PACKAGECLOUD_TOKEN} + + + diff --git a/.travis.yml b/.travis.yml index 2406cbd9..40e6f9fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,3 +4,20 @@ jdk: - oraclejdk7 - oraclejdk8 +deploy: + provider: script + script: "cp .travis.settings.xml $HOME/.m2/settings.xml && mvn deploy" + skip_cleanup: true + on: + tags: true + +# do not install anything instead return true via unix command true +install: true +script: mvn clean test +notifications: + email: + - github@graphhopper.com + +# enable container-based stack +sudo: false + diff --git a/pom.xml b/pom.xml index 2a1147c0..7b669fe8 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ HEAD + github https://github.com/graphhopper/jsprit/issues @@ -81,6 +82,15 @@ + + + + io.packagecloud.maven.wagon + maven-packagecloud-wagon + 0.0.4 + + + src/main/java src/test/java target @@ -180,9 +190,13 @@ + + packagecloud-graphhopper + packagecloud+https://packagecloud.io/graphhopper/jsprit + - ossrh - https://oss.sonatype.org/content/repositories/snapshots + packagecloud-graphhopper + packagecloud+https://packagecloud.io/graphhopper/jsprit From f647884184e7f686870979cf7259cc0587177c08 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 29 Jun 2017 09:58:38 +0200 Subject: [PATCH 101/106] make getMostLikely a static method --- .../core/util/UnassignedJobReasonTracker.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index 0a999953..65ce40fb 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -29,6 +29,21 @@ import java.util.*; */ public class UnassignedJobReasonTracker implements JobUnassignedListener { + public static String getMostLikely(Frequency reasons) { + if (reasons == null) return "no reason found"; + Iterator, Long>> entryIterator = reasons.entrySetIterator(); + int maxCount = 0; + String mostLikely = null; + while (entryIterator.hasNext()) { + Map.Entry, Long> entry = entryIterator.next(); + if (entry.getValue() > maxCount) { + Comparable key = entry.getKey(); + mostLikely = key.toString(); + } + } + return mostLikely; + } + Map reasons = new HashMap<>(); Map codesToReason = new HashMap<>(); @@ -141,20 +156,5 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { else return -1; } - private String getMostLikely(Frequency reasons) { - if (reasons == null) return "no reason found"; - Iterator, Long>> entryIterator = reasons.entrySetIterator(); - int maxCount = 0; - String mostLikely = null; - while (entryIterator.hasNext()) { - Map.Entry, Long> entry = entryIterator.next(); - if (entry.getValue() > maxCount) { - Comparable key = entry.getKey(); - mostLikely = key.toString(); - } - } - return mostLikely; - } - } From ecea356c5458c885cf47619b847c201b58136e69 Mon Sep 17 00:00:00 2001 From: oblonski Date: Thu, 29 Jun 2017 12:31:54 +0200 Subject: [PATCH 102/106] improve unassigned reason tracker --- .../core/util/UnassignedJobReasonTracker.java | 71 ++++++++++++------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java index 65ce40fb..03bf7d1d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/util/UnassignedJobReasonTracker.java @@ -29,9 +29,9 @@ import java.util.*; */ public class UnassignedJobReasonTracker implements JobUnassignedListener { - public static String getMostLikely(Frequency reasons) { - if (reasons == null) return "no reason found"; - Iterator, Long>> entryIterator = reasons.entrySetIterator(); + public static String getMostLikelyFailedConstraintName(Frequency failedConstraintNamesFrequency) { + if (failedConstraintNamesFrequency == null) return "no reason found"; + Iterator, Long>> entryIterator = failedConstraintNamesFrequency.entrySetIterator(); int maxCount = 0; String mostLikely = null; while (entryIterator.hasNext()) { @@ -44,19 +44,19 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { return mostLikely; } - Map reasons = new HashMap<>(); + Map failedConstraintNamesFrequencyMapping = new HashMap<>(); - Map codesToReason = new HashMap<>(); + Map codesToHumanReadableReason = new HashMap<>(); Map failedConstraintNamesToCode = new HashMap<>(); - Set constraintsToBeIgnored = new HashSet<>(); + Set failedConstraintNamesToBeIgnored = new HashSet<>(); public UnassignedJobReasonTracker() { - codesToReason.put(1, "cannot serve required skill"); - codesToReason.put(2, "cannot be visited within time window"); - codesToReason.put(3, "does not fit into any vehicle due to capacity"); - codesToReason.put(4, "cannot be assigned due to max distance constraint of vehicle"); + codesToHumanReadableReason.put(1, "cannot serve required skill"); + codesToHumanReadableReason.put(2, "cannot be visited within time window"); + codesToHumanReadableReason.put(3, "does not fit into any vehicle due to capacity"); + codesToHumanReadableReason.put(4, "cannot be assigned due to max distance constraint of vehicle"); failedConstraintNamesToCode.put("HardSkillConstraint", 1); failedConstraintNamesToCode.put("VehicleDependentTimeWindowConstraints", 2); @@ -67,24 +67,24 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { } public void ignore(String simpleNameOfConstraint) { - constraintsToBeIgnored.add(simpleNameOfConstraint); + failedConstraintNamesToBeIgnored.add(simpleNameOfConstraint); } @Override public void informJobUnassigned(Job unassigned, Collection failedConstraintNames) { - if (!this.reasons.containsKey(unassigned.getId())) { - this.reasons.put(unassigned.getId(), new Frequency()); + if (!this.failedConstraintNamesFrequencyMapping.containsKey(unassigned.getId())) { + this.failedConstraintNamesFrequencyMapping.put(unassigned.getId(), new Frequency()); } for (String r : failedConstraintNames) { - if (constraintsToBeIgnored.contains(r)) continue; - this.reasons.get(unassigned.getId()).addValue(r); + if (failedConstraintNamesToBeIgnored.contains(r)) continue; + this.failedConstraintNamesFrequencyMapping.get(unassigned.getId()).addValue(r); } } public void put(String simpleNameOfFailedConstraint, int code, String reason) { if (code <= 20) throw new IllegalArgumentException("first 20 codes are reserved internally. choose a code > 20"); - codesToReason.put(code, reason); + codesToHumanReadableReason.put(code, reason); if (failedConstraintNamesToCode.containsKey(simpleNameOfFailedConstraint)) { throw new IllegalArgumentException(simpleNameOfFailedConstraint + " already assigned to code and reason"); } else failedConstraintNamesToCode.put(simpleNameOfFailedConstraint, code); @@ -95,8 +95,18 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * * @return */ + @Deprecated public Map getReasons() { - return Collections.unmodifiableMap(reasons); + return Collections.unmodifiableMap(failedConstraintNamesFrequencyMapping); + } + + /** + * For each job id, it returns frequency distribution of failed constraints (simple name of constraint) in an unmodifiable map. + * + * @return + */ + public Map getFailedConstraintNamesFrequencyMapping() { + return Collections.unmodifiableMap(failedConstraintNamesFrequencyMapping); } /** @@ -105,7 +115,7 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public Map getCodesToReason() { - return Collections.unmodifiableMap(codesToReason); + return Collections.unmodifiableMap(codesToHumanReadableReason); } /** @@ -117,6 +127,17 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { return Collections.unmodifiableMap(failedConstraintNamesToCode); } + public int getCode(String failedConstraintName) { + return toCode(failedConstraintName); + } + + public String getHumanReadableReason(int code) { + return getCodesToReason().get(code); + } + + public String getHumanReadableReason(String failedConstraintName) { + return getCodesToReason().get(getCode(failedConstraintName)); + } /** * Returns the most likely reason code i.e. the reason (failed constraint) being observed most often. * @@ -129,9 +150,9 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public int getMostLikelyReasonCode(String jobId) { - if (!this.reasons.containsKey(jobId)) return -1; - Frequency reasons = this.reasons.get(jobId); - String mostLikelyReason = getMostLikely(reasons); + if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return -1; + Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId); + String mostLikelyReason = getMostLikelyFailedConstraintName(reasons); return toCode(mostLikelyReason); } @@ -142,12 +163,12 @@ public class UnassignedJobReasonTracker implements JobUnassignedListener { * @return */ public String getMostLikelyReason(String jobId) { - if (!this.reasons.containsKey(jobId)) return "no reason found"; - Frequency reasons = this.reasons.get(jobId); - String mostLikelyReason = getMostLikely(reasons); + if (!this.failedConstraintNamesFrequencyMapping.containsKey(jobId)) return "no reason found"; + Frequency reasons = this.failedConstraintNamesFrequencyMapping.get(jobId); + String mostLikelyReason = getMostLikelyFailedConstraintName(reasons); int code = toCode(mostLikelyReason); if (code == -1) return mostLikelyReason; - else return codesToReason.get(code); + else return codesToHumanReadableReason.get(code); } private int toCode(String mostLikelyReason) { From 1ef29a268cbfb05580387f55617c9447ff16fdd6 Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 30 Jun 2017 08:47:55 +0200 Subject: [PATCH 103/106] sort jobs acc to priorities --- .../recreate/AccordingToPriorities.java | 35 +++++++++++++++++++ .../algorithm/recreate/BestInsertion.java | 19 +++------- .../recreate/BestInsertionConcurrent.java | 17 +++------ 3 files changed, 45 insertions(+), 26 deletions(-) create mode 100644 jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AccordingToPriorities.java diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AccordingToPriorities.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AccordingToPriorities.java new file mode 100644 index 00000000..928e41a8 --- /dev/null +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/AccordingToPriorities.java @@ -0,0 +1,35 @@ +/* + * Licensed to GraphHopper GmbH under one or more contributor + * license agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + * + * GraphHopper GmbH licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.graphhopper.jsprit.core.algorithm.recreate; + +import com.graphhopper.jsprit.core.problem.job.Job; + +import java.util.Comparator; + +/** + * Created by schroeder on 30/06/17. + */ +class AccordingToPriorities implements Comparator { + + @Override + public int compare(Job o1, Job o2) { + return o1.getPriority() - o2.getPriority(); + } + +} diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java index 9ae1a2cd..576e41f4 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertion.java @@ -24,7 +24,10 @@ import com.graphhopper.jsprit.core.util.NoiseMaker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; /** @@ -63,7 +66,7 @@ public final class BestInsertion extends AbstractInsertionStrategy { List badJobs = new ArrayList(unassignedJobs.size()); List unassignedJobList = new ArrayList(unassignedJobs); Collections.shuffle(unassignedJobList, random); - sometimesSortPriorities(unassignedJobList); + Collections.sort(unassignedJobList, new AccordingToPriorities()); for (Job unassignedJob : unassignedJobList) { Insertion bestInsertion = null; InsertionData empty = new InsertionData.NoInsertionFound(); @@ -98,16 +101,4 @@ public final class BestInsertion extends AbstractInsertionStrategy { return badJobs; } - - private void sometimesSortPriorities(List unassignedJobList) { -// if(random.nextDouble() < 0.5){ - Collections.sort(unassignedJobList, new Comparator() { - @Override - public int compare(Job o1, Job o2) { - return o1.getPriority() - o2.getPriority(); - } - }); - //} - } - } diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java index bb7c11eb..c7e6ae94 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/recreate/BestInsertionConcurrent.java @@ -27,7 +27,10 @@ import com.graphhopper.jsprit.core.problem.vehicle.Vehicle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import java.util.concurrent.*; @@ -99,7 +102,7 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { List badJobs = new ArrayList(unassignedJobs.size()); List unassignedJobList = new ArrayList(unassignedJobs); Collections.shuffle(unassignedJobList, random); - sometimesSortPriorities(unassignedJobList); + Collections.sort(unassignedJobList, new AccordingToPriorities()); List batches = distributeRoutes(vehicleRoutes, nuOfBatches); List failedConstraintNames = new ArrayList<>(); for (final Job unassignedJob : unassignedJobList) { @@ -149,16 +152,6 @@ public final class BestInsertionConcurrent extends AbstractInsertionStrategy { return badJobs; } - private void sometimesSortPriorities(List unassignedJobList) { - // if(random.nextDouble() < 0.5){ - Collections.sort(unassignedJobList, new Comparator() { - @Override - public int compare(Job o1, Job o2) { - return o1.getPriority() - o2.getPriority(); - } - }); - // } - } private Insertion getBestInsertion(Batch batch, Job unassignedJob) { Insertion bestInsertion = null; From dfc8068eef20d256d0e7a6488a406287230b5c88 Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 30 Jun 2017 10:43:34 +0200 Subject: [PATCH 104/106] rm file --- .../test/resources/infiniteWriterV2Test.xml | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 jsprit-io/src/test/resources/infiniteWriterV2Test.xml diff --git a/jsprit-io/src/test/resources/infiniteWriterV2Test.xml b/jsprit-io/src/test/resources/infiniteWriterV2Test.xml deleted file mode 100644 index 9d863897..00000000 --- a/jsprit-io/src/test/resources/infiniteWriterV2Test.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - INFINITE - - - - - - [x=1.0][y=2.0] - - - 100.0 - - - 1.0 - 2.0 - - - - - - delLoc - - - 50.0 - - - 3.0 - 4.0 - - - - - 10 - - skill3, skill1, skill2 - - - From d8f7af7fb5a426d094db93092f62b0f94fe30d42 Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 30 Jun 2017 10:44:39 +0200 Subject: [PATCH 105/106] add helper --- .../acceptor/SchrimpfAcceptance.java | 39 ++++++++++++++++++- .../VariationCoefficientTermination.java | 15 +++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/acceptor/SchrimpfAcceptance.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/acceptor/SchrimpfAcceptance.java index f89960b0..f104a1ca 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/acceptor/SchrimpfAcceptance.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/acceptor/SchrimpfAcceptance.java @@ -25,7 +25,9 @@ import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolutio import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** @@ -78,7 +80,6 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList private final int solutionMemory; - public SchrimpfAcceptance(int solutionMemory, double alpha) { this.alpha = alpha; this.solutionMemory = solutionMemory; @@ -110,6 +111,32 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList return solutionAccepted; } + public boolean acceptSolution(VehicleRoutingProblemSolution solution, VehicleRoutingProblemSolution newSolution) { + List solutions = new ArrayList<>(); + solutions.add(solution); + 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); + solutionAccepted = true; + } + } + return solutionAccepted; + } + @Override public String toString() { return "[name=SchrimpfAcceptance][alpha=" + alpha + "]"; @@ -136,6 +163,16 @@ public class SchrimpfAcceptance implements SolutionAcceptor, IterationStartsList this.initialThreshold = initialThreshold; } + public void setMaxIterations(int maxIteration) { + this.maxIterations = maxIteration; + } + + public void incIteration() { + currentIteration++; + } + + ; + @Override public void informAlgorithmStarts(VehicleRoutingProblem problem, VehicleRoutingAlgorithm algorithm, Collection solutions) { reset(); diff --git a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/termination/VariationCoefficientTermination.java b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/termination/VariationCoefficientTermination.java index 5e900b35..5f177c3d 100644 --- a/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/termination/VariationCoefficientTermination.java +++ b/jsprit-core/src/main/java/com/graphhopper/jsprit/core/algorithm/termination/VariationCoefficientTermination.java @@ -30,7 +30,9 @@ import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; /** @@ -119,9 +121,22 @@ public class VariationCoefficientTermination implements PrematureAlgorithmTermin } } + public void informIterationEnds(int i, VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) { + informIterationEnds(i, problem, toList(solution)); + } + + private List toList(VehicleRoutingProblemSolution solution) { + List solutions = new ArrayList<>(); + solutions.add(solution); + return solutions; + } + @Override public void informIterationStarts(int i, VehicleRoutingProblem problem, Collection solutions) { if (lastAccepted == null) lastAccepted = Solutions.bestOf(solutions); } + public void informIterationStarts(int i, VehicleRoutingProblem problem, VehicleRoutingProblemSolution solution) { + informIterationStarts(i, problem, toList(solution)); + } } From 0dd74b5bf98f617ae4223e3a1a8f4081f996486d Mon Sep 17 00:00:00 2001 From: oblonski Date: Fri, 30 Jun 2017 11:35:15 +0200 Subject: [PATCH 106/106] get rid of file writing/reading --- .../jsprit/io/problem/VrpXMLWriterTest.java | 54 +++++-------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java index 54ea122f..0075600f 100644 --- a/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java +++ b/jsprit-io/src/test/java/com/graphhopper/jsprit/io/problem/VrpXMLWriterTest.java @@ -31,13 +31,11 @@ import com.graphhopper.jsprit.core.util.Coordinate; import com.graphhopper.jsprit.core.util.Solutions; import com.graphhopper.jsprit.io.util.TestUtils; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -46,34 +44,6 @@ import static org.junit.Assert.*; public class VrpXMLWriterTest { - private String infileName; - - @Before - public void doBefore() { - infileName = "src/test/resources/infiniteWriterV2Test.xml"; - } - - @Test - public void whenWritingInfiniteVrp_itWritesCorrectly() { - VehicleRoutingProblem.Builder builder = VehicleRoutingProblem.Builder.newInstance(); - builder.setFleetSize(VehicleRoutingProblem.FleetSize.INFINITE); - VehicleTypeImpl type = VehicleTypeImpl.Builder.newInstance("vehType").addCapacityDimension(0, 20).build(); - VehicleImpl vehicle = VehicleImpl.Builder.newInstance("myVehicle").setStartLocation(TestUtils.loc("loc")).setType(type).build(); - builder.addVehicle(vehicle); - VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - } - - @Test - public void whenWritingFiniteVrp_itWritesAndReadsCorrectly() { - VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); - builder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE); - - VehicleRoutingProblem vrp = builder.build(); - writeAndRereadXml(vrp); - } - - @Test public void whenWritingServices_itWritesThemCorrectly() { VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); @@ -630,8 +600,10 @@ public class VrpXMLWriterTest { VehicleRoutingProblem.Builder builder = twoVehicleTypesAndImpls(); VehicleRoutingProblem vrp = builder.build(); - new VrpXMLWriter(vrp, null).write(infileName); - String outputStringFromFile = new String(Files.readAllBytes(Paths.get(infileName))); + VrpXMLWriter vrpXMLWriter = new VrpXMLWriter(vrp, null); + ByteArrayOutputStream os = (ByteArrayOutputStream) vrpXMLWriter.write(); + + String outputStringFromFile = new String(os.toByteArray()); String outputStringFromStream = new VrpXMLWriter(vrp, null).write().toString(); assertEquals(outputStringFromFile, outputStringFromStream); @@ -639,19 +611,21 @@ public class VrpXMLWriterTest { } private VehicleRoutingProblem writeAndRereadXml(VehicleRoutingProblem vrp) { - new VrpXMLWriter(vrp, null).write(infileName); - + VrpXMLWriter vrpXMLWriter = new VrpXMLWriter(vrp, null); + ByteArrayOutputStream os = (ByteArrayOutputStream) vrpXMLWriter.write(); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); - new VrpXMLReader(vrpToReadBuilder, null).read(infileName); + new VrpXMLReader(vrpToReadBuilder, null).read(is); return vrpToReadBuilder.build(); } private List writeAndRereadXmlWithSolutions(VehicleRoutingProblem vrp, List solutions) { - new VrpXMLWriter(vrp, solutions).write(infileName); - + VrpXMLWriter vrpXMLWriter = new VrpXMLWriter(vrp, solutions); + ByteArrayOutputStream os = (ByteArrayOutputStream) vrpXMLWriter.write(); + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); VehicleRoutingProblem.Builder vrpToReadBuilder = VehicleRoutingProblem.Builder.newInstance(); List solutionsToRead = new ArrayList(); - new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(infileName); + new VrpXMLReader(vrpToReadBuilder, solutionsToRead).read(is); return solutionsToRead; }
" + date + "" + date + "