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 prioListeners = new ArrayList(); - AbstractInsertionStrategy insertion = getInsertionStrategy(moduleConfig, vrp, vehicleFleetManager, activityStates, - definedClasses, modKey, prioListeners); - SearchStrategyModule module = getModule(moduleName, insertion, vrp); - definedClasses.put(strategyModuleKey, module); - algorithmListeners.addAll(prioListeners); - return module; - } + +// if(moduleName.equals("bestInsertion") || moduleName.equals("regretInsertion")){ +// List prioListeners = new ArrayList(); +// AbstractInsertionStrategy insertion = getInsertionStrategy(moduleConfig, vrp, vehicleFleetManager, activityStates, +// definedClasses, modKey, prioListeners); +// SearchStrategyModule module = getModule(moduleName, insertion, vrp); +// definedClasses.put(strategyModuleKey, module); +// algorithmListeners.addAll(prioListeners); +// return module; +// } // if(moduleName.equals("regretInsertion")){ // List prioListeners = new ArrayList(); // AbstractInsertionKey insertionKey = new AbstractInsertionKey(modKey); @@ -664,20 +697,30 @@ public class VehicleRoutingAlgorithms { // algorithmListeners.addAll(prioListeners); // return module; // } - if(moduleName.equals("randomRuin")){ - double shareToRuin = moduleConfig.getDouble("share"); - RuinStrategy ruin = getRandomRuin(vrp, activityStates,definedClasses, modKey, shareToRuin); - SearchStrategyModule module = getModule(moduleName, ruin); - definedClasses.put(strategyModuleKey, module); - return module; - } - if(moduleName.equals("radialRuin")){ - double shareToRuin = moduleConfig.getDouble("share"); - RuinStrategy ruin = getRadialRuin(vrp, activityStates,definedClasses, modKey, shareToRuin); - SearchStrategyModule module = getModule(moduleName, ruin); - definedClasses.put(strategyModuleKey, module); - return module; - } +// if(moduleName.equals("randomRuin")){ +// double shareToRuin = moduleConfig.getDouble("share"); +// RuinStrategy ruin = getRandomRuin(vrp, activityStates,definedClasses, modKey, shareToRuin); +// SearchStrategyModule module = getModule(moduleName, ruin); +// definedClasses.put(strategyModuleKey, module); +// return module; +// } +// if(moduleName.equals("radialRuin")){ +// double shareToRuin = moduleConfig.getDouble("share"); +// String ruin_distance = moduleConfig.getString("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'"); +// } +// RuinStrategy ruin = getRadialRuin(vrp, activityStates,definedClasses, modKey, shareToRuin, jobDistance); +// SearchStrategyModule module = getModule(moduleName, ruin); +// definedClasses.put(strategyModuleKey, module); +// return module; +// } if(moduleName.equals("gendreauPostOpt")){ int iterations = moduleConfig.getInt("iterations"); double share = moduleConfig.getDouble("share"); @@ -734,13 +777,11 @@ public class VehicleRoutingAlgorithms { return bestInsertion; } - private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp, - RouteStates activityStates, TypedMap definedClasses, - ModKey modKey, double shareToRuin) { + private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp, RouteStates activityStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) { RuinStrategyKey stratKey = new RuinStrategyKey(modKey); RuinStrategy ruin = definedClasses.get(stratKey); if(ruin == null){ - ruin = RuinRadial.newInstance(vrp, shareToRuin, new JobDistanceAvgCosts(vrp.getTransportCosts()), new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts())); + ruin = RuinRadial.newInstance(vrp, shareToRuin, jobDistance, new JobRemoverImpl(), new TourStateUpdater(activityStates, vrp.getTransportCosts(), vrp.getActivityCosts())); definedClasses.put(stratKey, ruin); } return ruin; @@ -778,12 +819,6 @@ public class VehicleRoutingAlgorithms { double penalty = 0.0; if(jobsInSolution != vrp.getJobs().values().size()){ throw new IllegalStateException("solution not valid\n" + "#jobsInSolution=" + jobsInSolution + " #jobsInVrp=" + vrp.getJobs().values().size()); -// logger.warn("solution not valid\n" + "#jobsInSolution=" + jobsInSolution + " #jobsInVrp=" + vrp.getJobs().values().size()); -//// throw new IllegalStateException("solution not valid\n" + -//// "#jobsInSolution=" + jobsInSolution + " #jobsInVrp=" + vrp.getJobs().values().size()); -// logger.warn("a penalty of 1000 is added for each unassigned customer"); -// penalty = (vrp.getJobs().values().size() - jobsInSolution)*1000.0; -// logger.warn("penalty = " + penalty); } double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes()); vrpSolution.setCost(totalCost + penalty); @@ -841,37 +876,37 @@ public class VehicleRoutingAlgorithms { } - private static SearchStrategyModule getModule(final String moduleName, final RuinStrategy ruin) { - - - return new SearchStrategyModule() { - - private Logger logger = Logger.getLogger(SearchStrategyModule.class); - - @Override - public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { - ruin.ruin(vrpSolution.getRoutes()); - return vrpSolution; - } - - @Override - public String toString() { - return "[name="+ruin+"]"; - } - - @Override - public String getName() { - return moduleName; - } - - @Override - public void addModuleListener(SearchStrategyModuleListener moduleListener) { - // TODO Auto-generated method stub - - } - - }; - } +// private static SearchStrategyModule getModule(final String moduleName, final RuinStrategy ruin) { +// +// +// return new SearchStrategyModule() { +// +// private Logger logger = Logger.getLogger(SearchStrategyModule.class); +// +// @Override +// public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { +// ruin.ruin(vrpSolution.getRoutes()); +// return vrpSolution; +// } +// +// @Override +// public String toString() { +// return "[name="+ruin+"]"; +// } +// +// @Override +// public String getName() { +// return moduleName; +// } +// +// @Override +// public void addModuleListener(SearchStrategyModuleListener moduleListener) { +// // TODO Auto-generated method stub +// +// } +// +// }; +// } diff --git a/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java b/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java index 79695973..2534d1fa 100644 --- a/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java +++ b/jsprit-core/src/main/java/basics/VehicleRoutingProblem.java @@ -242,6 +242,12 @@ public class VehicleRoutingProblem { return this; } + /** + * Sets the neighborhood. + * + * @param neighborhood + * @return + */ public Builder setNeighborhood(Neighborhood neighborhood){ this.neighborhood = neighborhood; return this; @@ -261,6 +267,13 @@ public class VehicleRoutingProblem { return this; } + /** + * Builds the {@link VehicleRoutingProblem}. + * + *

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 jobs) { for(Job j : jobs){ addJob(j); @@ -282,6 +301,12 @@ public class VehicleRoutingProblem { return this; } + /** + * Adds a collection of vehicles. + * + * @param vehicles + * @return + */ public Builder addAllVehicles(Collection vehicles) { for(Vehicle v : vehicles){ addVehicle(v); @@ -289,11 +314,20 @@ public class VehicleRoutingProblem { return this; } - + /** + * Gets an unmodifiable collection of already added vehicles. + * + * @return collection of vehicles + */ public Collection getAddedVehicles(){ return Collections.unmodifiableCollection(vehicles); } + /** + * Gets an unmodifiable collection of already added services. + * + * @return collection of services + */ public Collection getAddedServices(){ return Collections.unmodifiableCollection(services); } diff --git a/jsprit-core/src/main/resources/algorithm_schema.xsd b/jsprit-core/src/main/resources/algorithm_schema.xsd index 2140340d..348b07a7 100644 --- a/jsprit-core/src/main/resources/algorithm_schema.xsd +++ b/jsprit-core/src/main/resources/algorithm_schema.xsd @@ -135,7 +135,7 @@ - + @@ -143,6 +143,13 @@ + + + + + + + diff --git a/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java b/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java index f9288f40..db93a116 100644 --- a/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java +++ b/jsprit-core/src/test/java/algorithms/TestAlgorithmReader.java @@ -230,43 +230,7 @@ public class TestAlgorithmReader { for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){ nOfModules += strat.getSearchStrategyModules().size(); } - assertEquals(6, nOfModules); - } - - @Test - public void whenCreatingAlgorithm_nOfUniqueInstancesOfInsertionModulesIsCorrect(){ - VehicleRoutingAlgorithm algo = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, config); - int nOfBestInsertions = 0; - Set uniqueStrategies = new HashSet(); - for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){ - for(SearchStrategyModule module : strat.getSearchStrategyModules()){ - if(module.getName().equals("bestInsertion")){ - nOfBestInsertions++; - uniqueStrategies.add(module); - } - } - - } - assertEquals(3, nOfBestInsertions); - assertEquals(2, uniqueStrategies.size()); - } - - @Test - public void whenCreatingAlgorithm_nOfUniqueInstancesOfRuinModulesIsCorrect(){ - VehicleRoutingAlgorithm algo = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, config); - int nOfRuinModules = 0; - Set uniqueStrategies = new HashSet(); - for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){ - for(SearchStrategyModule module : strat.getSearchStrategyModules()){ - if(module.getName().endsWith("Ruin")){ - nOfRuinModules++; - uniqueStrategies.add(module); - } - } - - } - assertEquals(3, nOfRuinModules); - assertEquals(2, uniqueStrategies.size()); + assertEquals(3, nOfModules); } @Test diff --git a/jsprit-core/src/test/resources/testConfig.xml b/jsprit-core/src/test/resources/testConfig.xml index 149aeb5c..4b5cb4e0 100755 --- a/jsprit-core/src/test/resources/testConfig.xml +++ b/jsprit-core/src/test/resources/testConfig.xml @@ -34,11 +34,12 @@ - - 0.5 + + + 0.5 + + - - 0.4 @@ -47,10 +48,12 @@ - - 0.1 + + + 0.1 + + - 0.4 @@ -59,11 +62,12 @@ - - 0.3 - euclid + + + 0.3 + + - 0.2