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