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 }