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  package org.apache.commons.math4.legacy.analysis.integration;
18  
19  import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
20  import org.apache.commons.math4.legacy.analysis.solvers.UnivariateSolverUtils;
21  import org.apache.commons.math4.legacy.exception.NullArgumentException;
22  import org.apache.commons.math4.legacy.exception.MaxCountExceededException;
23  import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
24  import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
25  import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException;
26  import org.apache.commons.math4.legacy.core.IntegerSequence;
27  
28  /**
29   * Provide a default implementation for several generic functions.
30   *
31   * @since 1.2
32   */
33  public abstract class BaseAbstractUnivariateIntegrator implements UnivariateIntegrator {
34  
35      /** Default absolute accuracy. */
36      public static final double DEFAULT_ABSOLUTE_ACCURACY = 1.0e-15;
37  
38      /** Default relative accuracy. */
39      public static final double DEFAULT_RELATIVE_ACCURACY = 1.0e-6;
40  
41      /** Default minimal iteration count. */
42      public static final int DEFAULT_MIN_ITERATIONS_COUNT = 3;
43  
44      /** Default maximal iteration count. */
45      public static final int DEFAULT_MAX_ITERATIONS_COUNT = Integer.MAX_VALUE;
46  
47      /** The iteration count. */
48      protected IntegerSequence.Incrementor iterations;
49  
50      /** Maximum absolute error. */
51      private final double absoluteAccuracy;
52  
53      /** Maximum relative error. */
54      private final double relativeAccuracy;
55  
56      /** minimum number of iterations. */
57      private final int minimalIterationCount;
58      /** maximum number of iterations. */
59      private final int maximalIterationCount;
60  
61      /** The functions evaluation count. */
62      private IntegerSequence.Incrementor evaluations;
63  
64      /** Function to integrate. */
65      private UnivariateFunction function;
66  
67      /** Lower bound for the interval. */
68      private double min;
69  
70      /** Upper bound for the interval. */
71      private double max;
72  
73      /**
74       * Construct an integrator with given accuracies and iteration counts.
75       * <p>
76       * The meanings of the various parameters are:
77       * <ul>
78       *   <li>relative accuracy:
79       *       this is used to stop iterations if the absolute accuracy can't be
80       *       achieved due to large values or short mantissa length. If this
81       *       should be the primary criterion for convergence rather then a
82       *       safety measure, set the absolute accuracy to a ridiculously small value,
83       *       like {@link org.apache.commons.numbers.core.Precision#SAFE_MIN Precision.SAFE_MIN}.</li>
84       *   <li>absolute accuracy:
85       *       The default is usually chosen so that results in the interval
86       *       -10..-0.1 and +0.1..+10 can be found with a reasonable accuracy. If the
87       *       expected absolute value of your results is of much smaller magnitude, set
88       *       this to a smaller value.</li>
89       *   <li>minimum number of iterations:
90       *       minimal iteration is needed to avoid false early convergence, e.g.
91       *       the sample points happen to be zeroes of the function. Users can
92       *       use the default value or choose one that they see as appropriate.</li>
93       *   <li>maximum number of iterations:
94       *       usually a high iteration count indicates convergence problems. However,
95       *       the "reasonable value" varies widely for different algorithms. Users are
96       *       advised to use the default value supplied by the algorithm.</li>
97       * </ul>
98       *
99       * @param relativeAccuracy relative accuracy of the result
100      * @param absoluteAccuracy absolute accuracy of the result
101      * @param minimalIterationCount minimum number of iterations
102      * @param maximalIterationCount maximum number of iterations
103      * @exception NotStrictlyPositiveException if minimal number of iterations
104      * is not strictly positive
105      * @exception NumberIsTooSmallException if maximal number of iterations
106      * is lesser than or equal to the minimal number of iterations
107      */
108     protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy,
109                                                final double absoluteAccuracy,
110                                                final int minimalIterationCount,
111                                                final int maximalIterationCount) {
112         // accuracy settings
113         this.relativeAccuracy      = relativeAccuracy;
114         this.absoluteAccuracy      = absoluteAccuracy;
115 
116         // iterations count settings
117         if (minimalIterationCount <= 0) {
118             throw new NotStrictlyPositiveException(minimalIterationCount);
119         }
120         if (maximalIterationCount <= minimalIterationCount) {
121             throw new NumberIsTooSmallException(maximalIterationCount, minimalIterationCount, false);
122         }
123         this.minimalIterationCount = minimalIterationCount;
124         this.maximalIterationCount = maximalIterationCount;
125     }
126 
127     /**
128      * Construct an integrator with given accuracies.
129      * @param relativeAccuracy relative accuracy of the result
130      * @param absoluteAccuracy absolute accuracy of the result
131      */
132     protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy,
133                                                final double absoluteAccuracy) {
134         this(relativeAccuracy, absoluteAccuracy,
135              DEFAULT_MIN_ITERATIONS_COUNT, DEFAULT_MAX_ITERATIONS_COUNT);
136     }
137 
138     /**
139      * Construct an integrator with given iteration counts.
140      * @param minimalIterationCount minimum number of iterations
141      * @param maximalIterationCount maximum number of iterations
142      * @exception NotStrictlyPositiveException if minimal number of iterations
143      * is not strictly positive
144      * @exception NumberIsTooSmallException if maximal number of iterations
145      * is lesser than or equal to the minimal number of iterations
146      */
147     protected BaseAbstractUnivariateIntegrator(final int minimalIterationCount,
148                                                final int maximalIterationCount) {
149         this(DEFAULT_RELATIVE_ACCURACY, DEFAULT_ABSOLUTE_ACCURACY,
150              minimalIterationCount, maximalIterationCount);
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public double getRelativeAccuracy() {
156         return relativeAccuracy;
157     }
158 
159     /** {@inheritDoc} */
160     @Override
161     public double getAbsoluteAccuracy() {
162         return absoluteAccuracy;
163     }
164 
165     /** {@inheritDoc} */
166     @Override
167     public int getMinimalIterationCount() {
168         return minimalIterationCount;
169     }
170 
171     /** {@inheritDoc} */
172     @Override
173     public int getMaximalIterationCount() {
174         return iterations.getMaximalCount();
175     }
176 
177     /** {@inheritDoc} */
178     @Override
179     public int getEvaluations() {
180         return evaluations.getCount();
181     }
182 
183     /** {@inheritDoc} */
184     @Override
185     public int getIterations() {
186         return iterations.getCount();
187     }
188 
189     /**
190      * @return the lower bound.
191      */
192     protected double getMin() {
193         return min;
194     }
195     /**
196      * @return the upper bound.
197      */
198     protected double getMax() {
199         return max;
200     }
201 
202     /**
203      * Compute the objective function value.
204      *
205      * @param point Point at which the objective function must be evaluated.
206      * @return the objective function value at specified point.
207      * @throws TooManyEvaluationsException if the maximal number of function
208      * evaluations is exceeded.
209      */
210     protected double computeObjectiveValue(final double point) {
211         try {
212             evaluations.increment();
213         } catch (MaxCountExceededException e) {
214             throw new TooManyEvaluationsException(e.getMax());
215         }
216         return function.value(point);
217     }
218 
219     /**
220      * Prepare for computation.
221      * Subclasses must call this method if they the {@code integrate} method.
222      *
223      * @param maxEval Maximum number of evaluations.
224      * @param f the integrand function
225      * @param lower the min bound for the interval
226      * @param upper the upper bound for the interval
227      * @throws NullArgumentException if {@code f} is {@code null}.
228      * @throws org.apache.commons.math4.legacy.exception.MathIllegalArgumentException
229      * if {@code min >= max}.
230      */
231     protected void setup(final int maxEval,
232                          final UnivariateFunction f,
233                          final double lower, final double upper) {
234 
235         // Checks.
236         NullArgumentException.check(f);
237         UnivariateSolverUtils.verifyInterval(lower, upper);
238 
239         // Reset.
240         min = lower;
241         max = upper;
242         function = f;
243         iterations = IntegerSequence.Incrementor.create()
244             .withMaximalCount(maximalIterationCount);
245         evaluations = IntegerSequence.Incrementor.create()
246             .withMaximalCount(maxEval);
247     }
248 
249     /** {@inheritDoc} */
250     @Override
251     public double integrate(final int maxEval, final UnivariateFunction f,
252                             final double lower, final double upper) {
253 
254         // Initialization.
255         setup(maxEval, f, lower, upper);
256 
257         // Perform computation.
258         return doIntegrate();
259     }
260 
261     /**
262      * Method for implementing actual integration algorithms in derived
263      * classes.
264      *
265      * @return the root.
266      * @throws TooManyEvaluationsException if the maximal number of evaluations
267      * is exceeded.
268      * @throws MaxCountExceededException if the maximum iteration count is exceeded
269      * or the integrator detects convergence problems otherwise
270      */
271     protected abstract double doIntegrate() ;
272 }