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
18 package org.apache.commons.math.analysis;
19
20 import java.io.Serializable;
21
22 import org.apache.commons.math.FunctionEvaluationException;
23
24 /**
25 * Provide a default implementation for several functions useful to generic
26 * solvers.
27 *
28 * @version $Revision: 480440 $ $Date: 2006-11-29 00:14:12 -0700 (Wed, 29 Nov 2006) $
29 */
30 public abstract class UnivariateRealSolverImpl implements UnivariateRealSolver,
31 Serializable {
32
33 /** Serializable version identifier */
34 private static final long serialVersionUID = 1112491292565386596L;
35
36 /** Maximum absolute error. */
37 protected double absoluteAccuracy;
38
39 /** Maximum relative error. */
40 protected double relativeAccuracy;
41
42 /** Maximum error of function. */
43 protected double functionValueAccuracy;
44
45 /** Maximum number of iterations. */
46 protected int maximalIterationCount;
47
48 /** Default maximum absolute error. */
49 protected double defaultAbsoluteAccuracy;
50
51 /** Default maximum relative error. */
52 protected double defaultRelativeAccuracy;
53
54 /** Default maximum error of function. */
55 protected double defaultFunctionValueAccuracy;
56
57 /** Default maximum number of iterations. */
58 protected int defaultMaximalIterationCount;
59
60 /** Indicates where a root has been computed. */
61 protected boolean resultComputed = false;
62
63 /** The last computed root. */
64 protected double result;
65
66 // Mainly for test framework.
67 /** The last iteration count. */
68 protected int iterationCount;
69
70 /** The function to solve. */
71 protected UnivariateRealFunction f;
72
73 /**
74 * Construct a solver with given iteration count and accuracy.
75 *
76 * @param f the function to solve.
77 * @param defaultAbsoluteAccuracy maximum absolute error
78 * @param defaultMaximalIterationCount maximum number of iterations
79 * @throws IllegalArgumentException if f is null or the
80 * defaultAbsoluteAccuracy is not valid
81 */
82 protected UnivariateRealSolverImpl(
83 UnivariateRealFunction f,
84 int defaultMaximalIterationCount,
85 double defaultAbsoluteAccuracy) {
86
87 super();
88
89 if (f == null) {
90 throw new IllegalArgumentException("function can not be null.");
91 }
92
93 this.f = f;
94 this.defaultAbsoluteAccuracy = defaultAbsoluteAccuracy;
95 this.defaultRelativeAccuracy = 1E-14;
96 this.defaultFunctionValueAccuracy = 1E-15;
97 this.absoluteAccuracy = defaultAbsoluteAccuracy;
98 this.relativeAccuracy = defaultRelativeAccuracy;
99 this.functionValueAccuracy = defaultFunctionValueAccuracy;
100 this.defaultMaximalIterationCount = defaultMaximalIterationCount;
101 this.maximalIterationCount = defaultMaximalIterationCount;
102 }
103
104 /**
105 * Access the last computed root.
106 *
107 * @return the last computed root
108 * @throws IllegalStateException if no root has been computed
109 */
110 public double getResult() {
111 if (resultComputed) {
112 return result;
113 } else {
114 throw new IllegalStateException("No result available");
115 }
116 }
117
118 /**
119 * Access the last iteration count.
120 *
121 * @return the last iteration count
122 * @throws IllegalStateException if no root has been computed
123 *
124 */
125 public int getIterationCount() {
126 if (resultComputed) {
127 return iterationCount;
128 } else {
129 throw new IllegalStateException("No result available");
130 }
131 }
132
133 /**
134 * Convenience function for implementations.
135 *
136 * @param result the result to set
137 * @param iterationCount the iteration count to set
138 */
139 protected final void setResult(double result, int iterationCount) {
140 this.result = result;
141 this.iterationCount = iterationCount;
142 this.resultComputed = true;
143 }
144
145 /**
146 * Convenience function for implementations.
147 */
148 protected final void clearResult() {
149 this.resultComputed = false;
150 }
151
152 /**
153 * Set the absolute accuracy.
154 *
155 * @param accuracy the accuracy.
156 * @throws IllegalArgumentException if the accuracy can't be achieved by
157 * the solver or is otherwise deemed unreasonable.
158 */
159 public void setAbsoluteAccuracy(double accuracy) {
160 absoluteAccuracy = accuracy;
161 }
162
163 /**
164 * Get the actual absolute accuracy.
165 *
166 * @return the accuracy
167 */
168 public double getAbsoluteAccuracy() {
169 return absoluteAccuracy;
170 }
171
172 /**
173 * Reset the absolute accuracy to the default.
174 */
175 public void resetAbsoluteAccuracy() {
176 absoluteAccuracy = defaultAbsoluteAccuracy;
177 }
178
179 /**
180 * Set the upper limit for the number of iterations.
181 *
182 * @param count maximum number of iterations
183 */
184 public void setMaximalIterationCount(int count) {
185 maximalIterationCount = count;
186 }
187
188 /**
189 * Get the upper limit for the number of iterations.
190 *
191 * @return the actual upper limit
192 */
193 public int getMaximalIterationCount() {
194 return maximalIterationCount;
195 }
196
197 /**
198 * Reset the upper limit for the number of iterations to the default.
199 */
200 public void resetMaximalIterationCount() {
201 maximalIterationCount = defaultMaximalIterationCount;
202 }
203
204 /**
205 * Set the relative accuracy.
206 *
207 * @param accuracy the relative accuracy.
208 * @throws IllegalArgumentException if the accuracy can't be achieved by
209 * the solver or is otherwise deemed unreasonable.
210 */
211 public void setRelativeAccuracy(double accuracy) {
212 relativeAccuracy = accuracy;
213 }
214
215 /**
216 * Get the actual relative accuracy.
217 * @return the accuracy
218 */
219 public double getRelativeAccuracy() {
220 return relativeAccuracy;
221 }
222
223 /**
224 * Reset the relative accuracy to the default.
225 */
226 public void resetRelativeAccuracy() {
227 relativeAccuracy = defaultRelativeAccuracy;
228 }
229
230 /**
231 * Set the function value accuracy.
232 *
233 * @param accuracy the accuracy.
234 * @throws IllegalArgumentException if the accuracy can't be achieved by
235 * the solver or is otherwise deemed unreasonable.
236 */
237 public void setFunctionValueAccuracy(double accuracy) {
238 functionValueAccuracy = accuracy;
239 }
240
241 /**
242 * Get the actual function value accuracy.
243 * @return the accuracy
244 */
245 public double getFunctionValueAccuracy() {
246 return functionValueAccuracy;
247 }
248
249 /**
250 * Reset the actual function accuracy to the default.
251 */
252 public void resetFunctionValueAccuracy() {
253 functionValueAccuracy = defaultFunctionValueAccuracy;
254 }
255
256
257 /**
258 * Returns true iff the function takes opposite signs at the endpoints.
259 *
260 * @param lower the lower endpoint
261 * @param upper the upper endpoint
262 * @param f the function
263 * @return true if f(lower) * f(upper) < 0
264 * @throws FunctionEvaluationException if an error occurs evaluating the
265 * function at the endpoints
266 */
267 protected boolean isBracketing(double lower, double upper,
268 UnivariateRealFunction f) throws FunctionEvaluationException {
269 double f1 = f.value(lower);
270 double f2 = f.value(upper);
271 return ((f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0));
272 }
273
274 /**
275 * Returns true if the arguments form a (strictly) increasing sequence
276 *
277 * @param start first number
278 * @param mid second number
279 * @param end third number
280 * @return true if the arguments form an increasing sequence
281 */
282 protected boolean isSequence(double start, double mid, double end) {
283 return (start < mid) && (mid < end);
284 }
285
286 /**
287 * Verifies that the endpoints specify an interval,
288 * throws IllegalArgumentException if not
289 *
290 * @param lower lower endpoint
291 * @param upper upper endpoint
292 * @throws IllegalArgumentException
293 */
294 protected void verifyInterval(double lower, double upper) {
295 if (lower >= upper) {
296 throw new IllegalArgumentException
297 ("Endpoints do not specify an interval: [" + lower +
298 "," + upper + "]");
299 }
300 }
301
302 /**
303 * Verifies that <code>lower < initial < upper</code>
304 * throws IllegalArgumentException if not
305 *
306 * @param lower lower endpoint
307 * @param initial initial value
308 * @param upper upper endpoint
309 * @throws IllegalArgumentException
310 */
311 protected void verifySequence(double lower, double initial, double upper) {
312 if (!isSequence(lower, initial, upper)) {
313 throw new IllegalArgumentException
314 ("Invalid interval, initial value parameters: lower=" +
315 lower + " initial=" + initial + " upper=" + upper);
316 }
317 }
318
319 /**
320 * Verifies that the endpoints specify an interval and the function takes
321 * opposite signs at the enpoints, throws IllegalArgumentException if not
322 *
323 * @param lower lower endpoint
324 * @param upper upper endpoint
325 * @param f function
326 * @throws IllegalArgumentException
327 * @throws FunctionEvaluationException if an error occurs evaluating the
328 * function at the endpoints
329 */
330 protected void verifyBracketing(double lower, double upper,
331 UnivariateRealFunction f) throws FunctionEvaluationException {
332
333 verifyInterval(lower, upper);
334 if (!isBracketing(lower, upper, f)) {
335 throw new IllegalArgumentException
336 ("Function values at endpoints do not have different signs." +
337 " Endpoints: [" + lower + "," + upper + "]" +
338 " Values: [" + f.value(lower) + "," + f.value(upper) + "]");
339 }
340 }
341 }