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.solvers;
19  
20  import org.apache.commons.math.ConvergingAlgorithmImpl;
21  import org.apache.commons.math.FunctionEvaluationException;
22  import org.apache.commons.math.MathRuntimeException;
23  import org.apache.commons.math.analysis.UnivariateRealFunction;
24  
25  /**
26   * Provide a default implementation for several functions useful to generic
27   * solvers.
28   *  
29   * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $
30   */
31  public abstract class UnivariateRealSolverImpl
32      extends ConvergingAlgorithmImpl implements UnivariateRealSolver {
33  
34      /** Maximum error of function. */
35      protected double functionValueAccuracy;
36  
37      /** Default maximum error of function. */
38      protected double defaultFunctionValueAccuracy;
39  
40      /** Indicates where a root has been computed. */
41      protected boolean resultComputed = false;
42  
43      /** The last computed root. */
44      protected double result;
45  
46      /** Value of the function at the last computed result. */
47      protected double functionValue;
48  
49      /** The function to solve.
50       * @deprecated as of 2.0 the function to solve is passed as an argument
51       * to the {@link #solve(UnivariateRealFunction, double, double)} or
52       * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
53       * method. */
54      @Deprecated
55      protected UnivariateRealFunction f;
56  
57      /**
58       * Construct a solver with given iteration count and accuracy.
59       * 
60       * @param f the function to solve.
61       * @param defaultAbsoluteAccuracy maximum absolute error
62       * @param defaultMaximalIterationCount maximum number of iterations
63       * @throws IllegalArgumentException if f is null or the 
64       * defaultAbsoluteAccuracy is not valid
65       * @deprecated as of 2.0 the function to solve is passed as an argument
66       * to the {@link #solve(UnivariateRealFunction, double, double)} or
67       * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
68       * method.
69       */
70      @Deprecated
71      protected UnivariateRealSolverImpl(final UnivariateRealFunction f,
72                                         final int defaultMaximalIterationCount,
73                                         final double defaultAbsoluteAccuracy) {
74          super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
75          if (f == null) {
76              throw MathRuntimeException.createIllegalArgumentException("function to solve cannot be null");
77          }
78          this.f = f;
79          this.defaultFunctionValueAccuracy = 1.0e-15;
80          this.functionValueAccuracy = defaultFunctionValueAccuracy;
81      }
82  
83      /**
84       * Construct a solver with given iteration count and accuracy.
85       * 
86       * @param defaultAbsoluteAccuracy maximum absolute error
87       * @param defaultMaximalIterationCount maximum number of iterations
88       * @throws IllegalArgumentException if f is null or the 
89       * defaultAbsoluteAccuracy is not valid
90       */
91      protected UnivariateRealSolverImpl(final int defaultMaximalIterationCount,
92                                         final double defaultAbsoluteAccuracy) {
93          super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
94          this.defaultFunctionValueAccuracy = 1.0e-15;
95          this.functionValueAccuracy = defaultFunctionValueAccuracy;
96      }
97  
98      /** Check if a result has been computed.
99       * @exception IllegalStateException if no result has been computed
100      */
101     protected void checkResultComputed() throws IllegalStateException {
102         if (!resultComputed) {
103             throw MathRuntimeException.createIllegalStateException("no result available");
104         }
105     }
106 
107     /** {@inheritDoc} */
108     public double getResult() {
109         checkResultComputed();
110         return result;
111     }
112 
113     /** {@inheritDoc} */
114     public double getFunctionValue() {
115         checkResultComputed();
116         return functionValue;
117     }
118 
119     /** {@inheritDoc} */
120     public void setFunctionValueAccuracy(final double accuracy) {
121         functionValueAccuracy = accuracy;
122     }
123 
124     /** {@inheritDoc} */
125     public double getFunctionValueAccuracy() {
126         return functionValueAccuracy;
127     }
128 
129     /** {@inheritDoc} */
130     public void resetFunctionValueAccuracy() {
131         functionValueAccuracy = defaultFunctionValueAccuracy;
132     }
133 
134     /**
135      * Convenience function for implementations.
136      * 
137      * @param result the result to set
138      * @param iterationCount the iteration count to set
139      */
140     protected final void setResult(final double result, final int iterationCount) {
141         this.result         = result;
142         this.iterationCount = iterationCount;
143         this.resultComputed = true;
144     }
145 
146     /**
147      * Convenience function for implementations.
148      * 
149      * @param x the result to set
150      * @param fx the result to set
151      * @param iterationCount the iteration count to set
152      */
153     protected final void setResult(final double x, final double fx,
154                                    final int iterationCount) {
155         this.result         = x;
156         this.functionValue  = fx;
157         this.iterationCount = iterationCount;
158         this.resultComputed = true;
159     }
160 
161     /**
162      * Convenience function for implementations.
163      */
164     protected final void clearResult() {
165         this.iterationCount = 0;
166         this.resultComputed = false;
167     }
168 
169     /**
170      * Returns true iff the function takes opposite signs at the endpoints.
171      * 
172      * @param lower  the lower endpoint 
173      * @param upper  the upper endpoint
174      * @param f the function
175      * @return true if f(lower) * f(upper) < 0
176      * @throws FunctionEvaluationException if an error occurs evaluating the 
177      * function at the endpoints
178      */
179     protected boolean isBracketing(final double lower, final double upper, 
180                                    final UnivariateRealFunction f)
181         throws FunctionEvaluationException {
182         final double f1 = f.value(lower);
183         final double f2 = f.value(upper);
184         return ((f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0));
185     }
186     
187     /**
188      * Returns true if the arguments form a (strictly) increasing sequence
189      * 
190      * @param start  first number
191      * @param mid   second number
192      * @param end  third number
193      * @return true if the arguments form an increasing sequence
194      */
195     protected boolean isSequence(final double start, final double mid, final double end) {
196         return (start < mid) && (mid < end);
197     }
198     
199     /**
200      * Verifies that the endpoints specify an interval, 
201      * throws IllegalArgumentException if not
202      * 
203      * @param lower  lower endpoint
204      * @param upper upper endpoint
205      * @throws IllegalArgumentException
206      */
207     protected void verifyInterval(final double lower, final double upper) {
208         if (lower >= upper) {
209             throw MathRuntimeException.createIllegalArgumentException(
210                     "endpoints do not specify an interval: [{0}, {1}]",
211                     lower, upper);
212         }       
213     }
214     
215     /**
216      * Verifies that <code>lower < initial < upper</code>
217      * throws IllegalArgumentException if not
218      * 
219      * @param lower  lower endpoint
220      * @param initial initial value
221      * @param upper upper endpoint
222      * @throws IllegalArgumentException
223      */
224     protected void verifySequence(final double lower, final double initial, final double upper) {
225         if (!isSequence(lower, initial, upper)) {
226             throw MathRuntimeException.createIllegalArgumentException(
227                     "invalid interval, initial value parameters:  lower={0}, initial={1}, upper={2}",
228                     lower, initial, upper);
229         }       
230     }
231     
232     /**
233      * Verifies that the endpoints specify an interval and the function takes
234      * opposite signs at the enpoints, throws IllegalArgumentException if not
235      * 
236      * @param lower  lower endpoint
237      * @param upper upper endpoint
238      * @param f function
239      * @throws IllegalArgumentException
240      * @throws FunctionEvaluationException if an error occurs evaluating the 
241      * function at the endpoints
242      */
243     protected void verifyBracketing(final double lower, final double upper, 
244                                     final UnivariateRealFunction f)
245         throws FunctionEvaluationException {
246         
247         verifyInterval(lower, upper);
248         if (!isBracketing(lower, upper, f)) {
249             throw MathRuntimeException.createIllegalArgumentException(
250                     "function values at endpoints do not have different signs.  " +
251                     "Endpoints: [{0}, {1}], Values: [{2}, {3}]",
252                     lower, upper, f.value(lower), f.value(upper));       
253         }
254     }
255 }