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  package org.apache.commons.math4.legacy.analysis.solvers;
18  
19  import org.apache.commons.math4.legacy.analysis.QuinticFunction;
20  import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
21  import org.apache.commons.math4.legacy.analysis.function.Expm1;
22  import org.apache.commons.math4.legacy.analysis.function.Sin;
23  import org.apache.commons.math4.legacy.exception.NoBracketingException;
24  import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException;
25  import org.apache.commons.math4.core.jdkmath.JdkMath;
26  import org.junit.Assert;
27  import org.junit.Test;
28  
29  /**
30   * Test case for {@link MullerSolver2 Muller} solver.
31   * <p>
32   * Muller's method converges almost quadratically near roots, but it can
33   * be very slow in regions far away from zeros. Test runs show that for
34   * reasonably good initial values, for a default absolute accuracy of 1E-6,
35   * it generally takes 5 to 10 iterations for the solver to converge.
36   * <p>
37   * Tests for the exponential function illustrate the situations where
38   * Muller solver performs poorly.
39   *
40   */
41  public final class MullerSolver2Test {
42      /**
43       * Test of solver for the sine function.
44       */
45      @Test
46      public void testSinFunction() {
47          UnivariateFunction f = new Sin();
48          UnivariateSolver solver = new MullerSolver2();
49          double min;
50          double max;
51          double expected;
52          double result;
53          double tolerance;
54  
55          min = 3.0; max = 4.0; expected = JdkMath.PI;
56          tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
57                      JdkMath.abs(expected * solver.getRelativeAccuracy()));
58          result = solver.solve(100, f, min, max);
59          Assert.assertEquals(expected, result, tolerance);
60  
61          min = -1.0; max = 1.5; expected = 0.0;
62          tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
63                      JdkMath.abs(expected * solver.getRelativeAccuracy()));
64          result = solver.solve(100, f, min, max);
65          Assert.assertEquals(expected, result, tolerance);
66      }
67  
68      /**
69       * Test of solver for the quintic function.
70       */
71      @Test
72      public void testQuinticFunction() {
73          UnivariateFunction f = new QuinticFunction();
74          UnivariateSolver solver = new MullerSolver2();
75          double min;
76          double max;
77          double expected;
78          double result;
79          double tolerance;
80  
81          min = -0.4; max = 0.2; expected = 0.0;
82          tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
83                      JdkMath.abs(expected * solver.getRelativeAccuracy()));
84          result = solver.solve(100, f, min, max);
85          Assert.assertEquals(expected, result, tolerance);
86  
87          min = 0.75; max = 1.5; expected = 1.0;
88          tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
89                      JdkMath.abs(expected * solver.getRelativeAccuracy()));
90          result = solver.solve(100, f, min, max);
91          Assert.assertEquals(expected, result, tolerance);
92  
93          min = -0.9; max = -0.2; expected = -0.5;
94          tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
95                      JdkMath.abs(expected * solver.getRelativeAccuracy()));
96          result = solver.solve(100, f, min, max);
97          Assert.assertEquals(expected, result, tolerance);
98      }
99  
100     /**
101      * Test of solver for the exponential function.
102      * <p>
103      * It takes 25 to 50 iterations for the last two tests to converge.
104      */
105     @Test
106     public void testExpm1Function() {
107         UnivariateFunction f = new Expm1();
108         UnivariateSolver solver = new MullerSolver2();
109         double min;
110         double max;
111         double expected;
112         double result;
113         double tolerance;
114 
115         min = -1.0; max = 2.0; expected = 0.0;
116         tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
117                     JdkMath.abs(expected * solver.getRelativeAccuracy()));
118         result = solver.solve(100, f, min, max);
119         Assert.assertEquals(expected, result, tolerance);
120 
121         min = -20.0; max = 10.0; expected = 0.0;
122         tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
123                     JdkMath.abs(expected * solver.getRelativeAccuracy()));
124         result = solver.solve(100, f, min, max);
125         Assert.assertEquals(expected, result, tolerance);
126 
127         min = -50.0; max = 100.0; expected = 0.0;
128         tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
129                     JdkMath.abs(expected * solver.getRelativeAccuracy()));
130         result = solver.solve(100, f, min, max);
131         Assert.assertEquals(expected, result, tolerance);
132     }
133 
134     /**
135      * Test of parameters for the solver.
136      */
137     @Test
138     public void testParameters() {
139         UnivariateFunction f = new Sin();
140         UnivariateSolver solver = new MullerSolver2();
141 
142         try {
143             // bad interval
144             solver.solve(100, f, 1, -1);
145             Assert.fail("Expecting NumberIsTooLargeException - bad interval");
146         } catch (NumberIsTooLargeException ex) {
147             // expected
148         }
149         try {
150             // no bracketing
151             solver.solve(100, f, 2, 3);
152             Assert.fail("Expecting NoBracketingException - no bracketing");
153         } catch (NoBracketingException ex) {
154             // expected
155         }
156     }
157 }