1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
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  
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          
84          
85          
86          
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             
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 }