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

improve JobDistance for RadialRuin

This commit is contained in:
Stefan Schroeder 2013-06-18 09:28:33 +02:00
parent b0de3eef86
commit 3587c7fe94
8 changed files with 233 additions and 145 deletions

View file

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

View file

@ -12,14 +12,25 @@
******************************************************************************/ ******************************************************************************/
package algorithms; package algorithms;
import org.apache.log4j.Logger;
import basics.Job; import basics.Job;
import basics.Service; import basics.Service;
import basics.costs.VehicleRoutingTransportCosts; import basics.costs.VehicleRoutingTransportCosts;
/**
* Calculator that calculates average distance between two jobs based on the input-transport costs.
*
* <p>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 { class JobDistanceAvgCosts implements JobDistance {
private static Logger log = Logger.getLogger(JobDistanceAvgCosts.class);
private VehicleRoutingTransportCosts costs; private VehicleRoutingTransportCosts costs;
public JobDistanceAvgCosts(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.
*
* <p>If the distance between two jobs cannot be calculated with input-transport costs, it tries the euclidean distance between these jobs.
*/
@Override @Override
public double calculateDistance(Job i, Job j) { public double calculateDistance(Job i, Job j) {
double avgCost = 0.0; 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 instanceof Service && j instanceof Service) {
if (i.equals(j)) { if (i.equals(j)) {
avgCost = 0.0; avgCost = 0.0;
} else { } else {
Service s_i = (Service) i; Service s_i = (Service) i;
Service s_j = (Service) j; Service s_j = (Service) j;
avgCost = calcDist(s_i.getLocationId(), s_j.getLocationId()); avgCost = calcDist(s_i, s_j);
} }
} else { } else {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
@ -59,8 +62,18 @@ class JobDistanceAvgCosts implements JobDistance {
return avgCost; return avgCost;
} }
private double calcDist(String from, String to) { private double calcDist(Service s_i, Service s_j) {
return costs.getTransportCost(from, to, 0.0, null, null); 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;
} }
} }

View file

@ -31,19 +31,6 @@ class JobDistanceBeeline implements JobDistance {
@Override @Override
public double calculateDistance(Job i, Job j) { public double calculateDistance(Job i, Job j) {
double avgCost = 0.0; 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 instanceof Service && j instanceof Service) {
if (i.equals(j)) { if (i.equals(j)) {
avgCost = 0.0; avgCost = 0.0;

View file

@ -359,6 +359,13 @@ public class VehicleRoutingAlgorithms {
private 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){ public static VehicleRoutingAlgorithm createAlgorithm(final VehicleRoutingProblem vrp, final AlgorithmConfig algorithmConfig){
return createAlgo(vrp,algorithmConfig.getXMLConfiguration()); return createAlgo(vrp,algorithmConfig.getXMLConfiguration());
} }
@ -368,6 +375,13 @@ public class VehicleRoutingAlgorithms {
return createAlgo(vrp,config); 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){ public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final URL configURL){
AlgorithmConfig algorithmConfig = new AlgorithmConfig(); AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig); AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
@ -375,6 +389,13 @@ public class VehicleRoutingAlgorithms {
return createAlgo(vrp,algorithmConfig.getXMLConfiguration()); 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){ public static VehicleRoutingAlgorithm readAndCreateAlgorithm(final VehicleRoutingProblem vrp, final String configFileName){
AlgorithmConfig algorithmConfig = new AlgorithmConfig(); AlgorithmConfig algorithmConfig = new AlgorithmConfig();
AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig); AlgorithmConfigXmlReader xmlReader = new AlgorithmConfigXmlReader(algorithmConfig);
@ -572,6 +593,7 @@ public class VehicleRoutingAlgorithms {
StrategyModuleKey strategyModuleKey = new StrategyModuleKey(modKey); StrategyModuleKey strategyModuleKey = new StrategyModuleKey(modKey);
SearchStrategyModule definedModule = definedClasses.get(strategyModuleKey); SearchStrategyModule definedModule = definedClasses.get(strategyModuleKey);
if(definedModule != null) return definedModule; if(definedModule != null) return definedModule;
if(moduleName.equals("ruin_and_recreate")){ if(moduleName.equals("ruin_and_recreate")){
String ruin_name = moduleConfig.getString("ruin[@name]"); String ruin_name = moduleConfig.getString("ruin[@name]");
if(ruin_name == null) throw new IllegalStateException("module.ruin[@name] is missing."); 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); ruin = getRandomRuin(vrp, activityStates, definedClasses, ruinKey, shareToRuin);
} }
else if(ruin_name.equals("radialRuin")){ 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."); 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; return module;
} }
if(moduleName.equals("bestInsertion") || moduleName.equals("regretInsertion")){
List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>(); // if(moduleName.equals("bestInsertion") || moduleName.equals("regretInsertion")){
AbstractInsertionStrategy insertion = getInsertionStrategy(moduleConfig, vrp, vehicleFleetManager, activityStates, // List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
definedClasses, modKey, prioListeners); // AbstractInsertionStrategy insertion = getInsertionStrategy(moduleConfig, vrp, vehicleFleetManager, activityStates,
SearchStrategyModule module = getModule(moduleName, insertion, vrp); // definedClasses, modKey, prioListeners);
definedClasses.put(strategyModuleKey, module); // SearchStrategyModule module = getModule(moduleName, insertion, vrp);
algorithmListeners.addAll(prioListeners); // definedClasses.put(strategyModuleKey, module);
return module; // algorithmListeners.addAll(prioListeners);
} // return module;
// }
// if(moduleName.equals("regretInsertion")){ // if(moduleName.equals("regretInsertion")){
// List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>(); // List<PrioritizedVRAListener> prioListeners = new ArrayList<PrioritizedVRAListener>();
// AbstractInsertionKey insertionKey = new AbstractInsertionKey(modKey); // AbstractInsertionKey insertionKey = new AbstractInsertionKey(modKey);
@ -664,20 +697,30 @@ public class VehicleRoutingAlgorithms {
// algorithmListeners.addAll(prioListeners); // algorithmListeners.addAll(prioListeners);
// return module; // return module;
// } // }
if(moduleName.equals("randomRuin")){ // if(moduleName.equals("randomRuin")){
double shareToRuin = moduleConfig.getDouble("share"); // double shareToRuin = moduleConfig.getDouble("share");
RuinStrategy ruin = getRandomRuin(vrp, activityStates,definedClasses, modKey, shareToRuin); // RuinStrategy ruin = getRandomRuin(vrp, activityStates,definedClasses, modKey, shareToRuin);
SearchStrategyModule module = getModule(moduleName, ruin); // SearchStrategyModule module = getModule(moduleName, ruin);
definedClasses.put(strategyModuleKey, module); // definedClasses.put(strategyModuleKey, module);
return module; // return module;
} // }
if(moduleName.equals("radialRuin")){ // if(moduleName.equals("radialRuin")){
double shareToRuin = moduleConfig.getDouble("share"); // double shareToRuin = moduleConfig.getDouble("share");
RuinStrategy ruin = getRadialRuin(vrp, activityStates,definedClasses, modKey, shareToRuin); // String ruin_distance = moduleConfig.getString("distance");
SearchStrategyModule module = getModule(moduleName, ruin); // JobDistance jobDistance;
definedClasses.put(strategyModuleKey, module); // if(ruin_distance == null) jobDistance = new JobDistanceAvgCosts(vrp.getTransportCosts());
return module; // 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")){ if(moduleName.equals("gendreauPostOpt")){
int iterations = moduleConfig.getInt("iterations"); int iterations = moduleConfig.getInt("iterations");
double share = moduleConfig.getDouble("share"); double share = moduleConfig.getDouble("share");
@ -734,13 +777,11 @@ public class VehicleRoutingAlgorithms {
return bestInsertion; return bestInsertion;
} }
private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp, private static RuinStrategy getRadialRuin(VehicleRoutingProblem vrp, RouteStates activityStates, TypedMap definedClasses, ModKey modKey, double shareToRuin, JobDistance jobDistance) {
RouteStates activityStates, TypedMap definedClasses,
ModKey modKey, double shareToRuin) {
RuinStrategyKey stratKey = new RuinStrategyKey(modKey); RuinStrategyKey stratKey = new RuinStrategyKey(modKey);
RuinStrategy ruin = definedClasses.get(stratKey); RuinStrategy ruin = definedClasses.get(stratKey);
if(ruin == null){ 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); definedClasses.put(stratKey, ruin);
} }
return ruin; return ruin;
@ -778,12 +819,6 @@ public class VehicleRoutingAlgorithms {
double penalty = 0.0; double penalty = 0.0;
if(jobsInSolution != vrp.getJobs().values().size()){ if(jobsInSolution != vrp.getJobs().values().size()){
throw new IllegalStateException("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("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()); double totalCost = RouteUtils.getTotalCost(vrpSolution.getRoutes());
vrpSolution.setCost(totalCost + penalty); vrpSolution.setCost(totalCost + penalty);
@ -841,37 +876,37 @@ public class VehicleRoutingAlgorithms {
} }
private static SearchStrategyModule getModule(final String moduleName, final RuinStrategy ruin) { // private static SearchStrategyModule getModule(final String moduleName, final RuinStrategy ruin) {
//
//
return new SearchStrategyModule() { // return new SearchStrategyModule() {
//
private Logger logger = Logger.getLogger(SearchStrategyModule.class); // private Logger logger = Logger.getLogger(SearchStrategyModule.class);
//
@Override // @Override
public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) { // public VehicleRoutingProblemSolution runAndGetSolution(VehicleRoutingProblemSolution vrpSolution) {
ruin.ruin(vrpSolution.getRoutes()); // ruin.ruin(vrpSolution.getRoutes());
return vrpSolution; // return vrpSolution;
} // }
//
@Override // @Override
public String toString() { // public String toString() {
return "[name="+ruin+"]"; // return "[name="+ruin+"]";
} // }
//
@Override // @Override
public String getName() { // public String getName() {
return moduleName; // return moduleName;
} // }
//
@Override // @Override
public void addModuleListener(SearchStrategyModuleListener moduleListener) { // public void addModuleListener(SearchStrategyModuleListener moduleListener) {
// TODO Auto-generated method stub // // TODO Auto-generated method stub
//
} // }
//
}; // };
} // }

View file

@ -242,6 +242,12 @@ public class VehicleRoutingProblem {
return this; return this;
} }
/**
* Sets the neighborhood.
*
* @param neighborhood
* @return
*/
public Builder setNeighborhood(Neighborhood neighborhood){ public Builder setNeighborhood(Neighborhood neighborhood){
this.neighborhood = neighborhood; this.neighborhood = neighborhood;
return this; return this;
@ -261,6 +267,13 @@ public class VehicleRoutingProblem {
return this; return this;
} }
/**
* Builds the {@link VehicleRoutingProblem}.
*
* <p>If {@link VehicleRoutingTransportCosts} are not set, {@link CrowFlyCosts} is used.
*
* @return {@link VehicleRoutingProblem}
*/
public VehicleRoutingProblem build() { public VehicleRoutingProblem build() {
log.info("build problem ..."); log.info("build problem ...");
if(transportCosts == null){ if(transportCosts == null){
@ -275,6 +288,12 @@ public class VehicleRoutingProblem {
return this; return this;
} }
/**
* Adds a collection of jobs.
*
* @param jobs
* @return
*/
public Builder addAllJobs(Collection<Job> jobs) { public Builder addAllJobs(Collection<Job> jobs) {
for(Job j : jobs){ for(Job j : jobs){
addJob(j); addJob(j);
@ -282,6 +301,12 @@ public class VehicleRoutingProblem {
return this; return this;
} }
/**
* Adds a collection of vehicles.
*
* @param vehicles
* @return
*/
public Builder addAllVehicles(Collection<Vehicle> vehicles) { public Builder addAllVehicles(Collection<Vehicle> vehicles) {
for(Vehicle v : vehicles){ for(Vehicle v : vehicles){
addVehicle(v); addVehicle(v);
@ -289,11 +314,20 @@ public class VehicleRoutingProblem {
return this; return this;
} }
/**
* Gets an unmodifiable collection of already added vehicles.
*
* @return collection of vehicles
*/
public Collection<Vehicle> getAddedVehicles(){ public Collection<Vehicle> getAddedVehicles(){
return Collections.unmodifiableCollection(vehicles); return Collections.unmodifiableCollection(vehicles);
} }
/**
* Gets an unmodifiable collection of already added services.
*
* @return collection of services
*/
public Collection<Service> getAddedServices(){ public Collection<Service> getAddedServices(){
return Collections.unmodifiableCollection(services); return Collections.unmodifiableCollection(services);
} }

View file

@ -135,7 +135,7 @@
<xs:complexType name="ruinType"> <xs:complexType name="ruinType">
<xs:sequence> <xs:sequence>
<xs:element name="share"> <xs:element name="share" minOccurs="1" maxOccurs="1">
<xs:simpleType> <xs:simpleType>
<xs:restriction base="xs:double"> <xs:restriction base="xs:double">
<xs:minInclusive value="0.0"/> <xs:minInclusive value="0.0"/>
@ -143,6 +143,13 @@
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
</xs:element> </xs:element>
<xs:element name="distance" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="euclidean"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence> </xs:sequence>
<xs:attribute name="name" use="required"> <xs:attribute name="name" use="required">
<xs:simpleType> <xs:simpleType>

View file

@ -230,43 +230,7 @@ public class TestAlgorithmReader {
for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){ for(SearchStrategy strat : algo.getSearchStrategyManager().getStrategies()){
nOfModules += strat.getSearchStrategyModules().size(); nOfModules += strat.getSearchStrategyModules().size();
} }
assertEquals(6, nOfModules); assertEquals(3, nOfModules);
}
@Test
public void whenCreatingAlgorithm_nOfUniqueInstancesOfInsertionModulesIsCorrect(){
VehicleRoutingAlgorithm algo = VehicleRoutingAlgorithms.readAndCreateAlgorithm(vrp, config);
int nOfBestInsertions = 0;
Set<SearchStrategyModule> uniqueStrategies = new HashSet<SearchStrategyModule>();
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<SearchStrategyModule> uniqueStrategies = new HashSet<SearchStrategyModule>();
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());
} }
@Test @Test

View file

@ -34,10 +34,11 @@
<selector name="selectBest"/> <selector name="selectBest"/>
<acceptor name="acceptNewRemoveWorst"/> <acceptor name="acceptNewRemoveWorst"/>
<modules> <modules>
<module name="randomRuin"> <module name="ruin_and_recreate">
<ruin name="randomRuin">
<share>0.5</share> <share>0.5</share>
</module> </ruin>
<module name="bestInsertion"> <insertion name="bestInsertion"/>
</module> </module>
</modules> </modules>
<probability>0.4</probability> <probability>0.4</probability>
@ -47,10 +48,12 @@
<selector name="selectBest"/> <selector name="selectBest"/>
<acceptor name="acceptNewRemoveWorst"/> <acceptor name="acceptNewRemoveWorst"/>
<modules> <modules>
<module name="randomRuin"> <module name="ruin_and_recreate">
<ruin name="randomRuin">
<share>0.1</share> <share>0.1</share>
</ruin>
<insertion name="bestInsertion"/>
</module> </module>
<module name="bestInsertion"></module>
</modules> </modules>
<probability>0.4</probability> <probability>0.4</probability>
</searchStrategy> </searchStrategy>
@ -59,11 +62,12 @@
<selector name="selectBest"/> <selector name="selectBest"/>
<acceptor name="acceptNewRemoveWorst"/> <acceptor name="acceptNewRemoveWorst"/>
<modules> <modules>
<module name="radialRuin"> <module name="ruin_and_recreate">
<ruin name="radialRuin">
<share>0.3</share> <share>0.3</share>
<distanceMeasure>euclid</distanceMeasure> </ruin>
<insertion name="bestInsertion" id="1"/>
</module> </module>
<module name="bestInsertion" id="1"></module>
</modules> </modules>
<probability>0.2</probability> <probability>0.2</probability>
</searchStrategy> </searchStrategy>