From 3587c7fe949ea8633d304e5638b347fc9c712efb Mon Sep 17 00:00:00 2001 From: Stefan Schroeder <4sschroeder@gmail.com> Date: Tue, 18 Jun 2013 09:28:33 +0200 Subject: [PATCH] improve JobDistance for RadialRuin --- .../algorithms/EuclideanServiceDistance.java | 44 +++++ .../java/algorithms/JobDistanceAvgCosts.java | 47 +++-- .../java/algorithms/JobDistanceBeeline.java | 13 -- .../algorithms/VehicleRoutingAlgorithms.java | 165 +++++++++++------- .../java/basics/VehicleRoutingProblem.java | 36 +++- .../src/main/resources/algorithm_schema.xsd | 9 +- .../java/algorithms/TestAlgorithmReader.java | 38 +--- jsprit-core/src/test/resources/testConfig.xml | 26 +-- 8 files changed, 233 insertions(+), 145 deletions(-) create mode 100644 jsprit-core/src/main/java/algorithms/EuclideanServiceDistance.java diff --git a/jsprit-core/src/main/java/algorithms/EuclideanServiceDistance.java b/jsprit-core/src/main/java/algorithms/EuclideanServiceDistance.java new file mode 100644 index 00000000..84562fbc --- /dev/null +++ b/jsprit-core/src/main/java/algorithms/EuclideanServiceDistance.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2011 Stefan Schroeder. + * eMail: stefan.schroeder@kit.edu + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * Stefan Schroeder - initial API and implementation + ******************************************************************************/ +package algorithms; + +import util.EuclideanDistanceCalculator; +import basics.Job; +import basics.Service; + +class EuclideanServiceDistance implements JobDistance { + + public EuclideanServiceDistance() { + super(); + } + + @Override + public double calculateDistance(Job i, Job j) { + double avgCost = 0.0; + if (i instanceof Service && j instanceof Service) { + if (i.equals(j)) { + avgCost = 0.0; + } else { + Service s_i = (Service) i; + Service s_j = (Service) j; + if(s_i.getCoord() == null || s_j.getCoord() == null) throw new IllegalStateException("cannot calculate euclidean distance. since service coords are missing"); + avgCost = EuclideanDistanceCalculator.calculateDistance(s_i.getCoord(), s_j.getCoord()); + } + } else { + throw new UnsupportedOperationException( + "currently, this class just works with shipments and services."); + } + return avgCost; + } + +} diff --git a/jsprit-core/src/main/java/algorithms/JobDistanceAvgCosts.java b/jsprit-core/src/main/java/algorithms/JobDistanceAvgCosts.java index 74c742e8..176cb946 100644 --- a/jsprit-core/src/main/java/algorithms/JobDistanceAvgCosts.java +++ b/jsprit-core/src/main/java/algorithms/JobDistanceAvgCosts.java @@ -12,14 +12,25 @@ ******************************************************************************/ package algorithms; +import org.apache.log4j.Logger; + import basics.Job; import basics.Service; import basics.costs.VehicleRoutingTransportCosts; - +/** + * Calculator that calculates average distance between two jobs based on the input-transport costs. + * + *
If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs. + * + * @author stefan schroeder + * + */ class JobDistanceAvgCosts implements JobDistance { + private static Logger log = Logger.getLogger(JobDistanceAvgCosts.class); + private VehicleRoutingTransportCosts costs; public JobDistanceAvgCosts(VehicleRoutingTransportCosts costs) { @@ -28,29 +39,21 @@ class JobDistanceAvgCosts implements JobDistance { } + /** + * Calculates and returns the average distance between two jobs based on the input-transport costs. + * + *
If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
+ */
@Override
public double calculateDistance(Job i, Job j) {
double avgCost = 0.0;
-// if (i instanceof Shipment && j instanceof Shipment) {
-// if (i.equals(j)) {
-// avgCost = 0.0;
-// } else {
-// Shipment s_i = (Shipment) i;
-// Shipment s_j = (Shipment) j;
-// double cost_i1_j1 = calcDist(s_i.getFromId(), s_j.getFromId());
-// double cost_i1_j2 = calcDist(s_i.getFromId(), s_j.getToId());
-// double cost_i2_j1 = calcDist(s_i.getToId(), s_j.getFromId());
-// double cost_i2_j2 = calcDist(s_i.getToId(), s_j.getToId());
-// avgCost = (cost_i1_j1 + cost_i1_j2 + cost_i2_j1 + cost_i2_j2) / 4;
-// }
-// } else
if (i instanceof Service && j instanceof Service) {
if (i.equals(j)) {
avgCost = 0.0;
} else {
Service s_i = (Service) i;
Service s_j = (Service) j;
- avgCost = calcDist(s_i.getLocationId(), s_j.getLocationId());
+ avgCost = calcDist(s_i, s_j);
}
} else {
throw new UnsupportedOperationException(
@@ -59,8 +62,18 @@ class JobDistanceAvgCosts implements JobDistance {
return avgCost;
}
- private double calcDist(String from, String to) {
- return costs.getTransportCost(from, to, 0.0, null, null);
+ private double calcDist(Service s_i, Service s_j) {
+ double distance;
+ try{
+ distance = costs.getTransportCost(s_i.getLocationId(), s_j.getLocationId(), 0.0, null, null);
+ return distance;
+ }
+ catch(IllegalStateException e){
+ // now try the euclidean distance between these two services
+ }
+ EuclideanServiceDistance euclidean = new EuclideanServiceDistance();
+ distance = euclidean.calculateDistance(s_i, s_j);
+ return distance;
}
}
diff --git a/jsprit-core/src/main/java/algorithms/JobDistanceBeeline.java b/jsprit-core/src/main/java/algorithms/JobDistanceBeeline.java
index b0fe0f5c..aef489fe 100644
--- a/jsprit-core/src/main/java/algorithms/JobDistanceBeeline.java
+++ b/jsprit-core/src/main/java/algorithms/JobDistanceBeeline.java
@@ -31,19 +31,6 @@ class JobDistanceBeeline implements JobDistance {
@Override
public double calculateDistance(Job i, Job j) {
double avgCost = 0.0;
-// if (i instanceof Shipment && j instanceof Shipment) {
-// if (i.equals(j)) {
-// avgCost = 0.0;
-// } else {
-// Shipment s_i = (Shipment) i;
-// Shipment s_j = (Shipment) j;
-// double cost_i1_j1 = calcDist(s_i.getFromId(), s_j.getFromId());
-// double cost_i1_j2 = calcDist(s_i.getFromId(), s_j.getToId());
-// double cost_i2_j1 = calcDist(s_i.getToId(), s_j.getFromId());
-// double cost_i2_j2 = calcDist(s_i.getToId(), s_j.getToId());
-// avgCost = (cost_i1_j1 + cost_i1_j2 + cost_i2_j1 + cost_i2_j2) / 4;
-// }
-// } else
if (i instanceof Service && j instanceof Service) {
if (i.equals(j)) {
avgCost = 0.0;
diff --git a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java
index 75236cd3..68d81cc2 100644
--- a/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java
+++ b/jsprit-core/src/main/java/algorithms/VehicleRoutingAlgorithms.java
@@ -359,6 +359,13 @@ public class VehicleRoutingAlgorithms {
private VehicleRoutingAlgorithms(){}
+ /**
+ * Creates a {@link VehicleRoutingAlgorithm} from a AlgorithConfig based on the input vrp.
+ *
+ * @param vrp
+ * @param algorithmConfig
+ * @return {@link VehicleRoutingAlgorithm}
+ */
public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, final AlgorithmConfig algorithmConfig){
return createAlgo(vrp,algorithmConfig.getXMLConfiguration());
}
@@ -368,6 +375,13 @@ public class VehicleRoutingAlgorithms {
return createAlgo(vrp,config);
}
+ /**
+ * Read and creates a {@link VehicleRoutingAlgorithm} from an url.
+ *
+ * @param vrp
+ * @param configURL
+ * @return {@link VehicleRoutingProblem}
+ */
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final URL configURL){
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
@@ -375,6 +389,13 @@ public class VehicleRoutingAlgorithms {
return createAlgo(vrp,algorithmConfig.getXMLConfiguration());
}
+ /**
+ * Read and creates {@link VehicleRoutingAlgorithm} from config-file.
+ *
+ * @param vrp
+ * @param configFileName
+ * @return
+ */
public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final String configFileName){
AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
@@ -572,6 +593,7 @@ public class VehicleRoutingAlgorithms {
StrategyModuleKey strategyModuleKey = new StrategyModuleKey(modKey);
SearchStrategyModule definedModule = definedClasses.get(strategyModuleKey);
if(definedModule != null) return definedModule;
+
if(moduleName.equals("ruin_and_recreate")){
String ruin_name = moduleConfig.getString("ruin[@name]");
if(ruin_name == null) throw new IllegalStateException("module.ruin[@name] is missing.");
@@ -586,7 +608,17 @@ public class VehicleRoutingAlgorithms {
ruin = getRandomRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin);
}
else if(ruin_name.equals("radialRuin")){
- ruin = getRadialRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin);
+ String ruin_distance = moduleConfig.getString("ruin.distance");
+ JobDistance jobDistance;
+ if(ruin_distance == null) jobDistance = new JobDistanceAvgCosts(vrp.getTransportCosts());
+ else {
+ if(ruin_distance.equals("euclidean")){
+ jobDistance = new EuclideanServiceDistance();
+ }
+ else throw new IllegalStateException("does not know ruin.distance " + ruin_distance + ". either ommit ruin.distance then the "
+ + "default is used or use 'euclidean'");
+ }
+ ruin = getRadialRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin, jobDistance);
}
else throw new IllegalStateException("ruin[@name] " + ruin_name + " is not known. Use either randomRuin or radialRuin.");
@@ -643,15 +675,16 @@ public class VehicleRoutingAlgorithms {
};
return module;
}
- if(moduleName.equals("bestInsertion") || moduleName.equals("regretInsertion")){
- List If {@link VehicleRoutingTransportCosts} are not set, {@link CrowFlyCosts} is used.
+ *
+ * @return {@link VehicleRoutingProblem}
+ */
public VehicleRoutingProblem build() {
log.info("build problem ...");
if(transportCosts == null){
@@ -275,6 +288,12 @@ public class VehicleRoutingProblem {
return this;
}
+ /**
+ * Adds a collection of jobs.
+ *
+ * @param jobs
+ * @return
+ */
public Builder addAllJobs(Collection