/* * 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.math4.analysis.solvers; import org.apache.commons.math4.analysis.RealFieldUnivariateFunction; import org.apache.commons.math4.analysis.solvers.AllowedSolution; import org.apache.commons.math4.dfp.Dfp; import org.apache.commons.math4.dfp.DfpField; import org.apache.commons.math4.dfp.DfpMath; import org.apache.commons.math4.exception.MathInternalError; import org.apache.commons.math4.exception.NumberIsTooSmallException; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Test case for {@link FieldBracketingNthOrderBrentSolver bracketing n<sup>th</sup> order Brent} solver. * */ public final class FieldBracketingNthOrderBrentSolverTest { @Test(expected=NumberIsTooSmallException.class) public void testInsufficientOrder3() { new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy, functionValueAccuracy, 1); } @Test public void testConstructorOK() { FieldBracketingNthOrderBrentSolver<Dfp> solver = new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy, functionValueAccuracy, 2); Assert.assertEquals(2, solver.getMaximalOrder()); } @Test public void testConvergenceOnFunctionAccuracy() { FieldBracketingNthOrderBrentSolver<Dfp> solver = new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy, field.newDfp(1.0e-20), 20); RealFieldUnivariateFunction<Dfp> f = new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { Dfp one = field.getOne(); Dfp oneHalf = one.divide(2); Dfp xMo = x.subtract(one); Dfp xMh = x.subtract(oneHalf); Dfp xPh = x.add(oneHalf); Dfp xPo = x.add(one); return xMo.multiply(xMh).multiply(x).multiply(xPh).multiply(xPo); } }; Dfp result = solver.solve(20, f, field.newDfp(0.2), field.newDfp(0.9), field.newDfp(0.4), AllowedSolution.BELOW_SIDE); Assert.assertTrue(f.value(result).abs().lessThan(solver.getFunctionValueAccuracy())); Assert.assertTrue(f.value(result).negativeOrNull()); Assert.assertTrue(result.subtract(field.newDfp(0.5)).subtract(solver.getAbsoluteAccuracy()).positiveOrNull()); result = solver.solve(20, f, field.newDfp(-0.9), field.newDfp(-0.2), field.newDfp(-0.4), AllowedSolution.ABOVE_SIDE); Assert.assertTrue(f.value(result).abs().lessThan(solver.getFunctionValueAccuracy())); Assert.assertTrue(f.value(result).positiveOrNull()); Assert.assertTrue(result.add(field.newDfp(0.5)).subtract(solver.getAbsoluteAccuracy()).negativeOrNull()); } @Test public void testNeta() { // the following test functions come from Beny Neta's paper: // "Several New Methods for solving Equations" // intern J. Computer Math Vol 23 pp 265-282 // available here: http://www.math.nps.navy.mil/~bneta/SeveralNewMethods.PDF for (AllowedSolution allowed : AllowedSolution.values()) { check(new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { return DfpMath.sin(x).subtract(x.divide(2)); } }, 200, -2.0, 2.0, allowed); check(new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { return DfpMath.pow(x, 5).add(x).subtract(field.newDfp(10000)); } }, 200, -5.0, 10.0, allowed); check(new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { return x.sqrt().subtract(field.getOne().divide(x)).subtract(field.newDfp(3)); } }, 200, 0.001, 10.0, allowed); check(new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { return DfpMath.exp(x).add(x).subtract(field.newDfp(20)); } }, 200, -5.0, 5.0, allowed); check(new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { return DfpMath.log(x).add(x.sqrt()).subtract(field.newDfp(5)); } }, 200, 0.001, 10.0, allowed); check(new RealFieldUnivariateFunction<Dfp>() { @Override public Dfp value(Dfp x) { return x.subtract(field.getOne()).multiply(x).multiply(x).subtract(field.getOne()); } }, 200, -0.5, 1.5, allowed); } } private void check(RealFieldUnivariateFunction<Dfp> f, int maxEval, double min, double max, AllowedSolution allowedSolution) { FieldBracketingNthOrderBrentSolver<Dfp> solver = new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy, functionValueAccuracy, 20); Dfp xResult = solver.solve(maxEval, f, field.newDfp(min), field.newDfp(max), allowedSolution); Dfp yResult = f.value(xResult); switch (allowedSolution) { case ANY_SIDE : Assert.assertTrue(yResult.abs().lessThan(functionValueAccuracy.multiply(2))); break; case LEFT_SIDE : { boolean increasing = f.value(xResult).add(absoluteAccuracy).greaterThan(yResult); Assert.assertTrue(increasing ? yResult.negativeOrNull() : yResult.positiveOrNull()); break; } case RIGHT_SIDE : { boolean increasing = f.value(xResult).add(absoluteAccuracy).greaterThan(yResult); Assert.assertTrue(increasing ? yResult.positiveOrNull() : yResult.negativeOrNull()); break; } case BELOW_SIDE : Assert.assertTrue(yResult.negativeOrNull()); break; case ABOVE_SIDE : Assert.assertTrue(yResult.positiveOrNull()); break; default : // this should never happen throw new MathInternalError(null); } } @Before public void setUp() { field = new DfpField(50); absoluteAccuracy = field.newDfp(1.0e-45); relativeAccuracy = field.newDfp(1.0e-45); functionValueAccuracy = field.newDfp(1.0e-45); } private DfpField field; private Dfp absoluteAccuracy; private Dfp relativeAccuracy; private Dfp functionValueAccuracy; }