1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.hipparchus.analysis.solvers;
24
25 import org.hipparchus.analysis.QuinticFunction;
26 import org.hipparchus.analysis.UnivariateFunction;
27 import org.hipparchus.analysis.differentiation.DSFactory;
28 import org.hipparchus.analysis.differentiation.Derivative;
29 import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction;
30 import org.hipparchus.exception.MathIllegalArgumentException;
31 import org.hipparchus.exception.MathIllegalStateException;
32 import org.hipparchus.util.FastMath;
33 import org.junit.jupiter.api.Test;
34
35 import java.util.ArrayList;
36 import java.util.List;
37
38 import static org.junit.jupiter.api.Assertions.assertEquals;
39 import static org.junit.jupiter.api.Assertions.assertThrows;
40 import static org.junit.jupiter.api.Assertions.assertTrue;
41
42
43
44
45
46
47 final class BracketingNthOrderBrentSolverTest extends BaseSecantSolverAbstractTest {
48
49
50 @Override
51 protected UnivariateSolver getSolver() {
52 return new BracketingNthOrderBrentSolver();
53 }
54
55
56 @Override
57 protected int[] getQuinticEvalCounts() {
58 return new int[] { 1, 3, 8, 1, 9, 4, 8, 1, 12, 1, 16 };
59 }
60
61 @Test
62 void testInsufficientOrder1() {
63 assertThrows(MathIllegalArgumentException.class, () -> {
64
65 new BracketingNthOrderBrentSolver(1.0e-10, 1);
66 });
67 }
68
69 @Test
70 void testInsufficientOrder2() {
71 assertThrows(MathIllegalArgumentException.class, () -> {
72 new BracketingNthOrderBrentSolver(1.0e-10, 1.0e-10, 1);
73 });
74 }
75
76 @Test
77 void testInsufficientOrder3() {
78 assertThrows(MathIllegalArgumentException.class, () -> {
79 new BracketingNthOrderBrentSolver(1.0e-10, 1.0e-10, 1.0e-10, 1);
80 });
81 }
82
83 @Test
84 void testConstructorsOK() {
85 assertEquals(2, new BracketingNthOrderBrentSolver(1.0e-10,
86 2).getMaximalOrder());
87 assertEquals(2, new BracketingNthOrderBrentSolver(1.0e-10,
88 1.0e-10,
89 2).getMaximalOrder());
90 assertEquals(2, new BracketingNthOrderBrentSolver(1.0e-10,
91 1.0e-10,
92 1.0e-10,
93 2).getMaximalOrder());
94 }
95
96 @Test
97 void testConvergenceOnFunctionAccuracy() {
98 BracketingNthOrderBrentSolver solver = new BracketingNthOrderBrentSolver(
99 1.0e-12, 1.0e-10, 0.001, 3);
100 QuinticFunction f = new QuinticFunction();
101 double result = solver.solve(20, f, 0.2, 0.9, 0.4,
102 AllowedSolution.BELOW_SIDE);
103 assertEquals(0, f.value(result),
104 solver.getFunctionValueAccuracy());
105 assertTrue(f.value(result) <= 0);
106 assertTrue(result - 0.5 > solver.getAbsoluteAccuracy());
107 result = solver.solve(20, f, -0.9, -0.2, -0.4,
108 AllowedSolution.ABOVE_SIDE);
109 assertEquals(0, f.value(result),
110 solver.getFunctionValueAccuracy());
111 assertTrue(f.value(result) >= 0);
112 assertTrue(result + 0.5 < -solver.getAbsoluteAccuracy());
113 }
114
115 @Test
116 void testIssue716() {
117 BracketingNthOrderBrentSolver solver = new BracketingNthOrderBrentSolver(
118 1.0e-12, 1.0e-10, 1.0e-22, 5);
119 UnivariateFunction sharpTurn = new UnivariateFunction() {
120
121 public double value(double x) {
122 return (2 * x + 1) / (1.0e9 * (x + 1));
123 }
124 };
125 double result = solver.solve(100, sharpTurn, -0.9999999, 30, 15,
126 AllowedSolution.RIGHT_SIDE);
127 assertEquals(0, sharpTurn.value(result),
128 solver.getFunctionValueAccuracy());
129 assertTrue(sharpTurn.value(result) >= 0);
130 assertEquals(-0.5, result, 1.0e-10);
131 }
132
133 @Test
134 void testToleranceLessThanUlp() {
135
136 UnivariateFunction f = (x) -> x < 2.1 ? -1 : 1;
137
138 UnivariateSolver solver = new BracketingNthOrderBrentSolver(0, 1e-18, 0,
139 5);
140
141
142 double result = solver.solve(100, f, 0.0, 5.0);
143 assertEquals(2.1, result, 0.0);
144 }
145
146 @Test
147 void testFasterThanNewton() {
148
149
150
151
152
153
154 compare(new TestFunction(0.0, -2, 2) {
155
156 @Override
157 public <T extends Derivative<T>> T value(T x) {
158 return x.sin().subtract(x.multiply(0.5));
159 }
160 });
161 compare(new TestFunction(6.3087771299726890947, -5, 10) {
162
163 @Override
164 public <T extends Derivative<T>> T value(T x) {
165 return x.pow(5).add(x).subtract(10000);
166 }
167 });
168 compare(new TestFunction(9.6335955628326951924, 0.001, 10) {
169
170 @Override
171 public <T extends Derivative<T>> T value(T x) {
172 return x.sqrt().subtract(x.reciprocal()).subtract(3);
173 }
174 });
175 compare(new TestFunction(2.8424389537844470678, -5, 5) {
176
177 @Override
178 public <T extends Derivative<T>> T value(T x) {
179 return x.exp().add(x).subtract(20);
180 }
181 });
182 compare(new TestFunction(8.3094326942315717953, 0.001, 10) {
183
184 @Override
185 public <T extends Derivative<T>> T value(T x) {
186 return x.log().add(x.sqrt()).subtract(5);
187 }
188 });
189 compare(new TestFunction(1.4655712318767680266, -0.5, 1.5) {
190
191 @Override
192 public <T extends Derivative<T>> T value(T x) {
193 return x.subtract(1).multiply(x).multiply(x).subtract(1);
194 }
195 });
196
197 }
198
199 @Test
200 void testSolverStopIteratingOnceSolutionIsFound() {
201 final double absoluteAccuracy = 0.1;
202 final double valueAccuracy = 1.;
203 BracketingNthOrderBrentSolver solver = new BracketingNthOrderBrentSolver(
204 1e-14, absoluteAccuracy, valueAccuracy, 5);
205 FunctionHipparcus function = new FunctionHipparcus();
206 solver.solve(100, function, -100, 100);
207 assertEquals(1, function.values.stream()
208 .filter(value -> FastMath.abs(value) < valueAccuracy)
209 .count());
210 assertEquals(7, function.values.size());
211 }
212
213 private static class FunctionHipparcus implements UnivariateFunction {
214
215 List<Double> values = new ArrayList<>();
216
217 @Override
218 public double value(double x) {
219 double value = -0.01 * x * x + 20;
220 values.add(value);
221 return value;
222 }
223 }
224
225 private void compare(TestFunction f) {
226 compare(f, f.getRoot(), f.getMin(), f.getMax());
227 }
228
229 private void compare(final UnivariateDifferentiableFunction f, double root,
230 double min, double max) {
231 NewtonRaphsonSolver newton = new NewtonRaphsonSolver(1.0e-12);
232 BracketingNthOrderBrentSolver bracketing = new BracketingNthOrderBrentSolver(
233 1.0e-12, 1.0e-12, 1.0e-18, 5);
234 double resultN;
235 try {
236 resultN = newton.solve(100, f, min, max);
237 } catch (MathIllegalStateException tmee) {
238 resultN = Double.NaN;
239 }
240 double resultB;
241 try {
242 resultB = bracketing.solve(100, f, min, max);
243 } catch (MathIllegalStateException tmee) {
244 resultB = Double.NaN;
245 }
246 assertEquals(root, resultN, newton.getAbsoluteAccuracy());
247 assertEquals(root, resultB,
248 bracketing.getAbsoluteAccuracy());
249
250
251 final int weightedBracketingEvaluations = bracketing.getEvaluations();
252
253
254 final int weightedNewtonEvaluations = 2 * newton.getEvaluations();
255
256 assertTrue(
257 weightedBracketingEvaluations < weightedNewtonEvaluations);
258
259 }
260
261 private static abstract class TestFunction implements UnivariateDifferentiableFunction {
262
263 private final double root;
264
265 private final double min;
266
267 private final double max;
268
269 protected TestFunction(final double root, final double min,
270 final double max) {
271 this.root = root;
272 this.min = min;
273 this.max = max;
274 }
275
276 public double getRoot() {
277 return root;
278 }
279
280 public double getMin() {
281 return min;
282 }
283
284 public double getMax() {
285 return max;
286 }
287
288 public double value(final double x) {
289 return value(new DSFactory(0, 0).constant(x)).getValue();
290 }
291
292 public abstract <T extends Derivative<T>> T value(final T t);
293
294 }
295
296 }