001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math.analysis.solvers;
018
019 import org.apache.commons.math.MathException;
020 import org.apache.commons.math.analysis.Expm1Function;
021 import org.apache.commons.math.analysis.QuinticFunction;
022 import org.apache.commons.math.analysis.SinFunction;
023 import org.apache.commons.math.analysis.UnivariateRealFunction;
024
025 import junit.framework.TestCase;
026
027 /**
028 * Testcase for Muller solver.
029 * <p>
030 * Muller's method converges almost quadratically near roots, but it can
031 * be very slow in regions far away from zeros. Test runs show that for
032 * reasonably good initial values, for a default absolute accuracy of 1E-6,
033 * it generally takes 5 to 10 iterations for the solver to converge.
034 * <p>
035 * Tests for the exponential function illustrate the situations where
036 * Muller solver performs poorly.
037 *
038 * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $
039 */
040 public final class MullerSolverTest extends TestCase {
041
042 /**
043 * Test deprecated APIs.
044 */
045 @Deprecated
046 public void testDeprecated() throws MathException {
047 UnivariateRealFunction f = new SinFunction();
048 UnivariateRealSolver solver = new MullerSolver(f);
049 double min, max, expected, result, tolerance;
050
051 min = 3.0; max = 4.0; expected = Math.PI;
052 tolerance = Math.max(solver.getAbsoluteAccuracy(),
053 Math.abs(expected * solver.getRelativeAccuracy()));
054 result = solver.solve(min, max);
055 assertEquals(expected, result, tolerance);
056
057 min = -1.0; max = 1.5; expected = 0.0;
058 tolerance = Math.max(solver.getAbsoluteAccuracy(),
059 Math.abs(expected * solver.getRelativeAccuracy()));
060 result = solver.solve(min, max);
061 assertEquals(expected, result, tolerance);
062 }
063
064 /**
065 * Test deprecated APIs.
066 */
067 @Deprecated
068 public void testDeprecated2() throws MathException {
069 UnivariateRealFunction f = new QuinticFunction();
070 MullerSolver solver = new MullerSolver(f);
071 double min, max, expected, result, tolerance;
072
073 min = -0.4; max = 0.2; expected = 0.0;
074 tolerance = Math.max(solver.getAbsoluteAccuracy(),
075 Math.abs(expected * solver.getRelativeAccuracy()));
076 result = solver.solve2(min, max);
077 assertEquals(expected, result, tolerance);
078
079 min = 0.75; max = 1.5; expected = 1.0;
080 tolerance = Math.max(solver.getAbsoluteAccuracy(),
081 Math.abs(expected * solver.getRelativeAccuracy()));
082 result = solver.solve2(min, max);
083 assertEquals(expected, result, tolerance);
084
085 min = -0.9; max = -0.2; expected = -0.5;
086 tolerance = Math.max(solver.getAbsoluteAccuracy(),
087 Math.abs(expected * solver.getRelativeAccuracy()));
088 result = solver.solve2(min, max);
089 assertEquals(expected, result, tolerance);
090 }
091
092 /**
093 * Test of solver for the sine function.
094 */
095 public void testSinFunction() throws MathException {
096 UnivariateRealFunction f = new SinFunction();
097 UnivariateRealSolver solver = new MullerSolver();
098 double min, max, expected, result, tolerance;
099
100 min = 3.0; max = 4.0; expected = Math.PI;
101 tolerance = Math.max(solver.getAbsoluteAccuracy(),
102 Math.abs(expected * solver.getRelativeAccuracy()));
103 result = solver.solve(f, min, max);
104 assertEquals(expected, result, tolerance);
105
106 min = -1.0; max = 1.5; expected = 0.0;
107 tolerance = Math.max(solver.getAbsoluteAccuracy(),
108 Math.abs(expected * solver.getRelativeAccuracy()));
109 result = solver.solve(f, min, max);
110 assertEquals(expected, result, tolerance);
111 }
112
113 /**
114 * Test of solver for the sine function using solve2().
115 */
116 public void testSinFunction2() throws MathException {
117 UnivariateRealFunction f = new SinFunction();
118 MullerSolver solver = new MullerSolver();
119 double min, max, expected, result, tolerance;
120
121 min = 3.0; max = 4.0; expected = Math.PI;
122 tolerance = Math.max(solver.getAbsoluteAccuracy(),
123 Math.abs(expected * solver.getRelativeAccuracy()));
124 result = solver.solve2(f, min, max);
125 assertEquals(expected, result, tolerance);
126
127 min = -1.0; max = 1.5; expected = 0.0;
128 tolerance = Math.max(solver.getAbsoluteAccuracy(),
129 Math.abs(expected * solver.getRelativeAccuracy()));
130 result = solver.solve2(f, min, max);
131 assertEquals(expected, result, tolerance);
132 }
133
134 /**
135 * Test of solver for the quintic function.
136 */
137 public void testQuinticFunction() throws MathException {
138 UnivariateRealFunction f = new QuinticFunction();
139 UnivariateRealSolver solver = new MullerSolver();
140 double min, max, expected, result, tolerance;
141
142 min = -0.4; max = 0.2; expected = 0.0;
143 tolerance = Math.max(solver.getAbsoluteAccuracy(),
144 Math.abs(expected * solver.getRelativeAccuracy()));
145 result = solver.solve(f, min, max);
146 assertEquals(expected, result, tolerance);
147
148 min = 0.75; max = 1.5; expected = 1.0;
149 tolerance = Math.max(solver.getAbsoluteAccuracy(),
150 Math.abs(expected * solver.getRelativeAccuracy()));
151 result = solver.solve(f, min, max);
152 assertEquals(expected, result, tolerance);
153
154 min = -0.9; max = -0.2; expected = -0.5;
155 tolerance = Math.max(solver.getAbsoluteAccuracy(),
156 Math.abs(expected * solver.getRelativeAccuracy()));
157 result = solver.solve(f, min, max);
158 assertEquals(expected, result, tolerance);
159 }
160
161 /**
162 * Test of solver for the quintic function using solve2().
163 */
164 public void testQuinticFunction2() throws MathException {
165 UnivariateRealFunction f = new QuinticFunction();
166 MullerSolver solver = new MullerSolver();
167 double min, max, expected, result, tolerance;
168
169 min = -0.4; max = 0.2; expected = 0.0;
170 tolerance = Math.max(solver.getAbsoluteAccuracy(),
171 Math.abs(expected * solver.getRelativeAccuracy()));
172 result = solver.solve2(f, min, max);
173 assertEquals(expected, result, tolerance);
174
175 min = 0.75; max = 1.5; expected = 1.0;
176 tolerance = Math.max(solver.getAbsoluteAccuracy(),
177 Math.abs(expected * solver.getRelativeAccuracy()));
178 result = solver.solve2(f, min, max);
179 assertEquals(expected, result, tolerance);
180
181 min = -0.9; max = -0.2; expected = -0.5;
182 tolerance = Math.max(solver.getAbsoluteAccuracy(),
183 Math.abs(expected * solver.getRelativeAccuracy()));
184 result = solver.solve2(f, min, max);
185 assertEquals(expected, result, tolerance);
186 }
187
188 /**
189 * Test of solver for the exponential function.
190 * <p>
191 * It takes 10 to 15 iterations for the last two tests to converge.
192 * In fact, if not for the bisection alternative, the solver would
193 * exceed the default maximal iteration of 100.
194 */
195 public void testExpm1Function() throws MathException {
196 UnivariateRealFunction f = new Expm1Function();
197 UnivariateRealSolver solver = new MullerSolver();
198 double min, max, expected, result, tolerance;
199
200 min = -1.0; max = 2.0; expected = 0.0;
201 tolerance = Math.max(solver.getAbsoluteAccuracy(),
202 Math.abs(expected * solver.getRelativeAccuracy()));
203 result = solver.solve(f, min, max);
204 assertEquals(expected, result, tolerance);
205
206 min = -20.0; max = 10.0; expected = 0.0;
207 tolerance = Math.max(solver.getAbsoluteAccuracy(),
208 Math.abs(expected * solver.getRelativeAccuracy()));
209 result = solver.solve(f, min, max);
210 assertEquals(expected, result, tolerance);
211
212 min = -50.0; max = 100.0; expected = 0.0;
213 tolerance = Math.max(solver.getAbsoluteAccuracy(),
214 Math.abs(expected * solver.getRelativeAccuracy()));
215 result = solver.solve(f, min, max);
216 assertEquals(expected, result, tolerance);
217 }
218
219 /**
220 * Test of solver for the exponential function using solve2().
221 * <p>
222 * It takes 25 to 50 iterations for the last two tests to converge.
223 */
224 public void testExpm1Function2() throws MathException {
225 UnivariateRealFunction f = new Expm1Function();
226 MullerSolver solver = new MullerSolver();
227 double min, max, expected, result, tolerance;
228
229 min = -1.0; max = 2.0; expected = 0.0;
230 tolerance = Math.max(solver.getAbsoluteAccuracy(),
231 Math.abs(expected * solver.getRelativeAccuracy()));
232 result = solver.solve2(f, min, max);
233 assertEquals(expected, result, tolerance);
234
235 min = -20.0; max = 10.0; expected = 0.0;
236 tolerance = Math.max(solver.getAbsoluteAccuracy(),
237 Math.abs(expected * solver.getRelativeAccuracy()));
238 result = solver.solve2(f, min, max);
239 assertEquals(expected, result, tolerance);
240
241 min = -50.0; max = 100.0; expected = 0.0;
242 tolerance = Math.max(solver.getAbsoluteAccuracy(),
243 Math.abs(expected * solver.getRelativeAccuracy()));
244 result = solver.solve2(f, min, max);
245 assertEquals(expected, result, tolerance);
246 }
247
248 /**
249 * Test of parameters for the solver.
250 */
251 public void testParameters() throws Exception {
252 UnivariateRealFunction f = new SinFunction();
253 UnivariateRealSolver solver = new MullerSolver();
254
255 try {
256 // bad interval
257 solver.solve(f, 1, -1);
258 fail("Expecting IllegalArgumentException - bad interval");
259 } catch (IllegalArgumentException ex) {
260 // expected
261 }
262 try {
263 // no bracketing
264 solver.solve(f, 2, 3);
265 fail("Expecting IllegalArgumentException - no bracketing");
266 } catch (IllegalArgumentException ex) {
267 // expected
268 }
269 }
270 }