Package org.apache.commons.math3.analysis.solvers

Source Code of org.apache.commons.math3.analysis.solvers.BaseSecantSolverAbstractTest

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math3.analysis.solvers;

import org.apache.commons.math3.analysis.QuinticFunction;
import org.apache.commons.math3.analysis.UnivariateFunction;
import org.apache.commons.math3.analysis.XMinus5Function;
import org.apache.commons.math3.analysis.function.Sin;
import org.apache.commons.math3.exception.NoBracketingException;
import org.apache.commons.math3.exception.NumberIsTooLargeException;
import org.apache.commons.math3.util.FastMath;
import org.junit.Assert;
import org.junit.Test;

/**
* Base class for root-finding algorithms tests derived from
* {@link BaseSecantSolver}.
*
*/
public abstract class BaseSecantSolverAbstractTest {
    /** Returns the solver to use to perform the tests.
     * @return the solver to use to perform the tests
     */
    protected abstract UnivariateSolver getSolver();

    /** Returns the expected number of evaluations for the
     * {@link #testQuinticZero} unit test. A value of {@code -1} indicates that
     * the test should be skipped for that solver.
     * @return the expected number of evaluations for the
     * {@link #testQuinticZero} unit test
     */
    protected abstract int[] getQuinticEvalCounts();

    @Test
    public void testSinZero() {
        // The sinus function is behaved well around the root at pi. The second
        // order derivative is zero, which means linear approximating methods
        // still converge quadratically.
        UnivariateFunction f = new Sin();
        double result;
        UnivariateSolver solver = getSolver();

        result = solver.solve(100, f, 3, 4);
        //System.out.println(
        //    "Root: " + result + " Evaluations: " + solver.getEvaluations());
        Assert.assertEquals(result, FastMath.PI, solver.getAbsoluteAccuracy());
        Assert.assertTrue(solver.getEvaluations() <= 6);
        result = solver.solve(100, f, 1, 4);
        //System.out.println(
        //    "Root: " + result + " Evaluations: " + solver.getEvaluations());
        Assert.assertEquals(result, FastMath.PI, solver.getAbsoluteAccuracy());
        Assert.assertTrue(solver.getEvaluations() <= 7);
    }

    @Test
    public void testQuinticZero() {
        // The quintic function has zeros at 0, +-0.5 and +-1.
        // Around the root of 0 the function is well behaved, with a second
        // derivative of zero a 0.
        // The other roots are less well to find, in particular the root at 1,
        // because the function grows fast for x>1.
        // The function has extrema (first derivative is zero) at 0.27195613
        // and 0.82221643, intervals containing these values are harder for
        // the solvers.
        UnivariateFunction f = new QuinticFunction();
        double result;
        UnivariateSolver solver = getSolver();
        double atol = solver.getAbsoluteAccuracy();
        int[] counts = getQuinticEvalCounts();

        // Tests data: initial bounds, and expected solution, per test case.
        double[][] testsData = {{-0.20.20.0},
                                {-0.10.30.0},
                                {-0.30.45, 0.0},
                                { 0.30.70.5},
                                { 0.20.60.5},
                                { 0.05, 0.95, 0.5},
                                { 0.85, 1.25, 1.0},
                                { 0.81.21.0},
                                { 0.85, 1.75, 1.0},
                                { 0.55, 1.45, 1.0},
                                { 0.85, 5.01.0},
                               };
        int maxIter = 500;

        for(int i = 0; i < testsData.length; i++) {
            // Skip test, if needed.
            if (counts[i] == -1) continue;

            // Compute solution.
            double[] testData = testsData[i];
            result = solver.solve(maxIter, f, testData[0], testData[1]);
            //System.out.println(
            //    "Root: " + result + " Evaluations: " + solver.getEvaluations());

            // Check solution.
            Assert.assertEquals(result, testData[2], atol);
            Assert.assertTrue(solver.getEvaluations() <= counts[i] + 1);
        }
    }

    @Test
    public void testRootEndpoints() {
        UnivariateFunction f = new XMinus5Function();
        UnivariateSolver solver = getSolver();

        // End-point is root. This should be a special case in the solver, and
        // the initial end-point should be returned exactly.
        double result = solver.solve(100, f, 5.0, 6.0);
        Assert.assertEquals(5.0, result, 0.0);

        result = solver.solve(100, f, 4.0, 5.0);
        Assert.assertEquals(5.0, result, 0.0);

        result = solver.solve(100, f, 5.0, 6.0, 5.5);
        Assert.assertEquals(5.0, result, 0.0);

        result = solver.solve(100, f, 4.0, 5.0, 4.5);
        Assert.assertEquals(5.0, result, 0.0);
    }

    @Test
    public void testBadEndpoints() {
        UnivariateFunction f = new Sin();
        UnivariateSolver solver = getSolver();
        try // bad interval
            solver.solve(100, f, 1, -1);
            Assert.fail("Expecting NumberIsTooLargeException - bad interval");
        } catch (NumberIsTooLargeException ex) {
            // expected
        }
        try // no bracket
            solver.solve(100, f, 1, 1.5);
            Assert.fail("Expecting NoBracketingException - non-bracketing");
        } catch (NoBracketingException ex) {
            // expected
        }
        try // no bracket
            solver.solve(100, f, 1, 1.5, 1.2);
            Assert.fail("Expecting NoBracketingException - non-bracketing");
        } catch (NoBracketingException ex) {
            // expected
        }
    }

    @Test
    public void testSolutionLeftSide() {
        UnivariateFunction f = new Sin();
        UnivariateSolver solver = getSolver();
        double left = -1.5;
        double right = 0.05;
        for(int i = 0; i < 10; i++) {
            // Test whether the allowed solutions are taken into account.
            double solution = getSolution(solver, 100, f, left, right, AllowedSolution.LEFT_SIDE);
            if (!Double.isNaN(solution)) {
                Assert.assertTrue(solution <= 0.0);
            }

            // Prepare for next test.
            left -= 0.1;
            right += 0.3;
        }
    }

    @Test
    public void testSolutionRightSide() {
        UnivariateFunction f = new Sin();
        UnivariateSolver solver = getSolver();
        double left = -1.5;
        double right = 0.05;
        for(int i = 0; i < 10; i++) {
            // Test whether the allowed solutions are taken into account.
            double solution = getSolution(solver, 100, f, left, right, AllowedSolution.RIGHT_SIDE);
            if (!Double.isNaN(solution)) {
                Assert.assertTrue(solution >= 0.0);
            }

            // Prepare for next test.
            left -= 0.1;
            right += 0.3;
        }
    }
    @Test
    public void testSolutionBelowSide() {
        UnivariateFunction f = new Sin();
        UnivariateSolver solver = getSolver();
        double left = -1.5;
        double right = 0.05;
        for(int i = 0; i < 10; i++) {
            // Test whether the allowed solutions are taken into account.
            double solution = getSolution(solver, 100, f, left, right, AllowedSolution.BELOW_SIDE);
            if (!Double.isNaN(solution)) {
                Assert.assertTrue(f.value(solution) <= 0.0);
            }

            // Prepare for next test.
            left -= 0.1;
            right += 0.3;
        }
    }

    @Test
    public void testSolutionAboveSide() {
        UnivariateFunction f = new Sin();
        UnivariateSolver solver = getSolver();
        double left = -1.5;
        double right = 0.05;
        for(int i = 0; i < 10; i++) {
            // Test whether the allowed solutions are taken into account.
            double solution = getSolution(solver, 100, f, left, right, AllowedSolution.ABOVE_SIDE);
            if (!Double.isNaN(solution)) {
                Assert.assertTrue(f.value(solution) >= 0.0);
            }

            // Prepare for next test.
            left -= 0.1;
            right += 0.3;
        }
    }

    private double getSolution(UnivariateSolver solver, int maxEval, UnivariateFunction f,
                               double left, double right, AllowedSolution allowedSolution) {
        try {
            @SuppressWarnings("unchecked")
            BracketedUnivariateSolver<UnivariateFunction> bracketing =
            (BracketedUnivariateSolver<UnivariateFunction>) solver;
            return bracketing.solve(100, f, left, right, allowedSolution);
        } catch (ClassCastException cce) {
            double baseRoot = solver.solve(maxEval, f, left, right);
            if ((baseRoot <= left) || (baseRoot >= right)) {
                // the solution slipped out of interval
                return Double.NaN;
            }
            PegasusSolver bracketing =
                    new PegasusSolver(solver.getRelativeAccuracy(), solver.getAbsoluteAccuracy(),
                                      solver.getFunctionValueAccuracy());
            return UnivariateSolverUtils.forceSide(maxEval - solver.getEvaluations(),
                                                       f, bracketing, baseRoot, left, right,
                                                       allowedSolution);
        }
    }

}
TOP

Related Classes of org.apache.commons.math3.analysis.solvers.BaseSecantSolverAbstractTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.