View Javadoc

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 }