blob: 325b6627e4512a6e9ab461f4fa7a335158071bf6 [file] [log] [blame]
Raymonddee08492015-04-02 10:43:13 -07001/*
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 */
17package org.apache.commons.math.analysis.solvers;
18
19import org.apache.commons.math.ConvergenceException;
20import org.apache.commons.math.FunctionEvaluationException;
21import org.apache.commons.math.MathRuntimeException;
22import org.apache.commons.math.MaxIterationsExceededException;
23import org.apache.commons.math.analysis.UnivariateRealFunction;
24import org.apache.commons.math.exception.util.LocalizedFormats;
25import org.apache.commons.math.util.FastMath;
26
27
28/**
29 * Implements a modified version of the
30 * <a href="http://mathworld.wolfram.com/SecantMethod.html">secant method</a>
31 * for approximating a zero of a real univariate function.
32 * <p>
33 * The algorithm is modified to maintain bracketing of a root by successive
34 * approximations. Because of forced bracketing, convergence may be slower than
35 * the unrestricted secant algorithm. However, this implementation should in
36 * general outperform the
37 * <a href="http://mathworld.wolfram.com/MethodofFalsePosition.html">
38 * regula falsi method.</a></p>
39 * <p>
40 * The function is assumed to be continuous but not necessarily smooth.</p>
41 *
42 * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
43 */
44public class SecantSolver extends UnivariateRealSolverImpl {
45
46 /**
47 * Construct a solver for the given function.
48 * @param f function to solve.
49 * @deprecated as of 2.0 the function to solve is passed as an argument
50 * to the {@link #solve(UnivariateRealFunction, double, double)} or
51 * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
52 * method.
53 */
54 @Deprecated
55 public SecantSolver(UnivariateRealFunction f) {
56 super(f, 100, 1E-6);
57 }
58
59 /**
60 * Construct a solver.
61 * @deprecated in 2.2 (to be removed in 3.0).
62 */
63 @Deprecated
64 public SecantSolver() {
65 super(100, 1E-6);
66 }
67
68 /** {@inheritDoc} */
69 @Deprecated
70 public double solve(final double min, final double max)
71 throws ConvergenceException, FunctionEvaluationException {
72 return solve(f, min, max);
73 }
74
75 /** {@inheritDoc} */
76 @Deprecated
77 public double solve(final double min, final double max, final double initial)
78 throws ConvergenceException, FunctionEvaluationException {
79 return solve(f, min, max, initial);
80 }
81
82 /**
83 * Find a zero in the given interval.
84 *
85 * @param f the function to solve
86 * @param min the lower bound for the interval
87 * @param max the upper bound for the interval
88 * @param initial the start value to use (ignored)
89 * @param maxEval Maximum number of evaluations.
90 * @return the value where the function is zero
91 * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
92 * @throws FunctionEvaluationException if an error occurs evaluating the function
93 * @throws IllegalArgumentException if min is not less than max or the
94 * signs of the values of the function at the endpoints are not opposites
95 */
96 @Override
97 public double solve(int maxEval, final UnivariateRealFunction f,
98 final double min, final double max, final double initial)
99 throws MaxIterationsExceededException, FunctionEvaluationException {
100 setMaximalIterationCount(maxEval);
101 return solve(f, min, max, initial);
102 }
103
104 /**
105 * Find a zero in the given interval.
106 *
107 * @param f the function to solve
108 * @param min the lower bound for the interval
109 * @param max the upper bound for the interval
110 * @param initial the start value to use (ignored)
111 * @return the value where the function is zero
112 * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
113 * @throws FunctionEvaluationException if an error occurs evaluating the function
114 * @throws IllegalArgumentException if min is not less than max or the
115 * signs of the values of the function at the endpoints are not opposites
116 * @deprecated in 2.2 (to be removed in 3.0).
117 */
118 @Deprecated
119 public double solve(final UnivariateRealFunction f,
120 final double min, final double max, final double initial)
121 throws MaxIterationsExceededException, FunctionEvaluationException {
122 return solve(f, min, max);
123 }
124
125 /**
126 * Find a zero in the given interval.
127 * @param f the function to solve
128 * @param min the lower bound for the interval.
129 * @param max the upper bound for the interval.
130 * @param maxEval Maximum number of evaluations.
131 * @return the value where the function is zero
132 * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
133 * @throws FunctionEvaluationException if an error occurs evaluating the function
134 * @throws IllegalArgumentException if min is not less than max or the
135 * signs of the values of the function at the endpoints are not opposites
136 */
137 @Override
138 public double solve(int maxEval, final UnivariateRealFunction f,
139 final double min, final double max)
140 throws MaxIterationsExceededException, FunctionEvaluationException {
141 setMaximalIterationCount(maxEval);
142 return solve(f, min, max);
143 }
144
145 /**
146 * Find a zero in the given interval.
147 * @param f the function to solve
148 * @param min the lower bound for the interval.
149 * @param max the upper bound for the interval.
150 * @return the value where the function is zero
151 * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
152 * @throws FunctionEvaluationException if an error occurs evaluating the function
153 * @throws IllegalArgumentException if min is not less than max or the
154 * signs of the values of the function at the endpoints are not opposites
155 * @deprecated in 2.2 (to be removed in 3.0).
156 */
157 @Deprecated
158 public double solve(final UnivariateRealFunction f,
159 final double min, final double max)
160 throws MaxIterationsExceededException, FunctionEvaluationException {
161
162 clearResult();
163 verifyInterval(min, max);
164
165 // Index 0 is the old approximation for the root.
166 // Index 1 is the last calculated approximation for the root.
167 // Index 2 is a bracket for the root with respect to x0.
168 // OldDelta is the length of the bracketing interval of the last
169 // iteration.
170 double x0 = min;
171 double x1 = max;
172 double y0 = f.value(x0);
173 double y1 = f.value(x1);
174
175 // Verify bracketing
176 if (y0 * y1 >= 0) {
177 throw MathRuntimeException.createIllegalArgumentException(
178 LocalizedFormats.SAME_SIGN_AT_ENDPOINTS, min, max, y0, y1);
179 }
180
181 double x2 = x0;
182 double y2 = y0;
183 double oldDelta = x2 - x1;
184 int i = 0;
185 while (i < maximalIterationCount) {
186 if (FastMath.abs(y2) < FastMath.abs(y1)) {
187 x0 = x1;
188 x1 = x2;
189 x2 = x0;
190 y0 = y1;
191 y1 = y2;
192 y2 = y0;
193 }
194 if (FastMath.abs(y1) <= functionValueAccuracy) {
195 setResult(x1, i);
196 return result;
197 }
198 if (FastMath.abs(oldDelta) <
199 FastMath.max(relativeAccuracy * FastMath.abs(x1), absoluteAccuracy)) {
200 setResult(x1, i);
201 return result;
202 }
203 double delta;
204 if (FastMath.abs(y1) > FastMath.abs(y0)) {
205 // Function value increased in last iteration. Force bisection.
206 delta = 0.5 * oldDelta;
207 } else {
208 delta = (x0 - x1) / (1 - y0 / y1);
209 if (delta / oldDelta > 1) {
210 // New approximation falls outside bracket.
211 // Fall back to bisection.
212 delta = 0.5 * oldDelta;
213 }
214 }
215 x0 = x1;
216 y0 = y1;
217 x1 = x1 + delta;
218 y1 = f.value(x1);
219 if ((y1 > 0) == (y2 > 0)) {
220 // New bracket is (x0,x1).
221 x2 = x0;
222 y2 = y0;
223 }
224 oldDelta = x2 - x1;
225 i++;
226 }
227 throw new MaxIterationsExceededException(maximalIterationCount);
228 }
229
230}