Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
RiddersSolver |
|
| 8.666666666666666;8.667 |
1 | /* |
|
2 | * Copyright 2005 The Apache Software Foundation. |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | package org.apache.commons.math.analysis; |
|
17 | ||
18 | import org.apache.commons.math.ConvergenceException; |
|
19 | import org.apache.commons.math.FunctionEvaluationException; |
|
20 | import org.apache.commons.math.util.MathUtils; |
|
21 | ||
22 | /** |
|
23 | * Implements the <a href="http://mathworld.wolfram.com/RiddersMethod.html"> |
|
24 | * Ridders' Method</a> for root finding of real univariate functions. For |
|
25 | * reference, see C. Ridders, <i>A new algorithm for computing a single root |
|
26 | * of a real continuous function </i>, IEEE Transactions on Circuits and |
|
27 | * Systems, 26 (1979), 979 - 980. |
|
28 | * <p> |
|
29 | * The function should be continuous but not necessarily smooth. |
|
30 | * |
|
31 | * @version $Revision$ $Date$ |
|
32 | */ |
|
33 | public class RiddersSolver extends UnivariateRealSolverImpl { |
|
34 | ||
35 | /** serializable version identifier */ |
|
36 | static final long serialVersionUID = -4703139035737911735L; |
|
37 | ||
38 | /** |
|
39 | * Construct a solver for the given function. |
|
40 | * |
|
41 | * @param f function to solve |
|
42 | */ |
|
43 | public RiddersSolver(UnivariateRealFunction f) { |
|
44 | 8 | super(f, 100, 1E-6); |
45 | 8 | } |
46 | ||
47 | /** |
|
48 | * Find a root in the given interval with initial value. |
|
49 | * <p> |
|
50 | * Requires bracketing condition. |
|
51 | * |
|
52 | * @param min the lower bound for the interval |
|
53 | * @param max the upper bound for the interval |
|
54 | * @param initial the start value to use |
|
55 | * @return the point at which the function value is zero |
|
56 | * @throws ConvergenceException if the maximum iteration count is exceeded |
|
57 | * or the solver detects convergence problems otherwise |
|
58 | * @throws FunctionEvaluationException if an error occurs evaluating the |
|
59 | * function |
|
60 | * @throws IllegalArgumentException if any parameters are invalid |
|
61 | */ |
|
62 | public double solve(double min, double max, double initial) throws |
|
63 | ConvergenceException, FunctionEvaluationException { |
|
64 | ||
65 | // check for zeros before verifying bracketing |
|
66 | 0 | if (f.value(min) == 0.0) { return min; } |
67 | 0 | if (f.value(max) == 0.0) { return max; } |
68 | 0 | if (f.value(initial) == 0.0) { return initial; } |
69 | ||
70 | 0 | verifyBracketing(min, max, f); |
71 | 0 | verifySequence(min, initial, max); |
72 | 0 | if (isBracketing(min, initial, f)) { |
73 | 0 | return solve(min, initial); |
74 | } else { |
|
75 | 0 | return solve(initial, max); |
76 | } |
|
77 | } |
|
78 | ||
79 | /** |
|
80 | * Find a root in the given interval. |
|
81 | * <p> |
|
82 | * Requires bracketing condition. |
|
83 | * |
|
84 | * @param min the lower bound for the interval |
|
85 | * @param max the upper bound for the interval |
|
86 | * @return the point at which the function value is zero |
|
87 | * @throws ConvergenceException if the maximum iteration count is exceeded |
|
88 | * or the solver detects convergence problems otherwise |
|
89 | * @throws FunctionEvaluationException if an error occurs evaluating the |
|
90 | * function |
|
91 | * @throws IllegalArgumentException if any parameters are invalid |
|
92 | */ |
|
93 | public double solve(double min, double max) throws ConvergenceException, |
|
94 | FunctionEvaluationException { |
|
95 | ||
96 | // [x1, x2] is the bracketing interval in each iteration |
|
97 | // x3 is the midpoint of [x1, x2] |
|
98 | // x is the new root approximation and an endpoint of the new interval |
|
99 | double x1, x2, x3, x, oldx, y1, y2, y3, y, delta, correction, tolerance; |
|
100 | ||
101 | 20 | x1 = min; y1 = f.value(x1); |
102 | 20 | x2 = max; y2 = f.value(x2); |
103 | ||
104 | // check for zeros before verifying bracketing |
|
105 | 20 | if (y1 == 0.0) { return min; } |
106 | 20 | if (y2 == 0.0) { return max; } |
107 | 20 | verifyBracketing(min, max, f); |
108 | ||
109 | 16 | int i = 1; |
110 | 16 | oldx = Double.POSITIVE_INFINITY; |
111 | 82 | while (i <= maximalIterationCount) { |
112 | // calculate the new root approximation |
|
113 | 82 | x3 = 0.5 * (x1 + x2); |
114 | 82 | y3 = f.value(x3); |
115 | 82 | if (Math.abs(y3) <= functionValueAccuracy) { |
116 | 0 | setResult(x3, i); |
117 | 0 | return result; |
118 | } |
|
119 | 82 | delta = 1 - (y1 * y2) / (y3 * y3); // delta > 1 due to bracketing |
120 | 82 | correction = (MathUtils.sign(y2) * MathUtils.sign(y3)) * |
121 | (x3 - x1) / Math.sqrt(delta); |
|
122 | 82 | x = x3 - correction; // correction != 0 |
123 | 82 | y = f.value(x); |
124 | ||
125 | // check for convergence |
|
126 | 82 | tolerance = Math.max(relativeAccuracy * Math.abs(x), absoluteAccuracy); |
127 | 82 | if (Math.abs(x - oldx) <= tolerance) { |
128 | 16 | setResult(x, i); |
129 | 16 | return result; |
130 | } |
|
131 | 66 | if (Math.abs(y) <= functionValueAccuracy) { |
132 | 0 | setResult(x, i); |
133 | 0 | return result; |
134 | } |
|
135 | ||
136 | // prepare the new interval for next iteration |
|
137 | // Ridders' method guarantees x1 < x < x2 |
|
138 | 66 | if (correction > 0.0) { // x1 < x < x3 |
139 | 42 | if (MathUtils.sign(y1) + MathUtils.sign(y) == 0.0) { |
140 | 18 | x2 = x; y2 = y; |
141 | } else { |
|
142 | 24 | x1 = x; x2 = x3; |
143 | 24 | y1 = y; y2 = y3; |
144 | } |
|
145 | } else { // x3 < x < x2 |
|
146 | 24 | if (MathUtils.sign(y2) + MathUtils.sign(y) == 0.0) { |
147 | 16 | x1 = x; y1 = y; |
148 | } else { |
|
149 | 8 | x1 = x3; x2 = x; |
150 | 8 | y1 = y3; y2 = y; |
151 | } |
|
152 | } |
|
153 | 66 | oldx = x; |
154 | 66 | i++; |
155 | } |
|
156 | 0 | throw new ConvergenceException("Maximum number of iterations exceeded."); |
157 | } |
|
158 | } |