View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.analysis.solvers;
24  
25  import org.hipparchus.CalculusFieldElement;
26  import org.hipparchus.analysis.FieldUnivariateFunction;
27  import org.hipparchus.analysis.CalculusFieldUnivariateFunction;
28  import org.hipparchus.dfp.Dfp;
29  import org.hipparchus.dfp.DfpField;
30  import org.hipparchus.dfp.DfpMath;
31  import org.hipparchus.exception.MathIllegalArgumentException;
32  import org.hipparchus.exception.MathRuntimeException;
33  import org.hipparchus.util.FastMath;
34  import org.junit.Assert;
35  import org.junit.Before;
36  import org.junit.Test;
37  
38  /**
39   * Test case for {@link FieldBracketingNthOrderBrentSolver bracketing n<sup>th</sup> order Brent} solver.
40   *
41   */
42  public final class FieldBracketingNthOrderBrentSolverTest {
43  
44      @Test(expected=MathIllegalArgumentException.class)
45      public void testInsufficientOrder3() {
46          new FieldBracketingNthOrderBrentSolver<Dfp>(relativeAccuracy, absoluteAccuracy,
47                                                      functionValueAccuracy, 1);
48      }
49  
50      @Test
51      public void testConstructorOK() {
52          FieldBracketingNthOrderBrentSolver<Dfp> solver =
53                  new FieldBracketingNthOrderBrentSolver<Dfp>(relativeAccuracy, absoluteAccuracy,
54                                                              functionValueAccuracy, 2);
55          Assert.assertEquals(2, solver.getMaximalOrder());
56      }
57  
58      @Test
59      public void testConvergenceOnFunctionAccuracy() {
60          FieldBracketingNthOrderBrentSolver<Dfp> solver =
61                  new FieldBracketingNthOrderBrentSolver<Dfp>(relativeAccuracy, absoluteAccuracy,
62                                                              field.newDfp(1.0e-20), 20);
63          FieldUnivariateFunction f = new FieldUnivariateFunction() {
64              public <T extends CalculusFieldElement<T>> T value(T x) {
65                  T one     = x.getField().getOne();
66                  T oneHalf = one.divide(2);
67                  T xMo     = x.subtract(one);
68                  T xMh     = x.subtract(oneHalf);
69                  T xPh     = x.add(oneHalf);
70                  T xPo     = x.add(one);
71                  return xMo.multiply(xMh).multiply(x).multiply(xPh).multiply(xPo);
72              }
73          };
74  
75          Dfp result = solver.solve(20, f.toCalculusFieldUnivariateFunction(field), field.newDfp(0.2), field.newDfp(0.9),
76                                    field.newDfp(0.4), AllowedSolution.BELOW_SIDE);
77          Assert.assertTrue(f.value(result).abs().lessThan(solver.getFunctionValueAccuracy()));
78          Assert.assertTrue(f.value(result).negativeOrNull());
79          Assert.assertTrue(result.subtract(field.newDfp(0.5)).subtract(solver.getAbsoluteAccuracy()).positiveOrNull());
80          result = solver.solve(20, f.toCalculusFieldUnivariateFunction(field), field.newDfp(-0.9), field.newDfp(-0.2),
81                                field.newDfp(-0.4), AllowedSolution.ABOVE_SIDE);
82          Assert.assertTrue(f.value(result).abs().lessThan(solver.getFunctionValueAccuracy()));
83          Assert.assertTrue(f.value(result).positiveOrNull());
84          Assert.assertTrue(result.add(field.newDfp(0.5)).subtract(solver.getAbsoluteAccuracy()).negativeOrNull());
85      }
86  
87      @Test
88      public void testToleranceLessThanUlp() {
89          // function that is never zero
90          Dfp zero = field.getZero();
91          Dfp one = field.getOne();
92          CalculusFieldUnivariateFunction<Dfp> f = (x) -> x.getReal() <= 2.1 ? one.negate(): one;
93          // tolerance less than 1 ulp(x)
94          FieldBracketingNthOrderBrentSolver<Dfp> solver =
95                  new FieldBracketingNthOrderBrentSolver<>(zero, field.newDfp(1e-55), zero, 5);
96  
97          // make sure it doesn't throw a maxIterations exception
98          Dfp result = solver.solve(200, f, zero, zero.add(5.0), AllowedSolution.LEFT_SIDE);
99          double difference = field.newDfp(2.1).subtract(result).abs().getReal();
100         Assert.assertTrue("difference: " + difference, difference < FastMath.ulp(2.1));
101     }
102 
103     @Test
104     public void testNeta() {
105 
106         // the following test functions come from Beny Neta's paper:
107         // "Several New Methods for solving Equations"
108         // intern J. Computer Math Vol 23 pp 265-282
109         // available here: http://www.math.nps.navy.mil/~bneta/SeveralNewMethods.PDF
110         for (AllowedSolution allowed : AllowedSolution.values()) {
111             check(new CalculusFieldUnivariateFunction<Dfp>() {
112                 public Dfp value(Dfp x) {
113                     return DfpMath.sin(x).subtract(x.divide(2));
114                 }
115             }, 200, -2.0, 2.0, allowed);
116 
117             check(new CalculusFieldUnivariateFunction<Dfp>() {
118                 public Dfp value(Dfp x) {
119                     return DfpMath.pow(x, 5).add(x).subtract(field.newDfp(10000));
120                 }
121             }, 200, -5.0, 10.0, allowed);
122 
123             check(new CalculusFieldUnivariateFunction<Dfp>() {
124                 public Dfp value(Dfp x) {
125                     return x.sqrt().subtract(field.getOne().divide(x)).subtract(field.newDfp(3));
126                 }
127             }, 200, 0.001, 10.0, allowed);
128 
129             check(new CalculusFieldUnivariateFunction<Dfp>() {
130                 public Dfp value(Dfp x) {
131                     return DfpMath.exp(x).add(x).subtract(field.newDfp(20));
132                 }
133             }, 200, -5.0, 5.0, allowed);
134 
135             check(new CalculusFieldUnivariateFunction<Dfp>() {
136                 public Dfp value(Dfp x) {
137                     return DfpMath.log(x).add(x.sqrt()).subtract(field.newDfp(5));
138                 }
139             }, 200, 0.001, 10.0, allowed);
140 
141             check(new CalculusFieldUnivariateFunction<Dfp>() {
142                 public Dfp value(Dfp x) {
143                     return x.subtract(field.getOne()).multiply(x).multiply(x).subtract(field.getOne());
144                 }
145             }, 200, -0.5, 1.5, allowed);
146         }
147 
148     }
149 
150     private void check(CalculusFieldUnivariateFunction<Dfp> f, int maxEval, double min, double max,
151                        AllowedSolution allowedSolution) {
152         FieldBracketingNthOrderBrentSolver<Dfp> solver =
153                 new FieldBracketingNthOrderBrentSolver<Dfp>(relativeAccuracy, absoluteAccuracy,
154                                                      functionValueAccuracy, 20);
155         Dfp xResult = solver.solve(maxEval, f, field.newDfp(min), field.newDfp(max),
156                                    allowedSolution);
157         Dfp yResult = f.value(xResult);
158         switch (allowedSolution) {
159         case ANY_SIDE :
160             Assert.assertTrue(yResult.abs().lessThan(functionValueAccuracy.multiply(2)));
161             break;
162         case LEFT_SIDE : {
163             boolean increasing = f.value(xResult).add(absoluteAccuracy).greaterThan(yResult);
164             Assert.assertTrue(increasing ? yResult.negativeOrNull() : yResult.positiveOrNull());
165             break;
166         }
167         case RIGHT_SIDE : {
168             boolean increasing = f.value(xResult).add(absoluteAccuracy).greaterThan(yResult);
169             Assert.assertTrue(increasing ? yResult.positiveOrNull() : yResult.negativeOrNull());
170             break;
171         }
172         case BELOW_SIDE :
173             Assert.assertTrue(yResult.negativeOrNull());
174             break;
175         case ABOVE_SIDE :
176             Assert.assertTrue(yResult.positiveOrNull());
177             break;
178         default :
179             // this should never happen
180             throw new MathRuntimeException(null);
181         }
182     }
183 
184     @Before
185     public void setUp() {
186         field                 = new DfpField(50);
187         absoluteAccuracy      = field.newDfp(1.0e-45);
188         relativeAccuracy      = field.newDfp(1.0e-45);
189         functionValueAccuracy = field.newDfp(1.0e-45);
190     }
191 
192     private DfpField field;
193     private Dfp      absoluteAccuracy;
194     private Dfp      relativeAccuracy;
195     private Dfp      functionValueAccuracy;
196 
197 }