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    *      http://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  package org.apache.commons.math4.legacy.analysis.solvers;
19  
20  import org.apache.commons.math4.legacy.analysis.RealFieldUnivariateFunction;
21  import org.apache.commons.math4.legacy.core.dfp.Dfp;
22  import org.apache.commons.math4.legacy.core.dfp.DfpField;
23  import org.apache.commons.math4.legacy.core.dfp.DfpMath;
24  import org.apache.commons.math4.legacy.exception.MathInternalError;
25  import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
26  import org.junit.Assert;
27  import org.junit.Before;
28  import org.junit.Test;
29  
30  /**
31   * Test case for {@link FieldBracketingNthOrderBrentSolver bracketing n<sup>th</sup> order Brent} solver.
32   *
33   */
34  public final class FieldBracketingNthOrderBrentSolverTest {
35  
36      @Test(expected=NumberIsTooSmallException.class)
37      public void testInsufficientOrder3() {
38          new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy,
39                                                      functionValueAccuracy, 1);
40      }
41  
42      @Test
43      public void testConstructorOK() {
44          FieldBracketingNthOrderBrentSolver<Dfp> solver =
45                  new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy,
46                                                              functionValueAccuracy, 2);
47          Assert.assertEquals(2, solver.getMaximalOrder());
48      }
49  
50      @Test
51      public void testConvergenceOnFunctionAccuracy() {
52          FieldBracketingNthOrderBrentSolver<Dfp> solver =
53                  new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy,
54                                                              field.newDfp(1.0e-20), 20);
55          RealFieldUnivariateFunction<Dfp> f = new RealFieldUnivariateFunction<Dfp>() {
56              @Override
57              public Dfp value(Dfp x) {
58                  Dfp one     = field.getOne();
59                  Dfp oneHalf = one.divide(2);
60                  Dfp xMo     = x.subtract(one);
61                  Dfp xMh     = x.subtract(oneHalf);
62                  Dfp xPh     = x.add(oneHalf);
63                  Dfp xPo     = x.add(one);
64                  return xMo.multiply(xMh).multiply(x).multiply(xPh).multiply(xPo);
65              }
66          };
67  
68          Dfp result = solver.solve(20, f, field.newDfp(0.2), field.newDfp(0.9),
69                                    field.newDfp(0.4), AllowedSolution.BELOW_SIDE);
70          Assert.assertTrue(f.value(result).abs().lessThan(solver.getFunctionValueAccuracy()));
71          Assert.assertTrue(f.value(result).negativeOrNull());
72          Assert.assertTrue(result.subtract(field.newDfp(0.5)).subtract(solver.getAbsoluteAccuracy()).positiveOrNull());
73          result = solver.solve(20, f, field.newDfp(-0.9), field.newDfp(-0.2),
74                                field.newDfp(-0.4), AllowedSolution.ABOVE_SIDE);
75          Assert.assertTrue(f.value(result).abs().lessThan(solver.getFunctionValueAccuracy()));
76          Assert.assertTrue(f.value(result).positiveOrNull());
77          Assert.assertTrue(result.add(field.newDfp(0.5)).subtract(solver.getAbsoluteAccuracy()).negativeOrNull());
78      }
79  
80      @Test
81      public void testNeta() {
82  
83          // the following test functions come from Beny Neta's paper:
84          // "Several New Methods for solving Equations"
85          // intern J. Computer Math Vol 23 pp 265-282
86          // available here: http://www.math.nps.navy.mil/~bneta/SeveralNewMethods.PDF
87          for (AllowedSolution allowed : AllowedSolution.values()) {
88              check(new RealFieldUnivariateFunction<Dfp>() {
89                  @Override
90                  public Dfp value(Dfp x) {
91                      return DfpMath.sin(x).subtract(x.divide(2));
92                  }
93              }, 200, -2.0, 2.0, allowed);
94  
95              check(new RealFieldUnivariateFunction<Dfp>() {
96                  @Override
97                  public Dfp value(Dfp x) {
98                      return DfpMath.pow(x, 5).add(x).subtract(field.newDfp(10000));
99                  }
100             }, 200, -5.0, 10.0, allowed);
101 
102             check(new RealFieldUnivariateFunction<Dfp>() {
103                 @Override
104                 public Dfp value(Dfp x) {
105                     return x.sqrt().subtract(field.getOne().divide(x)).subtract(field.newDfp(3));
106                 }
107             }, 200, 0.001, 10.0, allowed);
108 
109             check(new RealFieldUnivariateFunction<Dfp>() {
110                 @Override
111                 public Dfp value(Dfp x) {
112                     return DfpMath.exp(x).add(x).subtract(field.newDfp(20));
113                 }
114             }, 200, -5.0, 5.0, allowed);
115 
116             check(new RealFieldUnivariateFunction<Dfp>() {
117                 @Override
118                 public Dfp value(Dfp x) {
119                     return DfpMath.log(x).add(x.sqrt()).subtract(field.newDfp(5));
120                 }
121             }, 200, 0.001, 10.0, allowed);
122 
123             check(new RealFieldUnivariateFunction<Dfp>() {
124                 @Override
125                 public Dfp value(Dfp x) {
126                     return x.subtract(field.getOne()).multiply(x).multiply(x).subtract(field.getOne());
127                 }
128             }, 200, -0.5, 1.5, allowed);
129         }
130     }
131 
132     private void check(RealFieldUnivariateFunction<Dfp> f, int maxEval, double min, double max,
133                        AllowedSolution allowedSolution) {
134         FieldBracketingNthOrderBrentSolver<Dfp> solver =
135                 new FieldBracketingNthOrderBrentSolver<>(relativeAccuracy, absoluteAccuracy,
136                                                      functionValueAccuracy, 20);
137         Dfp xResult = solver.solve(maxEval, f, field.newDfp(min), field.newDfp(max),
138                                    allowedSolution);
139         Dfp yResult = f.value(xResult);
140         boolean increasing;
141         switch (allowedSolution) {
142         case ANY_SIDE :
143             Assert.assertTrue(yResult.abs().lessThan(functionValueAccuracy.multiply(2)));
144             break;
145         case LEFT_SIDE :
146             increasing = f.value(xResult).add(absoluteAccuracy).greaterThan(yResult);
147             Assert.assertTrue(increasing ? yResult.negativeOrNull() : yResult.positiveOrNull());
148             break;
149         case RIGHT_SIDE :
150             increasing = f.value(xResult).add(absoluteAccuracy).greaterThan(yResult);
151             Assert.assertTrue(increasing ? yResult.positiveOrNull() : yResult.negativeOrNull());
152             break;
153         case BELOW_SIDE :
154             Assert.assertTrue(yResult.negativeOrNull());
155             break;
156         case ABOVE_SIDE :
157             Assert.assertTrue(yResult.positiveOrNull());
158             break;
159         default :
160             // this should never happen
161             throw new MathInternalError(null);
162         }
163     }
164 
165     @Before
166     public void setUp() {
167         field                 = new DfpField(50);
168         absoluteAccuracy      = field.newDfp(1.0e-45);
169         relativeAccuracy      = field.newDfp(1.0e-45);
170         functionValueAccuracy = field.newDfp(1.0e-45);
171     }
172 
173     private DfpField field;
174     private Dfp      absoluteAccuracy;
175     private Dfp      relativeAccuracy;
176     private Dfp      functionValueAccuracy;
177 }