001: /*
002: * Copyright 2003-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.commons.math.analysis;
018:
019: import java.io.Serializable;
020:
021: import org.apache.commons.math.FunctionEvaluationException;
022:
023: /**
024: * Provide a default implementation for several functions useful to generic
025: * solvers.
026: *
027: * @version $Revision: 348888 $ $Date: 2005-11-24 23:21:25 -0700 (Thu, 24 Nov 2005) $
028: */
029: public abstract class UnivariateRealSolverImpl implements
030: UnivariateRealSolver, Serializable {
031:
032: /** Serializable version identifier */
033: private static final long serialVersionUID = 1112491292565386596L;
034:
035: /** Maximum absolute error. */
036: protected double absoluteAccuracy;
037:
038: /** Maximum relative error. */
039: protected double relativeAccuracy;
040:
041: /** Maximum error of function. */
042: protected double functionValueAccuracy;
043:
044: /** Maximum number of iterations. */
045: protected int maximalIterationCount;
046:
047: /** Default maximum absolute error. */
048: protected double defaultAbsoluteAccuracy;
049:
050: /** Default maximum relative error. */
051: protected double defaultRelativeAccuracy;
052:
053: /** Default maximum error of function. */
054: protected double defaultFunctionValueAccuracy;
055:
056: /** Default maximum number of iterations. */
057: protected int defaultMaximalIterationCount;
058:
059: /** Indicates where a root has been computed. */
060: protected boolean resultComputed = false;
061:
062: /** The last computed root. */
063: protected double result;
064:
065: // Mainly for test framework.
066: /** The last iteration count. */
067: protected int iterationCount;
068:
069: /** The function to solve. */
070: protected UnivariateRealFunction f;
071:
072: /**
073: * Construct a solver with given iteration count and accuracy.
074: *
075: * @param f the function to solve.
076: * @param defaultAbsoluteAccuracy maximum absolute error
077: * @param defaultMaximalIterationCount maximum number of iterations
078: * @throws IllegalArgumentException if f is null or the
079: * defaultAbsoluteAccuracy is not valid
080: */
081: protected UnivariateRealSolverImpl(UnivariateRealFunction f,
082: int defaultMaximalIterationCount,
083: double defaultAbsoluteAccuracy) {
084:
085: super ();
086:
087: if (f == null) {
088: throw new IllegalArgumentException(
089: "function can not be null.");
090: }
091:
092: this .f = f;
093: this .defaultAbsoluteAccuracy = defaultAbsoluteAccuracy;
094: this .defaultRelativeAccuracy = 1E-14;
095: this .defaultFunctionValueAccuracy = 1E-15;
096: this .absoluteAccuracy = defaultAbsoluteAccuracy;
097: this .relativeAccuracy = defaultRelativeAccuracy;
098: this .functionValueAccuracy = defaultFunctionValueAccuracy;
099: this .defaultMaximalIterationCount = defaultMaximalIterationCount;
100: this .maximalIterationCount = defaultMaximalIterationCount;
101: }
102:
103: /**
104: * Access the last computed root.
105: *
106: * @return the last computed root
107: * @throws IllegalStateException if no root has been computed
108: */
109: public double getResult() {
110: if (resultComputed) {
111: return result;
112: } else {
113: throw new IllegalStateException("No result available");
114: }
115: }
116:
117: /**
118: * Access the last iteration count.
119: *
120: * @return the last iteration count
121: * @throws IllegalStateException if no root has been computed
122: *
123: */
124: public int getIterationCount() {
125: if (resultComputed) {
126: return iterationCount;
127: } else {
128: throw new IllegalStateException("No result available");
129: }
130: }
131:
132: /**
133: * Convenience function for implementations.
134: *
135: * @param result the result to set
136: * @param iterationCount the iteration count to set
137: */
138: protected final void setResult(double result, int iterationCount) {
139: this .result = result;
140: this .iterationCount = iterationCount;
141: this .resultComputed = true;
142: }
143:
144: /**
145: * Convenience function for implementations.
146: */
147: protected final void clearResult() {
148: this .resultComputed = false;
149: }
150:
151: /**
152: * Set the absolute accuracy.
153: *
154: * @param accuracy the accuracy.
155: * @throws IllegalArgumentException if the accuracy can't be achieved by
156: * the solver or is otherwise deemed unreasonable.
157: */
158: public void setAbsoluteAccuracy(double accuracy) {
159: absoluteAccuracy = accuracy;
160: }
161:
162: /**
163: * Get the actual absolute accuracy.
164: *
165: * @return the accuracy
166: */
167: public double getAbsoluteAccuracy() {
168: return absoluteAccuracy;
169: }
170:
171: /**
172: * Reset the absolute accuracy to the default.
173: */
174: public void resetAbsoluteAccuracy() {
175: absoluteAccuracy = defaultAbsoluteAccuracy;
176: }
177:
178: /**
179: * Set the upper limit for the number of iterations.
180: *
181: * @param count maximum number of iterations
182: */
183: public void setMaximalIterationCount(int count) {
184: maximalIterationCount = count;
185: }
186:
187: /**
188: * Get the upper limit for the number of iterations.
189: *
190: * @return the actual upper limit
191: */
192: public int getMaximalIterationCount() {
193: return maximalIterationCount;
194: }
195:
196: /**
197: * Reset the upper limit for the number of iterations to the default.
198: */
199: public void resetMaximalIterationCount() {
200: maximalIterationCount = defaultMaximalIterationCount;
201: }
202:
203: /**
204: * Set the relative accuracy.
205: *
206: * @param accuracy the relative accuracy.
207: * @throws IllegalArgumentException if the accuracy can't be achieved by
208: * the solver or is otherwise deemed unreasonable.
209: */
210: public void setRelativeAccuracy(double accuracy) {
211: relativeAccuracy = accuracy;
212: }
213:
214: /**
215: * Get the actual relative accuracy.
216: * @return the accuracy
217: */
218: public double getRelativeAccuracy() {
219: return relativeAccuracy;
220: }
221:
222: /**
223: * Reset the relative accuracy to the default.
224: */
225: public void resetRelativeAccuracy() {
226: relativeAccuracy = defaultRelativeAccuracy;
227: }
228:
229: /**
230: * Set the function value accuracy.
231: *
232: * @param accuracy the accuracy.
233: * @throws IllegalArgumentException if the accuracy can't be achieved by
234: * the solver or is otherwise deemed unreasonable.
235: */
236: public void setFunctionValueAccuracy(double accuracy) {
237: functionValueAccuracy = accuracy;
238: }
239:
240: /**
241: * Get the actual function value accuracy.
242: * @return the accuracy
243: */
244: public double getFunctionValueAccuracy() {
245: return functionValueAccuracy;
246: }
247:
248: /**
249: * Reset the actual function accuracy to the default.
250: */
251: public void resetFunctionValueAccuracy() {
252: functionValueAccuracy = defaultFunctionValueAccuracy;
253: }
254:
255: /**
256: * Returns true iff the function takes opposite signs at the endpoints.
257: *
258: * @param lower the lower endpoint
259: * @param upper the upper endpoint
260: * @param f the function
261: * @return true if f(lower) * f(upper) < 0
262: * @throws FunctionEvaluationException if an error occurs evaluating the
263: * function at the endpoints
264: */
265: protected boolean isBracketing(double lower, double upper,
266: UnivariateRealFunction f)
267: throws FunctionEvaluationException {
268: double f1 = f.value(lower);
269: double f2 = f.value(upper);
270: return ((f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0));
271: }
272:
273: /**
274: * Returns true if the arguments form a (strictly) increasing sequence
275: *
276: * @param start first number
277: * @param mid second number
278: * @param end third number
279: * @return true if the arguments form an increasing sequence
280: */
281: protected boolean isSequence(double start, double mid, double end) {
282: return (start < mid) && (mid < end);
283: }
284:
285: /**
286: * Verifies that the endpoints specify an interval,
287: * throws IllegalArgumentException if not
288: *
289: * @param lower lower endpoint
290: * @param upper upper endpoint
291: * @throws IllegalArgumentException
292: */
293: protected void verifyInterval(double lower, double upper) {
294: if (lower >= upper) {
295: throw new IllegalArgumentException(
296: "Endpoints do not specify an interval: [" + lower
297: + "," + upper + "]");
298: }
299: }
300:
301: /**
302: * Verifies that <code>lower < initial < upper</code>
303: * throws IllegalArgumentException if not
304: *
305: * @param lower lower endpoint
306: * @param initial initial value
307: * @param upper upper endpoint
308: * @throws IllegalArgumentException
309: */
310: protected void verifySequence(double lower, double initial,
311: double upper) {
312: if (!isSequence(lower, initial, upper)) {
313: throw new IllegalArgumentException(
314: "Invalid interval, initial value parameters: lower="
315: + lower + " initial=" + initial + " upper="
316: + upper);
317: }
318: }
319:
320: /**
321: * Verifies that the endpoints specify an interval and the function takes
322: * opposite signs at the enpoints, throws IllegalArgumentException if not
323: *
324: * @param lower lower endpoint
325: * @param upper upper endpoint
326: * @param f function
327: * @throws IllegalArgumentException
328: * @throws FunctionEvaluationException if an error occurs evaluating the
329: * function at the endpoints
330: */
331: protected void verifyBracketing(double lower, double upper,
332: UnivariateRealFunction f)
333: throws FunctionEvaluationException {
334:
335: verifyInterval(lower, upper);
336: if (!isBracketing(lower, upper, f)) {
337: throw new IllegalArgumentException(
338: "Function values at endpoints do not have different signs."
339: + " Endpoints: [" + lower + "," + upper
340: + "]" + " Values: [" + f.value(lower)
341: + "," + f.value(upper) + "]");
342: }
343: }
344: }
|