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.analysis.QuinticFunction;
26  import org.hipparchus.analysis.CalculusFieldUnivariateFunction;
27  import org.hipparchus.analysis.UnivariateFunction;
28  import org.hipparchus.analysis.function.Sin;
29  import org.hipparchus.exception.MathIllegalArgumentException;
30  import org.hipparchus.exception.NullArgumentException;
31  import org.hipparchus.util.Binary64;
32  import org.hipparchus.util.FastMath;
33  import org.junit.Assert;
34  import org.junit.Test;
35  
36  /**
37   */
38  public class UnivariateSolverUtilsTest {
39  
40      private UnivariateFunction sin = new Sin();
41      private CalculusFieldUnivariateFunction<Binary64> fieldSin = x -> x.sin();
42  
43      @Test(expected=NullArgumentException.class)
44      public void testSolveNull() {
45          UnivariateSolverUtils.solve(null, 0.0, 4.0);
46      }
47  
48      @Test(expected=MathIllegalArgumentException.class)
49      public void testSolveBadEndpoints() {
50          double root = UnivariateSolverUtils.solve(sin, 4.0, -0.1, 1e-6);
51          System.out.println("root=" + root);
52      }
53  
54      @Test
55      public void testSolveBadAccuracy() {
56          try { // bad accuracy
57              UnivariateSolverUtils.solve(sin, 0.0, 4.0, 0.0);
58  //             Assert.fail("Expecting MathIllegalArgumentException"); // TODO needs rework since convergence behaviour was changed
59          } catch (MathIllegalArgumentException ex) {
60              // expected
61          }
62      }
63  
64      @Test
65      public void testSolveSin() {
66          double x = UnivariateSolverUtils.solve(sin, 1.0, 4.0);
67          Assert.assertEquals(FastMath.PI, x, 1.0e-4);
68      }
69  
70      @Test(expected=NullArgumentException.class)
71      public void testSolveAccuracyNull()  {
72          double accuracy = 1.0e-6;
73          UnivariateSolverUtils.solve(null, 0.0, 4.0, accuracy);
74      }
75  
76      @Test
77      public void testSolveAccuracySin() {
78          double accuracy = 1.0e-6;
79          double x = UnivariateSolverUtils.solve(sin, 1.0,
80                  4.0, accuracy);
81          Assert.assertEquals(FastMath.PI, x, accuracy);
82      }
83  
84      @Test(expected=MathIllegalArgumentException.class)
85      public void testSolveNoRoot() {
86          UnivariateSolverUtils.solve(sin, 1.0, 1.5);
87      }
88  
89      @Test
90      public void testBracketSin() {
91          double[] result = UnivariateSolverUtils.bracket(sin,
92                  0.0, -2.0, 2.0);
93          Assert.assertTrue(sin.value(result[0]) < 0);
94          Assert.assertTrue(sin.value(result[1]) > 0);
95      }
96  
97      @Test
98      public void testBracketCentered() {
99          double initial = 0.1;
100         double[] result = UnivariateSolverUtils.bracket(sin, initial, -2.0, 2.0, 0.2, 1.0, 100);
101         Assert.assertTrue(result[0] < initial);
102         Assert.assertTrue(result[1] > initial);
103         Assert.assertTrue(sin.value(result[0]) < 0);
104         Assert.assertTrue(sin.value(result[1]) > 0);
105     }
106 
107     @Test
108     public void testBracketLow() {
109         double initial = 0.5;
110         double[] result = UnivariateSolverUtils.bracket(sin, initial, -2.0, 2.0, 0.2, 1.0, 100);
111         Assert.assertTrue(result[0] < initial);
112         Assert.assertTrue(result[1] < initial);
113         Assert.assertTrue(sin.value(result[0]) < 0);
114         Assert.assertTrue(sin.value(result[1]) > 0);
115     }
116 
117     @Test
118     public void testBracketHigh(){
119         double initial = -0.5;
120         double[] result = UnivariateSolverUtils.bracket(sin, initial, -2.0, 2.0, 0.2, 1.0, 100);
121         Assert.assertTrue(result[0] > initial);
122         Assert.assertTrue(result[1] > initial);
123         Assert.assertTrue(sin.value(result[0]) < 0);
124         Assert.assertTrue(sin.value(result[1]) > 0);
125     }
126 
127     @Test(expected=MathIllegalArgumentException.class)
128     public void testBracketLinear(){
129         UnivariateSolverUtils.bracket(new UnivariateFunction() {
130             public double value(double x) {
131                 return 1 - x;
132             }
133         }, 1000, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 100);
134     }
135 
136     @Test
137     public void testBracketExponential(){
138         double[] result = UnivariateSolverUtils.bracket(new UnivariateFunction() {
139             public double value(double x) {
140                 return 1 - x;
141             }
142         }, 1000, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0, 2.0, 10);
143         Assert.assertTrue(result[0] <= 1);
144         Assert.assertTrue(result[1] >= 1);
145     }
146 
147     @Test
148     public void testBracketEndpointRoot() {
149         double[] result = UnivariateSolverUtils.bracket(sin, 1.5, 0, 2.0, 100);
150         Assert.assertEquals(0.0, sin.value(result[0]), 1.0e-15);
151         Assert.assertTrue(sin.value(result[1]) > 0);
152     }
153 
154     @Test(expected=NullArgumentException.class)
155     public void testNullFunction() {
156         UnivariateSolverUtils.bracket(null, 1.5, 0, 2.0);
157     }
158 
159     @Test(expected=MathIllegalArgumentException.class)
160     public void testBadInitial() {
161         UnivariateSolverUtils.bracket(sin, 2.5, 0, 2.0);
162     }
163 
164     @Test(expected=MathIllegalArgumentException.class)
165     public void testBadAdditive() {
166         UnivariateSolverUtils.bracket(sin, 1.0, -2.0, 3.0, -1.0, 1.0, 100);
167     }
168 
169     @Test(expected=MathIllegalArgumentException.class)
170     public void testIterationExceeded() {
171         UnivariateSolverUtils.bracket(sin, 1.0, -2.0, 3.0, 1.0e-5, 1.0, 100);
172     }
173 
174     @Test(expected=MathIllegalArgumentException.class)
175     public void testBadEndpoints() {
176         // endpoints not valid
177         UnivariateSolverUtils.bracket(sin, 1.5, 2.0, 1.0);
178     }
179 
180     @Test(expected=MathIllegalArgumentException.class)
181     public void testBadMaximumIterations() {
182         // bad maximum iterations
183         UnivariateSolverUtils.bracket(sin, 1.5, 0, 2.0, 0);
184     }
185 
186     @Test
187     public void testFieldBracketSin() {
188         Binary64[] result = UnivariateSolverUtils.bracket(fieldSin,new Binary64(0.0),
189                                                            new Binary64(-2.0),new Binary64(2.0));
190         Assert.assertTrue(fieldSin.value(result[0]).getReal() < 0);
191         Assert.assertTrue(fieldSin.value(result[1]).getReal() > 0);
192     }
193 
194     @Test
195     public void testFieldBracketCentered() {
196         Binary64 initial = new Binary64(0.1);
197         Binary64[] result = UnivariateSolverUtils.bracket(fieldSin, initial,
198                                                            new Binary64(-2.0), new Binary64(2.0),
199                                                            new Binary64(0.2), new Binary64(1.0),
200                                                            100);
201         Assert.assertTrue(result[0].getReal() < initial.getReal());
202         Assert.assertTrue(result[1].getReal() > initial.getReal());
203         Assert.assertTrue(fieldSin.value(result[0]).getReal() < 0);
204         Assert.assertTrue(fieldSin.value(result[1]).getReal() > 0);
205     }
206 
207     @Test
208     public void testFieldBracketLow() {
209         Binary64 initial = new Binary64(0.5);
210         Binary64[] result = UnivariateSolverUtils.bracket(fieldSin, initial,
211                                                            new Binary64(-2.0), new Binary64(2.0),
212                                                            new Binary64(0.2), new Binary64(1.0),
213                                                            100);
214         Assert.assertTrue(result[0].getReal() < initial.getReal());
215         Assert.assertTrue(result[1].getReal() < initial.getReal());
216         Assert.assertTrue(fieldSin.value(result[0]).getReal() < 0);
217         Assert.assertTrue(fieldSin.value(result[1]).getReal() > 0);
218     }
219 
220     @Test
221     public void testFieldBracketHigh(){
222         Binary64 initial = new Binary64(-0.5);
223         Binary64[] result = UnivariateSolverUtils.bracket(fieldSin, initial,
224                                                            new Binary64(-2.0), new Binary64(2.0),
225                                                            new Binary64(0.2), new Binary64(1.0),
226                                                            100);
227         Assert.assertTrue(result[0].getReal() > initial.getReal());
228         Assert.assertTrue(result[1].getReal() > initial.getReal());
229         Assert.assertTrue(fieldSin.value(result[0]).getReal() < 0);
230         Assert.assertTrue(fieldSin.value(result[1]).getReal() > 0);
231     }
232 
233     @Test(expected=MathIllegalArgumentException.class)
234     public void testFieldBracketLinear(){
235         UnivariateSolverUtils.bracket(new CalculusFieldUnivariateFunction<Binary64>() {
236             public Binary64 value(Binary64 x) {
237                 return x.negate().add(1);
238             }
239         },
240         new Binary64(1000),
241         new Binary64(Double.NEGATIVE_INFINITY), new Binary64(Double.POSITIVE_INFINITY),
242         new Binary64(1.0), new Binary64(1.0), 100);
243     }
244 
245     @Test
246     public void testFieldBracketExponential(){
247         Binary64[] result = UnivariateSolverUtils.bracket(new CalculusFieldUnivariateFunction<Binary64>() {
248             public Binary64 value(Binary64 x) {
249                 return x.negate().add(1);
250             }
251         },
252         new Binary64(1000),
253         new Binary64(Double.NEGATIVE_INFINITY), new Binary64(Double.POSITIVE_INFINITY),
254         new Binary64(1.0), new Binary64(2.0), 10);
255         Assert.assertTrue(result[0].getReal() <= 1);
256         Assert.assertTrue(result[1].getReal() >= 1);
257     }
258 
259     @Test
260     public void testFieldBracketEndpointRoot() {
261         Binary64[] result = UnivariateSolverUtils.bracket(fieldSin,
262                                                            new Binary64(1.5), new Binary64(0),
263                                                            new Binary64(2.0), 100);
264         Assert.assertEquals(0.0, fieldSin.value(result[0]).getReal(), 1.0e-15);
265         Assert.assertTrue(fieldSin.value(result[1]).getReal() > 0);
266     }
267 
268     @Test(expected=NullArgumentException.class)
269     public void testFieldNullFunction() {
270         UnivariateSolverUtils.bracket(null, new Binary64(1.5), new Binary64(0), new Binary64(2.0));
271     }
272 
273     @Test(expected=MathIllegalArgumentException.class)
274     public void testFieldBadInitial() {
275         UnivariateSolverUtils.bracket(fieldSin, new Binary64(2.5), new Binary64(0), new Binary64(2.0));
276     }
277 
278     @Test(expected=MathIllegalArgumentException.class)
279     public void testFieldBadAdditive() {
280         UnivariateSolverUtils.bracket(fieldSin, new Binary64(1.0), new Binary64(-2.0), new Binary64(3.0),
281                                       new Binary64(-1.0), new Binary64(1.0), 100);
282     }
283 
284     @Test(expected=MathIllegalArgumentException.class)
285     public void testFieldIterationExceeded() {
286         UnivariateSolverUtils.bracket(fieldSin, new Binary64(1.0), new Binary64(-2.0), new Binary64(3.0),
287                                       new Binary64(1.0e-5), new Binary64(1.0), 100);
288     }
289 
290     @Test(expected=MathIllegalArgumentException.class)
291     public void testFieldBadEndpoints() {
292         // endpoints not valid
293         UnivariateSolverUtils.bracket(fieldSin, new Binary64(1.5), new Binary64(2.0), new Binary64(1.0));
294     }
295 
296     @Test(expected=MathIllegalArgumentException.class)
297     public void testFieldBadMaximumIterations() {
298         // bad maximum iterations
299         UnivariateSolverUtils.bracket(fieldSin, new Binary64(1.5), new Binary64(0), new Binary64(2.0), 0);
300     }
301 
302     /** check the search continues when a = lowerBound and b &lt; upperBound. */
303     @Test
304     public void testBracketLoopConditionForB() {
305         double[] result = UnivariateSolverUtils.bracket(sin, -0.9, -1, 1, 0.1, 1, 100);
306         Assert.assertTrue(result[0] <= 0);
307         Assert.assertTrue(result[1] >= 0);
308     }
309 
310     @Test
311     public void testMisc() {
312         UnivariateFunction f = new QuinticFunction();
313         double result;
314         // Static solve method
315         result = UnivariateSolverUtils.solve(f, -0.2, 0.2);
316         Assert.assertEquals(result, 0, 1E-8);
317         result = UnivariateSolverUtils.solve(f, -0.1, 0.3);
318         Assert.assertEquals(result, 0, 1E-8);
319         result = UnivariateSolverUtils.solve(f, -0.3, 0.45);
320         Assert.assertEquals(result, 0, 1E-6);
321         result = UnivariateSolverUtils.solve(f, 0.3, 0.7);
322         Assert.assertEquals(result, 0.5, 1E-6);
323         result = UnivariateSolverUtils.solve(f, 0.2, 0.6);
324         Assert.assertEquals(result, 0.5, 1E-6);
325         result = UnivariateSolverUtils.solve(f, 0.05, 0.95);
326         Assert.assertEquals(result, 0.5, 1E-6);
327         result = UnivariateSolverUtils.solve(f, 0.85, 1.25);
328         Assert.assertEquals(result, 1.0, 1E-6);
329         result = UnivariateSolverUtils.solve(f, 0.8, 1.2);
330         Assert.assertEquals(result, 1.0, 1E-6);
331         result = UnivariateSolverUtils.solve(f, 0.85, 1.75);
332         Assert.assertEquals(result, 1.0, 1E-6);
333         result = UnivariateSolverUtils.solve(f, 0.55, 1.45);
334         Assert.assertEquals(result, 1.0, 1E-6);
335         result = UnivariateSolverUtils.solve(f, 0.85, 5);
336         Assert.assertEquals(result, 1.0, 1E-6);
337     }
338 }