blob: fadb1d003ef0c3ae1916b087e963eeb3cc476825 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.math4.analysis.integration;
import org.apache.commons.math4.analysis.UnivariateFunction;
import org.apache.commons.math4.analysis.solvers.UnivariateSolverUtils;
import org.apache.commons.math4.exception.MaxCountExceededException;
import org.apache.commons.math4.exception.NotStrictlyPositiveException;
import org.apache.commons.math4.exception.NumberIsTooSmallException;
import org.apache.commons.math4.exception.TooManyEvaluationsException;
import org.apache.commons.math4.util.IntegerSequence;
import org.apache.commons.math4.util.MathUtils;
/**
* Provide a default implementation for several generic functions.
*
* @since 1.2
*/
public abstract class BaseAbstractUnivariateIntegrator implements UnivariateIntegrator {
/** Default absolute accuracy. */
public static final double DEFAULT_ABSOLUTE_ACCURACY = 1.0e-15;
/** Default relative accuracy. */
public static final double DEFAULT_RELATIVE_ACCURACY = 1.0e-6;
/** Default minimal iteration count. */
public static final int DEFAULT_MIN_ITERATIONS_COUNT = 3;
/** Default maximal iteration count. */
public static final int DEFAULT_MAX_ITERATIONS_COUNT = Integer.MAX_VALUE;
/** Maximum absolute error. */
private final double absoluteAccuracy;
/** Maximum relative error. */
private final double relativeAccuracy;
/** minimum number of iterations */
private final int minimalIterationCount;
/** maximum number of iterations */
private final int maximalIterationCount;
/** The iteration count. */
protected IntegerSequence.Incrementor iterations;
/** The functions evaluation count. */
private IntegerSequence.Incrementor evaluations;
/** Function to integrate. */
private UnivariateFunction function;
/** Lower bound for the interval. */
private double min;
/** Upper bound for the interval. */
private double max;
/**
* Construct an integrator with given accuracies and iteration counts.
* <p>
* The meanings of the various parameters are:
* <ul>
* <li>relative accuracy:
* this is used to stop iterations if the absolute accuracy can't be
* achieved due to large values or short mantissa length. If this
* should be the primary criterion for convergence rather then a
* safety measure, set the absolute accuracy to a ridiculously small value,
* like {@link org.apache.commons.numbers.core.Precision#SAFE_MIN Precision.SAFE_MIN}.</li>
* <li>absolute accuracy:
* The default is usually chosen so that results in the interval
* -10..-0.1 and +0.1..+10 can be found with a reasonable accuracy. If the
* expected absolute value of your results is of much smaller magnitude, set
* this to a smaller value.</li>
* <li>minimum number of iterations:
* minimal iteration is needed to avoid false early convergence, e.g.
* the sample points happen to be zeroes of the function. Users can
* use the default value or choose one that they see as appropriate.</li>
* <li>maximum number of iterations:
* usually a high iteration count indicates convergence problems. However,
* the "reasonable value" varies widely for different algorithms. Users are
* advised to use the default value supplied by the algorithm.</li>
* </ul>
*
* @param relativeAccuracy relative accuracy of the result
* @param absoluteAccuracy absolute accuracy of the result
* @param minimalIterationCount minimum number of iterations
* @param maximalIterationCount maximum number of iterations
* @exception NotStrictlyPositiveException if minimal number of iterations
* is not strictly positive
* @exception NumberIsTooSmallException if maximal number of iterations
* is lesser than or equal to the minimal number of iterations
*/
protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy,
final double absoluteAccuracy,
final int minimalIterationCount,
final int maximalIterationCount) {
// accuracy settings
this.relativeAccuracy = relativeAccuracy;
this.absoluteAccuracy = absoluteAccuracy;
// iterations count settings
if (minimalIterationCount <= 0) {
throw new NotStrictlyPositiveException(minimalIterationCount);
}
if (maximalIterationCount <= minimalIterationCount) {
throw new NumberIsTooSmallException(maximalIterationCount, minimalIterationCount, false);
}
this.minimalIterationCount = minimalIterationCount;
this.maximalIterationCount = maximalIterationCount;
}
/**
* Construct an integrator with given accuracies.
* @param relativeAccuracy relative accuracy of the result
* @param absoluteAccuracy absolute accuracy of the result
*/
protected BaseAbstractUnivariateIntegrator(final double relativeAccuracy,
final double absoluteAccuracy) {
this(relativeAccuracy, absoluteAccuracy,
DEFAULT_MIN_ITERATIONS_COUNT, DEFAULT_MAX_ITERATIONS_COUNT);
}
/**
* Construct an integrator with given iteration counts.
* @param minimalIterationCount minimum number of iterations
* @param maximalIterationCount maximum number of iterations
* @exception NotStrictlyPositiveException if minimal number of iterations
* is not strictly positive
* @exception NumberIsTooSmallException if maximal number of iterations
* is lesser than or equal to the minimal number of iterations
*/
protected BaseAbstractUnivariateIntegrator(final int minimalIterationCount,
final int maximalIterationCount) {
this(DEFAULT_RELATIVE_ACCURACY, DEFAULT_ABSOLUTE_ACCURACY,
minimalIterationCount, maximalIterationCount);
}
/** {@inheritDoc} */
@Override
public double getRelativeAccuracy() {
return relativeAccuracy;
}
/** {@inheritDoc} */
@Override
public double getAbsoluteAccuracy() {
return absoluteAccuracy;
}
/** {@inheritDoc} */
@Override
public int getMinimalIterationCount() {
return minimalIterationCount;
}
/** {@inheritDoc} */
@Override
public int getMaximalIterationCount() {
return iterations.getMaximalCount();
}
/** {@inheritDoc} */
@Override
public int getEvaluations() {
return evaluations.getCount();
}
/** {@inheritDoc} */
@Override
public int getIterations() {
return iterations.getCount();
}
/**
* @return the lower bound.
*/
protected double getMin() {
return min;
}
/**
* @return the upper bound.
*/
protected double getMax() {
return max;
}
/**
* Compute the objective function value.
*
* @param point Point at which the objective function must be evaluated.
* @return the objective function value at specified point.
* @throws TooManyEvaluationsException if the maximal number of function
* evaluations is exceeded.
*/
protected double computeObjectiveValue(final double point) {
try {
evaluations.increment();
} catch (MaxCountExceededException e) {
throw new TooManyEvaluationsException(e.getMax());
}
return function.value(point);
}
/**
* Prepare for computation.
* Subclasses must call this method if they the {@code integrate} method.
*
* @param maxEval Maximum number of evaluations.
* @param f the integrand function
* @param lower the min bound for the interval
* @param upper the upper bound for the interval
* @throws org.apache.commons.math4.exception.NullArgumentException
* if {@code f} is {@code null}.
* @throws org.apache.commons.math4.exception.MathIllegalArgumentException
* if {@code min >= max}.
*/
protected void setup(final int maxEval,
final UnivariateFunction f,
final double lower, final double upper) {
// Checks.
MathUtils.checkNotNull(f);
UnivariateSolverUtils.verifyInterval(lower, upper);
// Reset.
min = lower;
max = upper;
function = f;
iterations = IntegerSequence.Incrementor.create()
.withMaximalCount(maximalIterationCount);
evaluations = IntegerSequence.Incrementor.create()
.withMaximalCount(maxEval);
}
/** {@inheritDoc} */
@Override
public double integrate(final int maxEval, final UnivariateFunction f,
final double lower, final double upper) {
// Initialization.
setup(maxEval, f, lower, upper);
// Perform computation.
return doIntegrate();
}
/**
* Method for implementing actual integration algorithms in derived
* classes.
*
* @return the root.
* @throws TooManyEvaluationsException if the maximal number of evaluations
* is exceeded.
* @throws MaxCountExceededException if the maximum iteration count is exceeded
* or the integrator detects convergence problems otherwise
*/
protected abstract double doIntegrate() ;
}