org.moeaframework.core.operator.AdaptiveMultimethodVariationTest.java Source code

Java tutorial

Introduction

Here is the source code for org.moeaframework.core.operator.AdaptiveMultimethodVariationTest.java

Source

/* 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.core.operator;

import org.apache.commons.math3.util.ArithmeticUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.moeaframework.TestThresholds;
import org.moeaframework.core.Population;
import org.moeaframework.core.Settings;
import org.moeaframework.core.Solution;
import org.moeaframework.core.Variation;

/**
 * Tests the {@link AdaptiveMultimethodVariation} class.
 */
public class AdaptiveMultimethodVariationTest {

    /**
     * The shared population used for testing.
     */
    private Population population;

    /**
     * The shared adaptive multhmethod variation operator used for testing.
     */
    private AdaptiveMultimethodVariation variation;

    /**
     * A dummy variation operator that counts the number of invocations of
     * {@code evolve}.
     */
    private static class DummyVariation implements Variation {

        /**
         * The arity of this operator.
         */
        private final int arity;

        /**
         * The number of invocations of the {@code evolve} method.
         */
        private int count = 0;

        /**
         * Constructs a dummy variation operator with the specified arity.
         * 
         * @param arity the arity of this operator
         */
        public DummyVariation(int arity) {
            super();
            this.arity = arity;
        }

        @Override
        public int getArity() {
            return arity;
        }

        @Override
        public Solution[] evolve(Solution[] parents) {
            count++;
            Assert.assertEquals(arity, parents.length);
            return new Solution[0];
        }

    }

    /**
     * Creates the shared objects used by these tests.
     */
    @Before
    public void setUp() {
        population = new Population();

        Solution s1 = new Solution(0, 0);
        Solution s2 = new Solution(0, 0);
        Solution s3 = new Solution(0, 0);

        s1.setAttribute(AdaptiveMultimethodVariation.OPERATOR_ATTRIBUTE, 0);
        s2.setAttribute(AdaptiveMultimethodVariation.OPERATOR_ATTRIBUTE, 1);
        s3.setAttribute(AdaptiveMultimethodVariation.OPERATOR_ATTRIBUTE, 0);

        population.add(s1);
        population.add(s2);
        population.add(s3);

        variation = new AdaptiveMultimethodVariation(population);
    }

    /**
     * Removes references to shared objects so they can be garbage collected.
     */
    @After
    public void tearDown() {
        population = null;
        variation = null;
    }

    /**
     * Tests if an exception is thrown when calling the {@code getArity()}
     * method with no operators.
     */
    @Test(expected = Exception.class)
    public void testGetArityNoOperators() {
        variation.getArity();
    }

    /**
     * Tests if an exception is thrown when calling the {@code evolve()} method
     * with no operators.
     */
    @Test(expected = Exception.class)
    public void testEvolveNoOperators() {
        variation.evolve(null);
    }

    /**
     * Tests if the probabilities used are correct.
     */
    @Test
    public void testProbabilities() {
        variation.addOperator(new DummyVariation(1));
        variation.addOperator(new DummyVariation(3));

        Assert.assertEquals(3, variation.getArity());

        Assert.assertEquals(3.0 / 5.0, variation.getOperatorProbability(0), Settings.EPS);
        Assert.assertEquals(2.0 / 5.0, variation.getOperatorProbability(1), Settings.EPS);

        assertActualSelectionProbabilities(variation, 3.0 / 5.0, 2.0 / 5.0);
    }

    /**
     * Tests if the probabilities used are correct for an initial population.
     */
    @Test
    public void testProbabilitiesInitialPopulation() {
        variation.addOperator(new DummyVariation(2));
        variation.addOperator(new DummyVariation(2));

        Assert.assertEquals(2, variation.getArity());

        for (Solution solution : population) {
            solution.removeAttribute(AdaptiveMultimethodVariation.OPERATOR_ATTRIBUTE);
        }

        Assert.assertEquals(0.5, variation.getOperatorProbability(0), Settings.EPS);
        Assert.assertEquals(0.5, variation.getOperatorProbability(1), Settings.EPS);

        assertActualSelectionProbabilities(variation, 0.5, 0.5);
    }

    /**
     * Tests if the actual selection probabilities are equal to the expected
     * selection probabilities.
     * 
     * @param variation the variation operator
     * @param probabilities the expected selection probabilities
     */
    private void assertActualSelectionProbabilities(AdaptiveMultimethodVariation variation,
            double... probabilities) {
        UniformSelection selection = new UniformSelection();

        for (int i = 0; i < TestThresholds.SAMPLES; i++) {
            variation.evolve(selection.select(variation.getArity(), population));
        }

        Assert.assertEquals(variation.getNumberOfOperators(), probabilities.length);

        for (int i = 0; i < variation.getNumberOfOperators(); i++) {
            int count = ((DummyVariation) variation.getOperator(i)).count;

            Assert.assertEquals(probabilities[i], count / (double) TestThresholds.SAMPLES,
                    TestThresholds.STATISTICS_EPS);
        }
    }

    /**
     * Extends {@link AdaptiveMultimethodVariation} to count the number of
     * invocations to {@link #getOperatorProbabilities()}.
     */
    private class AdaptiveMultimethodVariationCounter extends AdaptiveMultimethodVariation {

        private int count = 0;

        public AdaptiveMultimethodVariationCounter(Population archive) {
            super(archive);
        }

        @Override
        protected double[] getOperatorProbabilities() {
            count++;
            return super.getOperatorProbabilities();
        }

        public int getCount() {
            return count;
        }

    }

    /**
     * Tests if the number of invocations between probability updates matches
     * the UPDATE_WINDOW.
     */
    @Test
    public void testProbabilityUpdateInvocationCount() {
        AdaptiveMultimethodVariationCounter variation = new AdaptiveMultimethodVariationCounter(population);
        variation.addOperator(new DummyVariation(2));
        variation.addOperator(new DummyVariation(2));

        UniformSelection selection = new UniformSelection();

        //ensure sufficient number of samples to trigger off-by-one error
        int numberOfSamples = ArithmeticUtils.pow(variation.getUpdateWindow(), 3);

        for (int i = 0; i < numberOfSamples; i++) {
            variation.evolve(selection.select(variation.getArity(), population));
        }

        Assert.assertEquals(numberOfSamples / variation.getUpdateWindow(), variation.getCount());
    }

}