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 MullerSolver 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 MullerSolverTest {
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 MullerSolver();
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 MullerSolver();
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 10 to 15 iterations for the last two tests to converge.
104      * In fact, if not for the bisection alternative, the solver would
105      * exceed the default maximal iteration of 100.
106      */
107     @Test
108     public void testExpm1Function() {
109         UnivariateFunction f = new Expm1();
110         UnivariateSolver solver = new MullerSolver();
111         double min;
112         double max;
113         double expected;
114         double result;
115         double tolerance;
116 
117         min = -1.0; max = 2.0; expected = 0.0;
118         tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
119                     JdkMath.abs(expected * solver.getRelativeAccuracy()));
120         result = solver.solve(100, f, min, max);
121         Assert.assertEquals(expected, result, tolerance);
122 
123         min = -20.0; max = 10.0; expected = 0.0;
124         tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
125                     JdkMath.abs(expected * solver.getRelativeAccuracy()));
126         result = solver.solve(100, f, min, max);
127         Assert.assertEquals(expected, result, tolerance);
128 
129         min = -50.0; max = 100.0; expected = 0.0;
130         tolerance = JdkMath.max(solver.getAbsoluteAccuracy(),
131                     JdkMath.abs(expected * solver.getRelativeAccuracy()));
132         result = solver.solve(100, f, min, max);
133         Assert.assertEquals(expected, result, tolerance);
134     }
135 
136     /**
137      * Test of parameters for the solver.
138      */
139     @Test
140     public void testParameters() {
141         UnivariateFunction f = new Sin();
142         UnivariateSolver solver = new MullerSolver();
143 
144         try {
145             // bad interval
146             double root = solver.solve(100, f, 1, -1);
147             System.out.println("root=" + root);
148             Assert.fail("Expecting NumberIsTooLargeException - bad interval");
149         } catch (NumberIsTooLargeException ex) {
150             // expected
151         }
152         try {
153             // no bracketing
154             solver.solve(100, f, 2, 3);
155             Assert.fail("Expecting NoBracketingException - no bracketing");
156         } catch (NoBracketingException ex) {
157             // expected
158         }
159     }
160 }