/* 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.NotSerializableException; import java.io.Serializable; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.moeaframework.TestUtils; import org.moeaframework.core.EpsilonBoxDominanceArchive; import org.moeaframework.core.EpsilonBoxEvolutionaryAlgorithm; import org.moeaframework.core.NondominatedPopulation; import org.moeaframework.core.Population; import org.moeaframework.core.Problem; import org.moeaframework.core.Solution; import org.moeaframework.core.operator.UniformSelection; import org.moeaframework.core.operator.real.UM; /** * Test the {@link AdaptiveTimeContinuation} class. */ public class AdaptiveTimeContinuationTest { protected Population population; protected EpsilonBoxDominanceArchive archive; protected MockAlgorithm algorithm; protected AdaptiveTimeContinuation adaptiveTimeContinuation; protected int numberOfRestarts; private class MockAlgorithm implements EpsilonBoxEvolutionaryAlgorithm { private int numberOfIterations; @Override public Population getPopulation() { return population; } @Override public Problem getProblem() { throw new UnsupportedOperationException(); } @Override public NondominatedPopulation getResult() { throw new UnsupportedOperationException(); } @Override public void step() { numberOfIterations++; } @Override public void evaluate(Solution solution) { //do nothing } @Override public int getNumberOfEvaluations() { throw new UnsupportedOperationException(); } @Override public boolean isTerminated() { throw new UnsupportedOperationException(); } @Override public void terminate() { throw new UnsupportedOperationException(); } @Override public EpsilonBoxDominanceArchive getArchive() { return archive; } public int getNumberOfIterations() { return numberOfIterations; } @Override public Serializable getState() throws NotSerializableException { throw new UnsupportedOperationException(); } @Override public void setState(Object state) throws NotSerializableException { throw new UnsupportedOperationException(); } } @Before public void setUp() { population = new Population(); archive = new EpsilonBoxDominanceArchive(0.01); algorithm = new MockAlgorithm(); adaptiveTimeContinuation = new AdaptiveTimeContinuation( algorithm, 10, 100, 4.0, 4, 20, new UniformSelection(), new UM(1.0)); adaptiveTimeContinuation.addRestartListener(new RestartListener() { @Override public void restarted(RestartEvent event) { numberOfRestarts++; } }); numberOfRestarts = 0; } @After public void tearDown() { population = null; archive = null; algorithm = null; adaptiveTimeContinuation = null; } @Test public void testMaxWindow() { population.add(TestUtils.newSolution(0.0, 1.0)); population.add(TestUtils.newSolution(0.5, 0.5)); population.add(TestUtils.newSolution(1.0, 0.0)); population.add(TestUtils.newSolution(0.0, 1.0)); population.add(TestUtils.newSolution(0.5, 0.5)); population.add(TestUtils.newSolution(1.0, 0.0)); archive.add(TestUtils.newSolution(1.0, 0.0)); archive.add(TestUtils.newSolution(0.0, 1.0)); for (int i=0; i<1000; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(1000, algorithm.getNumberOfIterations()); Assert.assertEquals(10, numberOfRestarts); } @Test public void testPopulationRatio() { //population=6, archive=2, ratio within 25% population.add(TestUtils.newSolution(0.0, 1.0)); population.add(TestUtils.newSolution(0.5, 0.5)); population.add(TestUtils.newSolution(1.0, 0.0)); population.add(TestUtils.newSolution(0.0, 1.0)); population.add(TestUtils.newSolution(0.5, 0.5)); population.add(TestUtils.newSolution(1.0, 0.0)); archive.add(TestUtils.newSolution(0.0, 1.0)); archive.add(TestUtils.newSolution(1.0, 0.0)); for (int i=0; i<10; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(0, numberOfRestarts); //population=5, archive=2, population too small but not yet checked population.remove(0); for (int i=0; i<9; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(0, numberOfRestarts); //checked on 10th step adaptiveTimeContinuation.step(); Assert.assertEquals(1, numberOfRestarts); Assert.assertEquals(8, population.size()); //no other restarts should occur up to maxWindowSize for (int i=0; i<99; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(1, numberOfRestarts); } @Test public void testMaxPopulationSize() { archive.add(TestUtils.newSolution(1.0, 0.0)); archive.add(TestUtils.newSolution(0.75, 0.25)); archive.add(TestUtils.newSolution(0.5, 0.5)); archive.add(TestUtils.newSolution(0.25, 0.75)); archive.add(TestUtils.newSolution(0.0, 1.0)); for (int i=0; i<100; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(1, numberOfRestarts); Assert.assertEquals(20, population.size()); } @Test public void testMinPopulationSize() { population.add(TestUtils.newSolution(0.0, 1.0)); population.add(TestUtils.newSolution(0.5, 0.5)); population.add(TestUtils.newSolution(1.0, 0.0)); archive.add(TestUtils.newSolution(0.0, 1.0)); for (int i=0; i<100; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(1, numberOfRestarts); Assert.assertEquals(4, population.size()); } /** * Ensures an empty archive results in an error rather than an infinite * loop. */ @Test(expected=Exception.class) public void testEmptyArchive() { for (int i=0; i<100; i++) { adaptiveTimeContinuation.step(); } } /** * Ensures that if the population ratio would result in a population size * exceeding the maximum population size, a sequence of back-to-back * restarts would not occur due to the population ratio being violated. */ @Test public void testPopulationRatioConflictWithMaxPopulationSize() { archive.add(TestUtils.newSolution(1.0, 0.0)); archive.add(TestUtils.newSolution(0.9, 0.1)); archive.add(TestUtils.newSolution(0.75, 0.25)); archive.add(TestUtils.newSolution(0.5, 0.5)); archive.add(TestUtils.newSolution(0.25, 0.75)); archive.add(TestUtils.newSolution(0.1, 0.9)); archive.add(TestUtils.newSolution(0.0, 1.0)); for (int i=0; i<1000; i++) { adaptiveTimeContinuation.step(); } Assert.assertEquals(10, numberOfRestarts); Assert.assertEquals(20, population.size()); } }