/* Copyright 2009-2016 David Hadka
*
* This file is part of the MOEA Framework.
*
* The MOEA Framework is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* The MOEA Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>.
*/
package org.moeaframework.algorithm;
import java.util.List;
import java.util.Properties;
import org.apache.commons.math3.util.CombinatoricsUtils;
import org.moeaframework.algorithm.pso.OMOPSO;
import org.moeaframework.algorithm.pso.SMPSO;
import org.moeaframework.algorithm.single.DifferentialEvolution;
import org.moeaframework.algorithm.single.EvolutionStrategy;
import org.moeaframework.algorithm.single.GeneticAlgorithm;
import org.moeaframework.algorithm.single.RepeatedSingleObjective;
import org.moeaframework.algorithm.single.AggregateObjectiveComparator;
import org.moeaframework.algorithm.single.MinMaxDominanceComparator;
import org.moeaframework.algorithm.single.LinearDominanceComparator;
import org.moeaframework.algorithm.single.SelfAdaptiveNormalVariation;
import org.moeaframework.analysis.sensitivity.EpsilonHelper;
import org.moeaframework.core.Algorithm;
import org.moeaframework.core.EpsilonBoxDominanceArchive;
import org.moeaframework.core.FitnessEvaluator;
import org.moeaframework.core.FrameworkException;
import org.moeaframework.core.Initialization;
import org.moeaframework.core.NondominatedPopulation;
import org.moeaframework.core.NondominatedSortingPopulation;
import org.moeaframework.core.PRNG;
import org.moeaframework.core.Population;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Selection;
import org.moeaframework.core.Solution;
import org.moeaframework.core.Variable;
import org.moeaframework.core.Variation;
import org.moeaframework.core.comparator.AggregateConstraintComparator;
import org.moeaframework.core.comparator.ChainedComparator;
import org.moeaframework.core.comparator.CrowdingComparator;
import org.moeaframework.core.comparator.DominanceComparator;
import org.moeaframework.core.comparator.ParetoDominanceComparator;
import org.moeaframework.core.fitness.AdditiveEpsilonIndicatorFitnessEvaluator;
import org.moeaframework.core.fitness.HypervolumeContributionFitnessEvaluator;
import org.moeaframework.core.fitness.HypervolumeFitnessEvaluator;
import org.moeaframework.core.fitness.IndicatorFitnessEvaluator;
import org.moeaframework.core.operator.RandomInitialization;
import org.moeaframework.core.operator.TournamentSelection;
import org.moeaframework.core.operator.UniformSelection;
import org.moeaframework.core.operator.real.DifferentialEvolutionSelection;
import org.moeaframework.core.operator.real.DifferentialEvolutionVariation;
import org.moeaframework.core.operator.real.UM;
import org.moeaframework.core.spi.AlgorithmProvider;
import org.moeaframework.core.spi.OperatorFactory;
import org.moeaframework.core.spi.ProviderLookupException;
import org.moeaframework.core.spi.ProviderNotFoundException;
import org.moeaframework.core.variable.RealVariable;
import org.moeaframework.util.TypedProperties;
import org.moeaframework.util.Vector;
import org.moeaframework.util.weights.RandomGenerator;
/**
* A provider of standard algorithms. The following table contains all
* available algorithms and the customizable properties. These properties are
* tailored for real-valued operators. If using a different representation,
* see {@link OperatorFactory} for the appropriate parameters. See the user
* manual for a more detailed description of the algorithms and parameters.
* <p>
* <strong>For a more detailed description of each algorithm, their properties,
* and their default values, please refer to Appendix A in the Beginner's Guide
* to the MOEA Framework.</strong>
* <p>
* <table width="100%" border="1" cellpadding="3" cellspacing="0">
* <tr class="TableHeadingColor">
* <th width="10%" align="left">Name</th>
* <th width="10%" align="left">Type</th>
* <th width="80%" align="left">Properties</th>
* </tr>
* <tr>
* <td>CMA-ES</td>
* <td>Real</td>
* <td>{@code lambda, cc, cs, damps, ccov, ccovsep, sigma,
* diagonalIterations, indicator, initialSearchPoint}</td>
* </tr>
* <tr>
* <td>DBEA</td>
* <td>Any</td>
* <td>{@code divisions, sbx.rate, sbx.distributionIndex,
* pm.rate, pm.distributionIndex} (for the two-layer approach, replace
* {@code divisions} by {@code divisionsOuter} and
* {@code divisionsInner})</td>
* </tr>
* <tr>
* <td>eMOEA</td>
* <td>Any</td>
* <td>{@code populationSize, epsilon, sbx.rate,
* sbx.distributionIndex, pm.rate, pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>eNSGAII</td>
* <td>Any</td>
* <td>{@code populationSize, epsilon, sbx.rate,
* sbx.distributionIndex, pm.rate, pm.distributionIndex,
* injectionRate, windowSize, maxWindowSize, minimumPopulationSize,
* maximumPopulationSize}</td>
* </tr>
* <tr>
* <td>GDE3</td>
* <td>Real</td>
* <td>{@code populationSize, de.crossoverRate, de.stepSize}</td>
* </tr>
* <tr>
* <td>IBEA</td>
* <td>Any</td>
* <td>{@code populationSize, sbx.rate, sbx.distributionIndex, pm.rate,
* pm.distributionIndex, indicator}</td>
* </tr>
* <tr>
* <td>MOEAD</td>
* <td>Real</td>
* <td>{@code populationSize, de.crossoverRate, de.stepSize, pm.rate,
* pm.distributionIndex, neighborhoodSize, delta, eta,
* updateUtility}</td>
* </tr>
* <tr>
* <td>MSOPS</td>
* <td>Real</td>
* <td>{@code populationSize, numberOfWeights, de.crossoverRate,
* de.stepSize}</td>
* </tr>
* <tr>
* <td>NSGAII</td>
* <td>Any</td>
* <td>{@code populationSize, sbx.rate, sbx.distributionIndex,
* pm.rate, pm.distributionIndex, withReplacement}</td>
* </tr>
* <tr>
* <td>NSGAIII</td>
* <td>Any</td>
* <td>{@code populationSize, divisions, sbx.rate, sbx.distributionIndex,
* pm.rate, pm.distributionIndex} (for the two-layer approach, replace
* {@code divisions} by {@code divisionsOuter} and
* {@code divisionsInner})</td>
* </tr>
* <tr>
* <td>OMOPSO</td>
* <td>Real</td>
* <td>{@code populationSize, archiveSize, maxEvaluations,
* mutationProbability, perturbationIndex, epsilon}</td>
* </tr>
* <tr>
* <td>PAES</td>
* <td>Any</td>
* <td>{@code archiveSize, bisections, pm.rate, pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>PESA2</td>
* <td>Any</td>
* <td>{@code populationSize, archiveSize, bisections, sbx.rate,
* sbx.distributionIndex, pm.rate, pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>Random</td>
* <td>Any</td>
* <td>{@code populationSize, epsilon}</td>
* </tr>
* <tr>
* <td>RVEA</td>
* <td>Any</td>
* <td>{@code populationSize, divisions, alpha, maxEvaluations,
* adaptFrequency, sbx.rate, sbx.distributionIndex, pm.rate,
* pm.distributionIndex} (for the two-layer approach, replace
* {@code divisions} by {@code divisionsOuter} and
* {@code divisionsInner})</td>
* </tr>
* <tr>
* <td>SMPSO</td>
* <td>Real</td>
* <td>{@code populationSize, archiveSize, pm.rate,
* pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>SMS-EMOA</td>
* <td>Any</td>
* <td>{@code populationSize, offset, sbx.rate, sbx.distributionIndex,
* pm.rate, pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>SPEA2</td>
* <td>Any</td>
* <td>{@code populationSize, offspringSize, k, sbx.rate,
* sbx.distributionIndex, pm.rate, pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>VEGA</td>
* <td>Any</td>
* <td>{@code populationSize, sbx.rate, sbx.distributionIndex, pm.rate,
* pm.distributionIndex}</td>
* </tr>
* </table>
* <p>
* Several single-objective algorithms are also supported. These
* single-objective algorithms support an optional weighting method, which can
* be either {@code "linear"} or {@code "min-max"}.
* <p>
* <table width="100%" border="1" cellpadding="3" cellspacing="0">
* <tr class="TableHeadingColor">
* <th width="10%" align="left">Name</th>
* <th width="10%" align="left">Type</th>
* <th width="80%" align="left">Properties</th>
* </tr>
* <tr>
* <td>GA</td>
* <td>Any</td>
* <td>{@code populationSize, method, weights, sbx.rate,
* sbx.distributionIndex, pm.rate, pm.distributionIndex}</td>
* </tr>
* <tr>
* <td>ES</td>
* <td>Real</td>
* <td>{@code populationSize, method, weights}</td>
* </tr>
* <tr>
* <td>DE</td>
* <td>Real</td>
* <td>{@code populationSize, method, weights, de.crossoverRate,
* de.stepSize}</td>
* </tr>
* </table>
* <p>
* Lastly, the Repeated Single Objective ({@code RSO}) algorithm is a special
* case that runs a single-objective algorithm multiple times while aggregating
* the result. For example, you can create the algorithm {@code RSO(GA)} to
* run the single-objective genetic algorithm ({@code GA}) multiple times. The
* {@code instances} property controls the number of repeated runs.
*/
public class StandardAlgorithms extends AlgorithmProvider {
/**
* Constructs the standard algorithm provider.
*/
public StandardAlgorithms() {
super();
}
@Override
public Algorithm getAlgorithm(String name, Properties properties,
Problem problem) {
TypedProperties typedProperties = new TypedProperties(properties);
try {
if (name.equalsIgnoreCase("MOEAD") ||
name.equalsIgnoreCase("MOEA/D")) {
return newMOEAD(typedProperties, problem);
} else if (name.equalsIgnoreCase("GDE3")) {
return newGDE3(typedProperties, problem);
} else if (name.equalsIgnoreCase("NSGAII") ||
name.equalsIgnoreCase("NSGA-II") ||
name.equalsIgnoreCase("NSGA2")) {
return newNSGAII(typedProperties, problem);
} else if (name.equalsIgnoreCase("NSGAIII") ||
name.equalsIgnoreCase("NSGA-III") ||
name.equalsIgnoreCase("NSGA3")) {
return newNSGAIII(typedProperties, problem);
} else if (name.equalsIgnoreCase("eNSGAII") ||
name.equalsIgnoreCase("e-NSGA-II") ||
name.equalsIgnoreCase("eNSGA2")) {
return neweNSGAII(typedProperties, problem);
} else if (name.equalsIgnoreCase("eMOEA")) {
return neweMOEA(typedProperties, problem);
} else if (name.equalsIgnoreCase("CMA-ES") ||
name.equalsIgnoreCase("CMAES") ||
name.equalsIgnoreCase("MO-CMA-ES")) {
return newCMAES(typedProperties, problem);
} else if (name.equalsIgnoreCase("SPEA2")) {
return newSPEA2(typedProperties, problem);
} else if (name.equalsIgnoreCase("PAES")) {
return newPAES(typedProperties, problem);
} else if (name.equalsIgnoreCase("PESA2")) {
return newPESA2(typedProperties, problem);
} else if (name.equalsIgnoreCase("OMOPSO")) {
return newOMOPSO(typedProperties, problem);
} else if (name.equalsIgnoreCase("SMPSO")) {
return newSMPSO(typedProperties, problem);
} else if (name.equalsIgnoreCase("IBEA")) {
return newIBEA(typedProperties, problem);
} else if (name.equalsIgnoreCase("SMSEMOA") ||
name.equalsIgnoreCase("SMS-EMOA")) {
return newSMSEMOA(typedProperties, problem);
} else if (name.equalsIgnoreCase("VEGA")) {
return newVEGA(typedProperties, problem);
} else if (name.equalsIgnoreCase("DBEA") ||
name.equalsIgnoreCase("I-DBEA")) {
return newDBEA(typedProperties, problem);
} else if (name.equalsIgnoreCase("RVEA")) {
return newRVEA(typedProperties, problem);
} else if (name.equalsIgnoreCase("MSOPS")) {
return newMSOPS(typedProperties, problem);
} else if (name.equalsIgnoreCase("Random")) {
return newRandomSearch(typedProperties, problem);
} else if (name.equalsIgnoreCase("DifferentialEvolution") ||
name.equalsIgnoreCase("DE") ||
name.equalsIgnoreCase("DE/rand/1/bin")) {
return newDifferentialEvolution(typedProperties, problem);
} else if (name.equalsIgnoreCase("GeneticAlgorithm") ||
name.equalsIgnoreCase("GA")) {
return newGeneticAlgorithm(typedProperties, problem);
} else if (name.equalsIgnoreCase("EvolutionStrategy") ||
name.equalsIgnoreCase("ES")) {
return newEvolutionaryStrategy(typedProperties, problem);
} else if (name.equalsIgnoreCase("RSO")) {
return newRSO(typedProperties, problem);
} else if (name.toUpperCase().startsWith("RSO(") && name.endsWith(")")) {
typedProperties.setString("algorithm", name.substring(4, name.length()-1));
return newRSO(typedProperties, problem);
} else {
return null;
}
} catch (FrameworkException e) {
throw new ProviderNotFoundException(name, e);
}
}
/**
* Returns {@code true} if all decision variables are assignment-compatible
* with the specified type; {@code false} otherwise.
*
* @param type the type of decision variable
* @param problem the problem
* @return {@code true} if all decision variables are assignment-compatible
* with the specified type; {@code false} otherwise
*/
private boolean checkType(Class<? extends Variable> type, Problem problem) {
Solution solution = problem.newSolution();
for (int i=0; i<solution.getNumberOfVariables(); i++) {
if (!type.isInstance(solution.getVariable(i))) {
return false;
}
}
return true;
}
/**
* Returns a new {@link eMOEA} instance.
*
* @param properties the properties for customizing the new {@code eMOEA}
* instance
* @param problem the problem
* @return a new {@code eMOEA} instance
*/
private Algorithm neweMOEA(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
Initialization initialization = new RandomInitialization(problem,
populationSize);
Population population = new Population();
DominanceComparator comparator = new ParetoDominanceComparator();
EpsilonBoxDominanceArchive archive = new EpsilonBoxDominanceArchive(
properties.getDoubleArray("epsilon",
new double[] { EpsilonHelper.getEpsilon(problem) }));
final TournamentSelection selection = new TournamentSelection(
2, comparator);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
EpsilonMOEA emoea = new EpsilonMOEA(problem, population, archive,
selection, variation, initialization, comparator);
return emoea;
}
/**
* Returns a new {@link NSGAII} instance.
*
* @param properties the properties for customizing the new {@code NSGAII}
* instance
* @param problem the problem
* @return a new {@code NSGAII} instance
*/
private Algorithm newNSGAII(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
Initialization initialization = new RandomInitialization(problem,
populationSize);
NondominatedSortingPopulation population =
new NondominatedSortingPopulation();
TournamentSelection selection = null;
if (properties.getBoolean("withReplacement", true)) {
selection = new TournamentSelection(2, new ChainedComparator(
new ParetoDominanceComparator(),
new CrowdingComparator()));
}
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
return new NSGAII(problem, population, null, selection, variation,
initialization);
}
/**
* Returns a new {@link NSGAIII} instance.
*
* @param properties the properties for customizing the new {@code NSGAIII}
* instance
* @param problem the problem
* @return a new {@code NSGAIII} instance
*/
private Algorithm newNSGAIII(TypedProperties properties, Problem problem) {
int divisionsOuter = 4;
int divisionsInner = 0;
if (properties.contains("divisionsOuter") && properties.contains("divisionsInner")) {
divisionsOuter = (int)properties.getDouble("divisionsOuter", 4);
divisionsInner = (int)properties.getDouble("divisionsInner", 0);
} else if (properties.contains("divisions")){
divisionsOuter = (int)properties.getDouble("divisions", 4);
} else if (problem.getNumberOfObjectives() == 1) {
divisionsOuter = 100;
} else if (problem.getNumberOfObjectives() == 2) {
divisionsOuter = 99;
} else if (problem.getNumberOfObjectives() == 3) {
divisionsOuter = 12;
} else if (problem.getNumberOfObjectives() == 4) {
divisionsOuter = 8;
} else if (problem.getNumberOfObjectives() == 5) {
divisionsOuter = 6;
} else if (problem.getNumberOfObjectives() == 6) {
divisionsOuter = 4;
divisionsInner = 1;
} else if (problem.getNumberOfObjectives() == 7) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 8) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 9) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 10) {
divisionsOuter = 3;
divisionsInner = 2;
} else {
divisionsOuter = 2;
divisionsInner = 1;
}
int populationSize;
if (properties.contains("populationSize")) {
populationSize = (int)properties.getDouble("populationSize", 100);
} else {
// compute number of reference points
populationSize = (int)(CombinatoricsUtils.binomialCoefficient(problem.getNumberOfObjectives() + divisionsOuter - 1, divisionsOuter) +
(divisionsInner == 0 ? 0 : CombinatoricsUtils.binomialCoefficient(problem.getNumberOfObjectives() + divisionsInner - 1, divisionsInner)));
// round up to a multiple of 4
populationSize = (int)Math.ceil(populationSize / 4d) * 4;
}
Initialization initialization = new RandomInitialization(problem,
populationSize);
ReferencePointNondominatedSortingPopulation population = new ReferencePointNondominatedSortingPopulation(
problem.getNumberOfObjectives(), divisionsOuter, divisionsInner);
Selection selection = null;
if (problem.getNumberOfConstraints() == 0) {
selection = new Selection() {
@Override
public Solution[] select(int arity, Population population) {
Solution[] result = new Solution[arity];
for (int i = 0; i < arity; i++) {
result[i] = population.get(PRNG.nextInt(population.size()));
}
return result;
}
};
} else {
selection = new TournamentSelection(2, new ChainedComparator(
new AggregateConstraintComparator(),
new DominanceComparator() {
@Override
public int compare(Solution solution1, Solution solution2) {
return PRNG.nextBoolean() ? -1 : 1;
}
}));
}
// disable swapping variables in SBX operator to remain consistent with
// Deb's implementation (thanks to Haitham Seada for identifying this
// discrepancy)
if (!properties.contains("sbx.swap")) {
properties.setBoolean("sbx.swap", false);
}
if (!properties.contains("sbx.distributionIndex")) {
properties.setDouble("sbx.distributionIndex", 30.0);
}
if (!properties.contains("pm.distributionIndex")) {
properties.setDouble("pm.distributionIndex", 20.0);
}
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
return new NSGAII(problem, population, null, selection, variation,
initialization);
}
/**
* Returns a new {@link MOEAD} instance. Only real encodings are supported.
*
* @param properties the properties for customizing the new {@code MOEAD}
* instance
* @param problem the problem
* @return a new {@code MOEAD} instance
* @throws FrameworkException if the decision variables are not real valued
*/
private Algorithm newMOEAD(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
//enforce population size lower bound
if (populationSize < problem.getNumberOfObjectives()) {
System.err.println("increasing MOEA/D population size");
populationSize = problem.getNumberOfObjectives();
}
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(
"de+pm", properties, problem);
int neighborhoodSize = 20;
int eta = 2;
if (properties.contains("neighborhoodSize")) {
neighborhoodSize = Math.max(2,
(int)(properties.getDouble("neighborhoodSize", 0.1)
* populationSize));
}
if (neighborhoodSize > populationSize) {
neighborhoodSize = populationSize;
}
if (properties.contains("eta")) {
eta = Math.max(2, (int)(properties.getDouble("eta", 0.01)
* populationSize));
}
MOEAD algorithm = new MOEAD(
problem,
neighborhoodSize,
initialization,
variation,
properties.getDouble("delta", 0.9),
eta,
(int)properties.getDouble("updateUtility", -1));
return algorithm;
}
/**
* Returns a new {@link GDE3} instance. Only real encodings are supported.
*
* @param properties the properties for customizing the new {@code GDE3}
* instance
* @param problem the problem
* @return a new {@code GDE3} instance
* @throws FrameworkException if the decision variables are not real valued
*/
private Algorithm newGDE3(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
DominanceComparator comparator = new ParetoDominanceComparator();
NondominatedSortingPopulation population =
new NondominatedSortingPopulation(comparator);
Initialization initialization = new RandomInitialization(problem,
populationSize);
DifferentialEvolutionSelection selection =
new DifferentialEvolutionSelection();
DifferentialEvolutionVariation variation = (DifferentialEvolutionVariation)OperatorFactory
.getInstance().getVariation("de", properties, problem);
return new GDE3(problem, population, comparator, selection, variation,
initialization);
}
/**
* Returns a new {@link eNSGAII} instance.
*
* @param properties the properties for customizing the new {@code eNSGAII}
* instance
* @param problem the problem
* @return a new {@code eNSGAII} instance
*/
private Algorithm neweNSGAII(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
Initialization initialization = new RandomInitialization(problem,
populationSize);
NondominatedSortingPopulation population =
new NondominatedSortingPopulation(
new ParetoDominanceComparator());
EpsilonBoxDominanceArchive archive = new EpsilonBoxDominanceArchive(
properties.getDoubleArray("epsilon",
new double[] { EpsilonHelper.getEpsilon(problem) }));
TournamentSelection selection = new TournamentSelection(2,
new ChainedComparator(
new ParetoDominanceComparator(),
new CrowdingComparator()));
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
NSGAII nsgaii = new NSGAII(problem, population, archive, selection,
variation, initialization);
AdaptiveTimeContinuation algorithm = new AdaptiveTimeContinuation(
nsgaii,
properties.getInt("windowSize", 100),
Math.max(properties.getInt("windowSize", 100),
properties.getInt("maxWindowSize", 100)),
1.0 / properties.getDouble("injectionRate", 0.25),
properties.getInt("minimumPopulationSize", 100),
properties.getInt("maximumPopulationSize", 10000),
new UniformSelection(),
new UM(1.0));
return algorithm;
}
/**
* Returns a new {@link CMAES} instance.
*
* @param properties the properties for customizing the new {@code CMAES}
* instance
* @param problem the problem
* @return a new {@code CMAES} instance
*/
private Algorithm newCMAES(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int lambda = (int)properties.getDouble("lambda", 100);
double cc = properties.getDouble("cc", -1.0);
double cs = properties.getDouble("cs", -1.0);
double damps = properties.getDouble("damps", -1.0);
double ccov = properties.getDouble("ccov", -1.0);
double ccovsep = properties.getDouble("ccovsep", -1.0);
double sigma = properties.getDouble("sigma", -1.0);
int diagonalIterations = (int)properties.getDouble("diagonalIterations", 0);
String indicator = properties.getString("indicator", "crowding");
double[] initialSearchPoint = properties.getDoubleArray("initialSearchPoint", null);
NondominatedPopulation archive = null;
FitnessEvaluator fitnessEvaluator = null;
if (problem.getNumberOfObjectives() == 1) {
archive = new NondominatedPopulation();
} else {
archive = new EpsilonBoxDominanceArchive(
properties.getDoubleArray("epsilon",
new double[] { EpsilonHelper.getEpsilon(problem) }));
}
if ("hypervolume".equals(indicator)) {
fitnessEvaluator = new HypervolumeFitnessEvaluator(problem);
} else if ("epsilon".equals(indicator)) {
fitnessEvaluator = new AdditiveEpsilonIndicatorFitnessEvaluator(problem);
}
CMAES cmaes = new CMAES(problem, lambda, fitnessEvaluator, archive,
initialSearchPoint, false, cc, cs, damps, ccov, ccovsep, sigma,
diagonalIterations);
return cmaes;
}
/**
* Returns a new {@link SPEA2} instance.
*
* @param properties the properties for customizing the new {@code SPEA2}
* instance
* @param problem the problem
* @return a new {@code SPEA2} instance
*/
private Algorithm newSPEA2(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
int offspringSize = (int)properties.getDouble("offspringSize", 100);
int k = (int)properties.getDouble("k", 1);
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
return new SPEA2(problem, initialization, variation, offspringSize, k);
}
/**
* Returns a new {@link PAES} instance.
*
* @param properties the properties for customizing the new {@code PAES}
* instance
* @param problem the problem
* @return a new {@code PAES} instance
*/
private Algorithm newPAES(TypedProperties properties, Problem problem) {
int archiveSize = (int)properties.getDouble("archiveSize", 100);
int bisections = (int)properties.getDouble("bisections", 8);
Variation variation = OperatorFactory.getInstance().getVariation(
OperatorFactory.getInstance().getDefaultMutation(problem),
properties,
problem);
return new PAES(problem, variation, bisections, archiveSize);
}
/**
* Returns a new {@link PESA2} instance.
*
* @param properties the properties for customizing the new {@code PESA2}
* instance
* @param problem the problem
* @return a new {@code PESA2} instance
*/
private Algorithm newPESA2(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
int archiveSize = (int)properties.getDouble("archiveSize", 100);
int bisections = (int)properties.getDouble("bisections", 8);
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
return new PESA2(problem, variation, initialization, bisections, archiveSize);
}
/**
* Returns a new {@link OMOPSO} instance.
*
* @param properties the properties for customizing the new {@code OMOPSO}
* instance
* @param problem the problem
* @return a new {@code OMOPSO} instance
*/
private Algorithm newOMOPSO(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
int archiveSize = (int)properties.getDouble("archiveSize", 100);
int maxIterations = (int)properties.getDouble("maxEvaluations", 25000) /
populationSize;
double mutationProbability = properties.getDouble("mutationProbability",
1.0 / problem.getNumberOfVariables());
double perturbationIndex = properties.getDouble("perturbationIndex",
0.5);
double[] epsilon = properties.getDoubleArray("epsilon",
new double[] { EpsilonHelper.getEpsilon(problem) });
return new OMOPSO(problem, populationSize, archiveSize,
epsilon, mutationProbability, perturbationIndex, maxIterations);
}
/**
* Returns a new {@link SMPSO} instance.
*
* @param properties the properties for customizing the new {@code SMPSO}
* instance
* @param problem the problem
* @return a new {@code SMPSO} instance
*/
private Algorithm newSMPSO(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
int archiveSize = (int)properties.getDouble("archiveSize", 100);
double mutationProbability = properties.getDouble("pm.rate",
1.0 / problem.getNumberOfVariables());
double distributionIndex = properties.getDouble("pm.distributionIndex",
20.0);
return new SMPSO(problem, populationSize, archiveSize,
mutationProbability, distributionIndex);
}
/**
* Returns a new {@link IBEA} instance.
*
* @param properties the properties for customizing the new {@code IBEA}
* instance
* @param problem the problem
* @return a new {@code IBEA} instance
*/
private Algorithm newIBEA(TypedProperties properties, Problem problem) {
if (problem.getNumberOfConstraints() > 0) {
throw new ProviderNotFoundException("IBEA",
new ProviderLookupException("constraints not supported"));
}
int populationSize = (int)properties.getDouble("populationSize", 100);
String indicator = properties.getString("indicator", "hypervolume");
IndicatorFitnessEvaluator fitnessEvaluator = null;
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
if ("hypervolume".equals(indicator)) {
fitnessEvaluator = new HypervolumeFitnessEvaluator(problem);
} else if ("epsilon".equals(indicator)) {
fitnessEvaluator = new AdditiveEpsilonIndicatorFitnessEvaluator(
problem);
} else {
throw new IllegalArgumentException("invalid indicator: " +
indicator);
}
return new IBEA(problem, null, initialization, variation,
fitnessEvaluator);
}
/**
* Returns a new {@link SMSEMOA} instance.
*
* @param properties the properties for customizing the new {@code SMSEMOA}
* instance
* @param problem the problem
* @return a new {@code SMSEMOA} instance
*/
private Algorithm newSMSEMOA(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
double offset = properties.getDouble("offset", 100.0);
String indicator = properties.getString("indicator", "hypervolume");
FitnessEvaluator fitnessEvaluator = null;
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
if ("hypervolume".equals(indicator)) {
fitnessEvaluator = new HypervolumeContributionFitnessEvaluator(
problem, offset);
}
return new SMSEMOA(problem, initialization, variation,
fitnessEvaluator);
}
/**
* Returns a new {@link VEGA} instance.
*
* @param properties the properties for customizing the new {@code VEGA}
* instance
* @param problem the problem
* @return a new {@code VEGA} instance
*/
private Algorithm newVEGA(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
return new VEGA(problem, new Population(), null, initialization,
variation);
}
/**
* Returns a new {@link DBEA} instance.
*
* @param properties the properties for customizing the new {@code DBEA}
* instance
* @param problem the problem
* @return a new {@code DBEA} instance
*/
private Algorithm newDBEA(TypedProperties properties, Problem problem) {
int divisionsOuter = 4;
int divisionsInner = 0;
if (properties.contains("divisionsOuter") && properties.contains("divisionsInner")) {
divisionsOuter = (int)properties.getDouble("divisionsOuter", 4);
divisionsInner = (int)properties.getDouble("divisionsInner", 0);
} else if (properties.contains("divisions")){
divisionsOuter = (int)properties.getDouble("divisions", 4);
} else if (problem.getNumberOfObjectives() == 1) {
divisionsOuter = 100;
} else if (problem.getNumberOfObjectives() == 2) {
divisionsOuter = 99;
} else if (problem.getNumberOfObjectives() == 3) {
divisionsOuter = 12;
} else if (problem.getNumberOfObjectives() == 4) {
divisionsOuter = 8;
} else if (problem.getNumberOfObjectives() == 5) {
divisionsOuter = 6;
} else if (problem.getNumberOfObjectives() == 6) {
divisionsOuter = 4;
divisionsInner = 1;
} else if (problem.getNumberOfObjectives() == 7) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 8) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 9) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 10) {
divisionsOuter = 3;
divisionsInner = 2;
} else {
divisionsOuter = 2;
divisionsInner = 1;
}
int populationSize = (int)(CombinatoricsUtils.binomialCoefficient(problem.getNumberOfObjectives() + divisionsOuter - 1, divisionsOuter) +
(divisionsInner == 0 ? 0 : CombinatoricsUtils.binomialCoefficient(problem.getNumberOfObjectives() + divisionsInner - 1, divisionsInner)));
Initialization initialization = new RandomInitialization(problem,
populationSize);
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
return new DBEA(problem, initialization,
variation, divisionsOuter, divisionsInner);
}
/**
* Returns a new {@link RVEA} instance.
*
* @param properties the properties for customizing the new {@code RVEA}
* instance
* @param problem the problem
* @return a new {@code RVEA} instance
*/
private Algorithm newRVEA(TypedProperties properties, Problem problem) {
int divisionsOuter = 4;
int divisionsInner = 0;
if (problem.getNumberOfObjectives() < 2) {
throw new FrameworkException("RVEA requires at least two objectives");
}
if (properties.contains("divisionsOuter") && properties.contains("divisionsInner")) {
divisionsOuter = (int)properties.getDouble("divisionsOuter", 4);
divisionsInner = (int)properties.getDouble("divisionsInner", 0);
} else if (properties.contains("divisions")){
divisionsOuter = (int)properties.getDouble("divisions", 4);
} else if (problem.getNumberOfObjectives() == 1) {
divisionsOuter = 100;
} else if (problem.getNumberOfObjectives() == 2) {
divisionsOuter = 99;
} else if (problem.getNumberOfObjectives() == 3) {
divisionsOuter = 12;
} else if (problem.getNumberOfObjectives() == 4) {
divisionsOuter = 8;
} else if (problem.getNumberOfObjectives() == 5) {
divisionsOuter = 6;
} else if (problem.getNumberOfObjectives() == 6) {
divisionsOuter = 4;
divisionsInner = 1;
} else if (problem.getNumberOfObjectives() == 7) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 8) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 9) {
divisionsOuter = 3;
divisionsInner = 2;
} else if (problem.getNumberOfObjectives() == 10) {
divisionsOuter = 3;
divisionsInner = 2;
} else {
divisionsOuter = 2;
divisionsInner = 1;
}
// compute number of reference vectors
int populationSize = (int)(CombinatoricsUtils.binomialCoefficient(problem.getNumberOfObjectives() + divisionsOuter - 1, divisionsOuter) +
(divisionsInner == 0 ? 0 : CombinatoricsUtils.binomialCoefficient(problem.getNumberOfObjectives() + divisionsInner - 1, divisionsInner)));
Initialization initialization = new RandomInitialization(problem,
populationSize);
ReferenceVectorGuidedPopulation population = new ReferenceVectorGuidedPopulation(
problem.getNumberOfObjectives(), divisionsOuter, divisionsInner,
properties.getDouble("alpha", 2.0));
if (!properties.contains("sbx.swap")) {
properties.setBoolean("sbx.swap", false);
}
if (!properties.contains("sbx.distributionIndex")) {
properties.setDouble("sbx.distributionIndex", 30.0);
}
if (!properties.contains("pm.distributionIndex")) {
properties.setDouble("pm.distributionIndex", 20.0);
}
Variation variation = OperatorFactory.getInstance().getVariation(null,
properties, problem);
int maxGenerations = (int)(properties.getDouble("maxEvaluations", 10000) / populationSize);
int adaptFrequency = (int)properties.getDouble("adaptFrequency", maxGenerations / 10);
return new RVEA(problem, population, variation, initialization,
maxGenerations, adaptFrequency);
}
/**
* Returns a new {@link RandomSearch} instance.
*
* @param properties the properties for customizing the new
* {@code RandomSearch} instance
* @param problem the problem
* @return a new {@code RandomSearch} instance
*/
private Algorithm newRandomSearch(TypedProperties properties,
Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
Initialization generator = new RandomInitialization(problem,
populationSize);
NondominatedPopulation archive = null;
if (properties.contains("epsilon")) {
archive = new EpsilonBoxDominanceArchive(
properties.getDoubleArray("epsilon", new double[] {
EpsilonHelper.getEpsilon(problem) }));
} else {
archive = new NondominatedPopulation();
}
return new RandomSearch(problem, generator, archive);
}
/**
* Returns a new {@link MSOPS} instance.
*
* @param properties the properties for customizing the new {@code MSOPS}
* instance
* @param problem the problem
* @return a new {@code MSOPS} instance
*/
private Algorithm newMSOPS(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
int numberOfWeights = (int)properties.getDouble("numberOfWeights", 50);
Initialization initialization = new RandomInitialization(problem,
populationSize);
List<double[]> weights = new RandomGenerator(problem.getNumberOfObjectives(), numberOfWeights).generate();
// normalize weights so their magnitude is 1
for (int i = 0; i < weights.size(); i++) {
weights.set(i, Vector.normalize(weights.get(i)));
}
MSOPSRankedPopulation population = new MSOPSRankedPopulation(weights);
DifferentialEvolutionSelection selection = new DifferentialEvolutionSelection();
DifferentialEvolutionVariation variation = (DifferentialEvolutionVariation)OperatorFactory.getInstance().getVariation(
"de", properties, problem);
return new MSOPS(problem, population, selection, variation,
initialization);
}
/**
* Returns a new single-objective {@link RepeatedSingleObjective} instance.
*
* @param properties the properties for customizing the new
* {@code RepeatedSingleObjective} instance
* @param problem the problem
* @return a new {@code RepeatedSingleObjective} instance
*/
private Algorithm newRSO(TypedProperties properties, Problem problem) {
String algorithmName = properties.getString("algorithm", "GA");
int instances = (int)properties.getDouble("instances", 100);
if (!properties.contains("method")) {
properties.setString("method", "min-max");
}
return new RepeatedSingleObjective(problem, algorithmName,
properties.getProperties(), instances);
}
/**
* Returns a new single-objective {@link GeneticAlgorithm} instance.
*
* @param properties the properties for customizing the new
* {@code GeneticAlgorithm} instance
* @param problem the problem
* @return a new {@code GeneticAlgorithm} instance
*/
private Algorithm newGeneticAlgorithm(TypedProperties properties, Problem problem) {
int populationSize = (int)properties.getDouble("populationSize", 100);
double[] weights = properties.getDoubleArray("weights", new double[] { 1.0 });
String method = properties.getString("method", "linear");
AggregateObjectiveComparator comparator = null;
if (method.equalsIgnoreCase("linear")) {
comparator = new LinearDominanceComparator(weights);
} else if (method.equalsIgnoreCase("min-max")) {
comparator = new MinMaxDominanceComparator(weights);
} else {
throw new FrameworkException("unrecognized weighting method: " + method);
}
Initialization initialization = new RandomInitialization(problem, populationSize);
Selection selection = new TournamentSelection(2, comparator);
Variation variation = OperatorFactory.getInstance().getVariation(null, properties, problem);
return new GeneticAlgorithm(problem, comparator, initialization, selection, variation);
}
/**
* Returns a new single-objective {@link EvolutionStrategy} instance.
*
* @param properties the properties for customizing the new
* {@code EvolutionaryStrategy} instance
* @param problem the problem
* @return a new {@code EvolutionaryStrategy} instance
*/
private Algorithm newEvolutionaryStrategy(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
double[] weights = properties.getDoubleArray("weights", new double[] { 1.0 });
String method = properties.getString("method", "linear");
AggregateObjectiveComparator comparator = null;
if (method.equalsIgnoreCase("linear")) {
comparator = new LinearDominanceComparator(weights);
} else if (method.equalsIgnoreCase("min-max")) {
comparator = new MinMaxDominanceComparator(weights);
} else {
throw new FrameworkException("unrecognized weighting method: " + method);
}
Initialization initialization = new RandomInitialization(problem, populationSize);
Variation variation = new SelfAdaptiveNormalVariation();
return new EvolutionStrategy(problem, comparator, initialization, variation);
}
/**
* Returns a new single-objective {@link DE/rand/1/bin} instance.
*
* @param properties the properties for customizing the new
* {@code DE/rand/1/bin} instance
* @param problem the problem
* @return a new {@code DE/rand/1/bin} instance
*/
private Algorithm newDifferentialEvolution(TypedProperties properties, Problem problem) {
if (!checkType(RealVariable.class, problem)) {
throw new FrameworkException("unsupported decision variable type");
}
int populationSize = (int)properties.getDouble("populationSize", 100);
double[] weights = properties.getDoubleArray("weights", new double[] { 1.0 });
String method = properties.getString("method", "linear");
AggregateObjectiveComparator comparator = null;
if (method.equalsIgnoreCase("linear")) {
comparator = new LinearDominanceComparator(weights);
} else if (method.equalsIgnoreCase("min-max")) {
comparator = new MinMaxDominanceComparator(weights);
} else {
throw new FrameworkException("unrecognized weighting method: " + method);
}
Initialization initialization = new RandomInitialization(problem, populationSize);
DifferentialEvolutionSelection selection = new DifferentialEvolutionSelection();
DifferentialEvolutionVariation variation = (DifferentialEvolutionVariation)OperatorFactory.getInstance()
.getVariation("de", properties, problem);
return new DifferentialEvolution(problem, comparator, initialization, selection, variation);
}
}