eu.crisis_economics.abm.markets.clearing.heterogeneous.LineSearchTest.java Source code

Java tutorial

Introduction

Here is the source code for eu.crisis_economics.abm.markets.clearing.heterogeneous.LineSearchTest.java

Source

/*
 * This file is part of CRISIS, an economics simulator.
 * 
 * Copyright (C) 2015 John Kieran Phillips
 *
 * CRISIS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CRISIS 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CRISIS.  If not, see <http://www.gnu.org/licenses/>.
 */
package eu.crisis_economics.abm.markets.clearing.heterogeneous;

import java.util.Random;

import org.apache.commons.math3.analysis.MultivariateFunction;
import org.junit.Assert;
import org.junit.Test;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

import eu.crisis_economics.abm.algorithms.optimization.BrentLineSearch;
import eu.crisis_economics.abm.algorithms.optimization.BrentLineSearch.LineSearchResult;

public class LineSearchTest {

    @BeforeMethod
    public void setUp() {
        System.out.println("Testing Brent line search minimizer..");
    }

    @Test
    /**
      * Test the Brent line search algorithm by minimizing a one-dimensional
      * cosine function. The starting point of the minimization is the origin,
      * and the maximum distance to travel in the positive x direction is 2*Pi.
      * The expected solution is therefor the local minimum at Pi.
      */
    public void testOneDimensionalCosMinimization() {
        final MultivariateFunction meritFunction = new MultivariateFunction() {
            @Override
            public double value(final double[] x) {
                return Math.cos(x[0]);
            }
        };
        final double[] lineDirection = new double[] { 1.0 };
        double distanceToTravel = Math.PI * 2.;
        final LineSearchResult solution = BrentLineSearch.doLineSearch(meritFunction, new double[] { 0.0 },
                lineDirection, distanceToTravel);
        Assert.assertTrue(Math.abs(solution.getEvaluationAtSolution() + 1.) < 1.e-10);
        Assert.assertEquals(solution.getSolutionPoint()[0], Math.PI, 1.e-10);
    }

    @Test
    /**
      * Test the Brent line search algorithm by minimizing a multidimensional
      * quadratic scalar function. This test generates many random quadratic 
      * fields with random global minima. In each case, the starting point
      * of the minimization is random and the line search direction points 
      * toward the global minimum.
      */
    public void batchTestMultidimensionalQuadraticLineSearch() {
        final Random dice = new Random();
        for (int i = 0; i < 100; ++i) { // 100 random quadratic minimization tests
            final int numDimensions = dice.nextInt(20) + 2;
            final double[] globalMinimum = new double[numDimensions], startingPoint = new double[numDimensions];
            for (int j = 0; j < globalMinimum.length; ++j) {
                globalMinimum[j] = dice.nextDouble() * 10. - 5.;
                startingPoint[j] = dice.nextDouble() * 10. - 5.;
            }
            testMultiDimensionalQuadraticMinimization(numDimensions, startingPoint, globalMinimum);
        }
    }

    private void testMultiDimensionalQuadraticMinimization(final int numberOfDimensions,
            final double[] startingPoint, final double[] locationOfGlobalMinimum) {
        final MultivariateFunction meritFunction = new MultivariateFunction() {
            @Override
            public double value(final double[] x) {
                double result = 0.;
                for (int i = 0; i < numberOfDimensions; ++i)
                    result += (x[i] - locationOfGlobalMinimum[i]) * (x[i] - locationOfGlobalMinimum[i]);
                return result;
            }
        };
        final double[] lineDirection = new double[startingPoint.length];
        double distanceToTravel = 0.;
        for (int i = 0; i < lineDirection.length; ++i) {
            lineDirection[i] = locationOfGlobalMinimum[i] - startingPoint[i];
            distanceToTravel += lineDirection[i] * lineDirection[i];
        }
        distanceToTravel = Math.sqrt(distanceToTravel);
        final LineSearchResult solution = BrentLineSearch.doLineSearch(meritFunction, startingPoint, lineDirection,
                distanceToTravel + 1.);
        Assert.assertTrue(Math.abs(solution.getEvaluationAtSolution()) < 1.e-10);
        for (int i = 0; i < startingPoint.length; ++i)
            Assert.assertEquals(solution.getSolutionPoint()[i], locationOfGlobalMinimum[i], 1.e-10);
    }

    @Test
    /**
      * Test the Brent line search algorithm by minimizing a negative
      * multidimensional quadratic scalar function, with maximum at the
      * origin. This test generated many random boundary boxes (limits
      * inside of which to perform line searches) and, in each case, 
      * extremizes the quadratic function along a random direction starting
      * at the origin. It is expected that the solution lies on the domain
      * bounds in each case.
      */
    public void batchTestBoundedDecreasingMultidimensionalSearch() {
        final Random dice = new Random();
        for (int i = 0; i < 100; ++i) { // 100 random tests
            final int numDimensions = dice.nextInt(20) + 2;
            final double[] lowerDomainBounds = new double[numDimensions],
                    upperDomainBounds = new double[numDimensions];
            for (int j = 0; j < numDimensions; ++j) {
                lowerDomainBounds[j] = -dice.nextDouble();
                upperDomainBounds[j] = +dice.nextDouble();
            }
            testOptimizationWithDomainBounds(numDimensions, lowerDomainBounds, upperDomainBounds);
        }
    }

    private void testOptimizationWithDomainBounds(final int numberOfDimensions, final double[] lowerDomainBounds,
            final double[] upperDomainBounds) {
        final MultivariateFunction meritFunction = new MultivariateFunction() {
            @Override
            public double value(final double[] x) {
                double result = 0.;
                for (int i = 0; i < numberOfDimensions; ++i)
                    result += -x[i] * x[i];
                return result;
            }
        };
        Random dice = new Random();
        double[] startingPoint = new double[numberOfDimensions], vectorDirection = new double[numberOfDimensions];
        for (int i = 0; i < numberOfDimensions; ++i)
            vectorDirection[i] = dice.nextDouble() - .5;
        LineSearchResult solution = BrentLineSearch.doLineSearch(meritFunction, startingPoint, vectorDirection,
                upperDomainBounds, lowerDomainBounds);
        boolean solutionIsOnDomainBoundary = false;
        for (int i = 0; i < numberOfDimensions; ++i) {
            final double solutionPoint = solution.getSolutionPoint()[i];
            System.out.printf("Coordinate %4d: distance from lower bound: %16.10g, from upper bound: %16.10g\n", i,
                    solutionPoint - lowerDomainBounds[i], upperDomainBounds[i] - solutionPoint);
            if (Math.abs(solutionPoint - upperDomainBounds[i]) < 1.e-8
                    || Math.abs(solutionPoint - lowerDomainBounds[i]) < 1.e-8)
                solutionIsOnDomainBoundary = true;
        }
        Assert.assertTrue(solutionIsOnDomainBoundary);
    }

    @AfterMethod
    public void tearDown() {
        System.out.println("Brent line search minimizer tests pass.");
    }

    /**
      * Manual entry point.
      */
    static public void main(String[] args) {
        final LineSearchTest test = new LineSearchTest();
        test.setUp();
        test.testOneDimensionalCosMinimization();
        test.batchTestMultidimensionalQuadraticLineSearch();
        test.batchTestBoundedDecreasingMultidimensionalSearch();
        test.tearDown();
    }
}