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