/* Copyright 2009-2015 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.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import org.junit.Assert;
import org.moeaframework.Analyzer;
import org.moeaframework.Executor;
import org.moeaframework.core.spi.AlgorithmFactory;
/**
* Methods for comparing two algorithm implementations statistically.
*/
public abstract class AlgorithmTest {
/**
* Tests if two algorithms are statistically indifferent. The default
* {@link AlgorithmFactory} is used to create instances.
*
* @param problem the name of the problem to test
* @param algorithm1 the name of the first algorithm to test
* @param algorithm2 the name of the second algorithm to test
* @throws IOException should not occur
*/
public void test(String problem, String algorithm1, String algorithm2)
throws IOException {
test(problem, algorithm1, algorithm2, AlgorithmFactory.getInstance());
}
/**
* Tests if two algorithms are statistically indifferent.
*
* @param problem the name of the problem to test
* @param algorithm1 the name of the first algorithm to test
* @param algorithm2 the name of the second algorithm to test
* @param factory the factory used to construct the algorithms
* @throws IOException should not occur
*/
public void test(String problem, String algorithm1, String algorithm2,
AlgorithmFactory factory) throws IOException {
Analyzer analyzer = new Analyzer()
.withProblem(problem)
.includeAllMetrics()
.showAggregate()
.showStatisticalSignificance();
Executor executor = new Executor()
.withProblem(problem)
.usingAlgorithmFactory(factory)
.withMaxEvaluations(10000)
.distributeOnAllCores();
analyzer.addAll(algorithm1,
executor.withAlgorithm(algorithm1).runSeeds(10));
analyzer.addAll(algorithm2,
executor.withAlgorithm(algorithm2).runSeeds(10));
ByteArrayOutputStream output = null;
try {
output = new ByteArrayOutputStream();
analyzer.printAnalysis(new PrintStream(output));
Assert.assertTrue(countIndifferences(output.toString(), algorithm1)
>= 5);
} finally {
if (output != null) {
output.close();
}
}
}
/**
* Counts the number of indifferences in the statistical output by counting
* the number of lines matching
* <pre>
* Indifferent: [<algorithmName>]
* </pre>
*
* @param output the statistical output from
* {@link Analyzer#printAnalysis(PrintStream)}
* @param algorithmName the name of one of the algorithms being tested
* @return the number of indifferences in the statistical output
* @throws IOException should not occur
*/
public int countIndifferences(String output, String algorithmName)
throws IOException {
BufferedReader reader = null;
String line = null;
int count = 0;
try {
reader = new BufferedReader(new StringReader(output));
while ((line = reader.readLine()) != null) {
if (line.matches("^\\s*Indifferent:\\s*\\[" + algorithmName +
"\\]\\s*$")) {
count++;
}
}
} finally {
if (reader != null) {
reader.close();
}
}
return count;
}
}