/* 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.io.File;
import java.io.IOException;
import org.apache.commons.math3.stat.descriptive.rank.Max;
import org.apache.commons.math3.stat.descriptive.rank.Median;
import org.apache.commons.math3.stat.descriptive.rank.Min;
import org.junit.Ignore;
import org.junit.Test;
import org.moeaframework.core.Algorithm;
import org.moeaframework.core.NondominatedPopulation;
import org.moeaframework.core.Population;
import org.moeaframework.core.PopulationIO;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Solution;
import org.moeaframework.core.indicator.InvertedGenerationalDistance;
import org.moeaframework.core.spi.AlgorithmFactory;
import org.moeaframework.problem.DTLZ.DTLZ1;
import org.moeaframework.problem.DTLZ.DTLZ2;
import org.moeaframework.problem.DTLZ.DTLZ3;
import org.moeaframework.problem.DTLZ.DTLZ4;
import org.moeaframework.util.TypedProperties;
/**
* Tests the {@link NSGAIII} class.
*/
public class NSGAIIITest {
/**
* Replicates the unscaled and scaled DTLZ experiments performed in the
* original NSGA-III paper.
*/
@Test
@Ignore("Must download reference sets from http://web.ntnu.edu.tw/~tcchiang/publications/nsga3cpp/nsga3cpp.htm")
public void test() throws IOException {
evaluate(new DTLZ1(3), 400, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(3)-PF.txt"))));
evaluate(new DTLZ1(5), 600, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(5)-PF.txt"))));
evaluate(new DTLZ1(8), 750, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(8)-PF.txt"))));
evaluate(new DTLZ1(10), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(10)-PF.txt"))));
evaluate(new DTLZ1(15), 1500, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(15)-PF.txt"))));
evaluate(new DTLZ2(3), 250, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(3)-PF.txt"))));
evaluate(new DTLZ2(5), 350, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(5)-PF.txt"))));
evaluate(new DTLZ2(8), 500, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(8)-PF.txt"))));
evaluate(new DTLZ2(10), 750, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(10)-PF.txt"))));
evaluate(new DTLZ2(15), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(15)-PF.txt"))));
evaluate(new DTLZ3(3), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ3(3)-PF.txt"))));
evaluate(new DTLZ3(5), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ3(5)-PF.txt"))));
evaluate(new DTLZ3(8), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ3(8)-PF.txt"))));
evaluate(new DTLZ3(10), 1500, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ3(10)-PF.txt"))));
evaluate(new DTLZ3(15), 2000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ3(15)-PF.txt"))));
evaluate(new DTLZ4(3), 600, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ4(3)-PF.txt"))));
evaluate(new DTLZ4(5), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ4(5)-PF.txt"))));
evaluate(new DTLZ4(8), 1250, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ4(8)-PF.txt"))));
evaluate(new DTLZ4(10), 2000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ4(10)-PF.txt"))));
evaluate(new DTLZ4(15), 3000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ4(15)-PF.txt"))));
new ScaledProblem(new DTLZ1(3), 10).scaleReferenceSet(new File("DTLZ1(3)-PF.txt"), new File("DTLZ1(3)-PFscaled.txt"));
new ScaledProblem(new DTLZ1(5), 10).scaleReferenceSet(new File("DTLZ1(5)-PF.txt"), new File("DTLZ1(5)-PFscaled.txt"));
new ScaledProblem(new DTLZ1(8), 3).scaleReferenceSet(new File("DTLZ1(8)-PF.txt"), new File("DTLZ1(8)-PFscaled.txt"));
new ScaledProblem(new DTLZ1(10), 2).scaleReferenceSet(new File("DTLZ1(10)-PF.txt"), new File("DTLZ1(10)-PFscaled.txt"));
new ScaledProblem(new DTLZ1(15), 1.2).scaleReferenceSet(new File("DTLZ1(15)-PF.txt"), new File("DTLZ1(15)-PFscaled.txt"));
new ScaledProblem(new DTLZ2(3), 10).scaleReferenceSet(new File("DTLZ2(3)-PF.txt"), new File("DTLZ2(3)-PFscaled.txt"));
new ScaledProblem(new DTLZ2(5), 10).scaleReferenceSet(new File("DTLZ2(5)-PF.txt"), new File("DTLZ2(5)-PFscaled.txt"));
new ScaledProblem(new DTLZ2(8), 3).scaleReferenceSet(new File("DTLZ2(8)-PF.txt"), new File("DTLZ2(8)-PFscaled.txt"));
new ScaledProblem(new DTLZ2(10), 3).scaleReferenceSet(new File("DTLZ2(10)-PF.txt"), new File("DTLZ2(10)-PFscaled.txt"));
new ScaledProblem(new DTLZ2(15), 2).scaleReferenceSet(new File("DTLZ2(15)-PF.txt"), new File("DTLZ2(15)-PFscaled.txt"));
evaluate(new ScaledProblem(new DTLZ1(3), 10), 400, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(3)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ1(5), 10), 600, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(5)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ1(8), 3), 750, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(8)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ1(10), 2), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(10)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ1(15), 1.2), 1500, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ1(15)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ2(3), 10), 250, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(3)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ2(5), 10), 350, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(5)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ2(8), 3), 500, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(8)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ2(10), 3), 750, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(10)-PFscaled.txt"))));
evaluate(new ScaledProblem(new DTLZ2(15), 2), 1000, new NondominatedPopulation(PopulationIO.readObjectives(new File("DTLZ2(15)-PFscaled.txt"))));
}
public void evaluate(Problem problem, int maxGen, NondominatedPopulation referenceSet) {
int trials = 20;
double[] igdValues = new double[trials];
InvertedGenerationalDistance igd = new InvertedGenerationalDistance(
problem, referenceSet, 2.0);
for (int i = 0; i < trials; i++) {
int populationSize;
if (problem.getNumberOfObjectives() == 3) {
populationSize = 92;
} else if (problem.getNumberOfObjectives() == 5) {
populationSize = 212;
} else if (problem.getNumberOfObjectives() == 8) {
populationSize = 156;
} else if (problem.getNumberOfObjectives() == 10) {
populationSize = 276;
} else if (problem.getNumberOfObjectives() == 15) {
populationSize = 136;
} else {
throw new IllegalArgumentException();
}
TypedProperties properties = new TypedProperties();
properties.setDouble("sbx.rate", 1.0);
properties.setDouble("sbx.distributionIndex", 30.0);
properties.setDouble("pm.distributionIndex", 20.0);
properties.setBoolean("sbx.swap", false);
properties.setDouble("populationSize", populationSize);
if (problem.getNumberOfObjectives() == 3) {
properties.setInt("divisions", 12);
} else if (problem.getNumberOfObjectives() == 5) {
properties.setInt("divisions", 6);
} else if (problem.getNumberOfObjectives() == 8) {
properties.setInt("divisionsOuter", 3);
properties.setInt("divisionsInner", 2);
} else if (problem.getNumberOfObjectives() == 10) {
properties.setInt("divisionsOuter", 3);
properties.setInt("divisionsInner", 2);
} else if (problem.getNumberOfObjectives() == 15) {
properties.setInt("divisionsOuter", 2);
properties.setInt("divisionsInner", 1);
}
Algorithm algorithm = AlgorithmFactory.getInstance().getAlgorithm(
"NSGAIII", properties.getProperties(), problem);
while (algorithm.getNumberOfEvaluations() < maxGen*populationSize) {
algorithm.step();
}
NondominatedPopulation result = algorithm.getResult();
igdValues[i] = igd.evaluate(result);
}
System.out.println(problem.getName() + " " + problem.getNumberOfObjectives());
System.out.println(" Min: " + new Min().evaluate(igdValues));
System.out.println(" Med: " + new Median().evaluate(igdValues));
System.out.println(" Max: " + new Max().evaluate(igdValues));
}
public class ScaledProblem implements Problem {
private final Problem problem;
private final double[] factors;
public ScaledProblem(Problem problem, double base) {
super();
this.problem = problem;
factors = new double[problem.getNumberOfObjectives()];
for (int i = 0; i < problem.getNumberOfObjectives(); i++) {
factors[i] = Math.pow(base, i);
}
}
@Override
public String getName() {
return "Scaled " + problem.getName();
}
@Override
public int getNumberOfVariables() {
return problem.getNumberOfVariables();
}
@Override
public int getNumberOfObjectives() {
return problem.getNumberOfObjectives();
}
@Override
public int getNumberOfConstraints() {
return problem.getNumberOfConstraints();
}
@Override
public void evaluate(Solution solution) {
problem.evaluate(solution);
for (int i = 0; i < problem.getNumberOfObjectives(); i++) {
solution.setObjective(i, solution.getObjective(i) * factors[i]);
}
}
@Override
public Solution newSolution() {
return problem.newSolution();
}
@Override
public void close() {
problem.close();
}
public void scaleReferenceSet(File file, File scaledFile) throws IOException {
Population population = PopulationIO.readObjectives(file);
for (Solution solution : population) {
for (int i = 0; i < solution.getNumberOfObjectives(); i++) {
solution.setObjective(i, solution.getObjective(i) * factors[i]);
}
}
PopulationIO.writeObjectives(scaledFile, population);
}
}
}