Skip to content

Instantly share code, notes, and snippets.

@dhadka
Created July 27, 2016 12:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhadka/9b63587cb34f3115fd05b35f0ce0cdfd to your computer and use it in GitHub Desktop.
Save dhadka/9b63587cb34f3115fd05b35f0ce0cdfd to your computer and use it in GitHub Desktop.
Demonstrates creating a new operator within the MOEA Framework
/* 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/>.
*/
import java.util.Properties;
import org.moeaframework.Executor;
import org.moeaframework.core.FrameworkException;
import org.moeaframework.core.NondominatedPopulation;
import org.moeaframework.core.PRNG;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Solution;
import org.moeaframework.core.Variable;
import org.moeaframework.core.Variation;
import org.moeaframework.core.spi.OperatorFactory;
import org.moeaframework.core.spi.OperatorProvider;
import org.moeaframework.core.variable.BinaryVariable;
import org.moeaframework.core.variable.EncodingUtils;
import org.moeaframework.problem.AbstractProblem;
import org.moeaframework.util.TypedProperties;
/**
* Demonstrates how to define a new operator (in this case, we define
* single-point binary crossover for binary integers) in the MOEA Framework.
*/
public class ExampleSinglePointBinaryCrossover {
/**
* Single-point crossover for binary variables.
*/
public static class SinglePointBinaryCrossover implements Variation {
/**
* The probability of applying this operator.
*/
private final double probability;
/**
* Constructs a single-point crossover operator for binary variables.
*
* @param probability the probability of applying this operator
*/
public SinglePointBinaryCrossover(double probability) {
super();
this.probability = probability;
}
@Override
public Solution[] evolve(Solution[] parents) {
Solution result1 = parents[0].copy();
Solution result2 = parents[1].copy();
for (int i = 0; i < result1.getNumberOfVariables(); i++) {
Variable variable1 = result1.getVariable(i);
Variable variable2 = result2.getVariable(i);
if ((PRNG.nextDouble() <= probability)
&& (variable1 instanceof BinaryVariable)
&& (variable2 instanceof BinaryVariable)) {
evolve((BinaryVariable)variable1, (BinaryVariable)variable2);
}
}
return new Solution[] { result1, result2 };
}
/**
* Evolves the specified variables using the single point crossover
* operator.
*
* @param v1 the first variable
* @param v2 the second variable
*/
public static void evolve(BinaryVariable v1, BinaryVariable v2) {
if (v1.getNumberOfBits() != v2.getNumberOfBits()) {
throw new FrameworkException("binary variables not same length");
}
int crossoverPoint = PRNG.nextInt(v1.getNumberOfBits() - 1);
for (int i = 0; i <= crossoverPoint; i++) {
boolean temp = v1.get(i);
v1.set(i, v2.get(i));
v2.set(i, temp);
}
}
@Override
public int getArity() {
return 2;
}
}
public static void main(String[] args) {
// First, register our new single point crossover operator with the
// MOEAFramework. Our operator will use the name "1xbin".
OperatorFactory.getInstance().addProvider(new OperatorProvider() {
@Override
public String getMutationHint(Problem problem) {
return null;
}
@Override
public String getVariationHint(Problem problem) {
return null;
}
@Override
public Variation getVariation(String name, Properties properties,
Problem problem) {
if (name.equalsIgnoreCase("1xbin")) {
TypedProperties typedProperties = new TypedProperties(properties);
return new SinglePointBinaryCrossover(
typedProperties.getDouble("1xbin.rate", 1.0));
} else {
return null;
}
}
});
// Second, lets define a simple problem using the binary integer
// encoding. This problem will have 1 variable and 2 objectives.
Problem problem = new AbstractProblem(1, 2) {
@Override
public void evaluate(Solution solution) {
double x = EncodingUtils.getInt(solution.getVariable(0));
solution.setObjective(0, Math.pow(x, 2.0));
solution.setObjective(1, Math.pow(x - 2.0, 2.0));
}
@Override
public Solution newSolution() {
Solution solution = new Solution(1, 2);
solution.setVariable(0, EncodingUtils.newBinaryInt(-10, 10));
return solution;
}
};
// Third, use the Executor to parameterize the algorithm. Here, we
// assign the operator as "1xbin+bf" to use our new single-point binary
// crossover operator with bit flip mutation.
NondominatedPopulation result = new Executor()
.withProblem(problem)
.withAlgorithm("NSGAII")
.withProperty("operator", "1xbin+bf")
.withMaxEvaluations(10000)
.run();
// Finally, display the results. There should be three solutions:
// (4, 0), (1, 1), and (0, 4)
System.out.format("Objective1 Objective2%n");
for (Solution solution : result) {
System.out.format("%.4f %.4f%n",
solution.getObjective(0),
solution.getObjective(1));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment