| /* |
| * 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.legacy.analysis.solvers; |
| |
| import org.apache.commons.math4.legacy.analysis.UnivariateFunction; |
| import org.apache.commons.math4.legacy.exception.NullArgumentException; |
| import org.apache.commons.math4.legacy.exception.MaxCountExceededException; |
| import org.apache.commons.math4.legacy.exception.TooManyEvaluationsException; |
| import org.apache.commons.math4.legacy.core.IntegerSequence; |
| |
| /** |
| * Provide a default implementation for several functions useful to generic |
| * solvers. |
| * The default values for relative and function tolerances are 1e-14 |
| * and 1e-15, respectively. It is however highly recommended to not |
| * rely on the default, but rather carefully consider values that match |
| * user's expectations, as well as the specifics of each implementation. |
| * |
| * @param <FUNC> Type of function to solve. |
| * |
| * @since 2.0 |
| */ |
| public abstract class BaseAbstractUnivariateSolver<FUNC extends UnivariateFunction> |
| implements BaseUnivariateSolver<FUNC> { |
| /** Default relative accuracy. */ |
| private static final double DEFAULT_RELATIVE_ACCURACY = 1e-14; |
| /** Default function value accuracy. */ |
| private static final double DEFAULT_FUNCTION_VALUE_ACCURACY = 1e-15; |
| /** Function value accuracy. */ |
| private final double functionValueAccuracy; |
| /** Absolute accuracy. */ |
| private final double absoluteAccuracy; |
| /** Relative accuracy. */ |
| private final double relativeAccuracy; |
| /** Evaluations counter. */ |
| private IntegerSequence.Incrementor evaluations; |
| /** Lower end of search interval. */ |
| private double searchMin; |
| /** Higher end of search interval. */ |
| private double searchMax; |
| /** Initial guess. */ |
| private double searchStart; |
| /** Function to solve. */ |
| private FUNC function; |
| |
| /** |
| * Construct a solver with given absolute accuracy. |
| * |
| * @param absoluteAccuracy Maximum absolute error. |
| */ |
| protected BaseAbstractUnivariateSolver(final double absoluteAccuracy) { |
| this(DEFAULT_RELATIVE_ACCURACY, |
| absoluteAccuracy, |
| DEFAULT_FUNCTION_VALUE_ACCURACY); |
| } |
| |
| /** |
| * Construct a solver with given accuracies. |
| * |
| * @param relativeAccuracy Maximum relative error. |
| * @param absoluteAccuracy Maximum absolute error. |
| */ |
| protected BaseAbstractUnivariateSolver(final double relativeAccuracy, |
| final double absoluteAccuracy) { |
| this(relativeAccuracy, |
| absoluteAccuracy, |
| DEFAULT_FUNCTION_VALUE_ACCURACY); |
| } |
| |
| /** |
| * Construct a solver with given accuracies. |
| * |
| * @param relativeAccuracy Maximum relative error. |
| * @param absoluteAccuracy Maximum absolute error. |
| * @param functionValueAccuracy Maximum function value error. |
| */ |
| protected BaseAbstractUnivariateSolver(final double relativeAccuracy, |
| final double absoluteAccuracy, |
| final double functionValueAccuracy) { |
| this.absoluteAccuracy = absoluteAccuracy; |
| this.relativeAccuracy = relativeAccuracy; |
| this.functionValueAccuracy = functionValueAccuracy; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public int getMaxEvaluations() { |
| return evaluations.getMaximalCount(); |
| } |
| /** {@inheritDoc} */ |
| @Override |
| public int getEvaluations() { |
| return evaluations.getCount(); |
| } |
| /** |
| * @return the lower end of the search interval. |
| */ |
| public double getMin() { |
| return searchMin; |
| } |
| /** |
| * @return the higher end of the search interval. |
| */ |
| public double getMax() { |
| return searchMax; |
| } |
| /** |
| * @return the initial guess. |
| */ |
| public double getStartValue() { |
| return searchStart; |
| } |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public double getAbsoluteAccuracy() { |
| return absoluteAccuracy; |
| } |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public double getRelativeAccuracy() { |
| return relativeAccuracy; |
| } |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public double getFunctionValueAccuracy() { |
| return functionValueAccuracy; |
| } |
| |
| /** |
| * 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 evaluations |
| * is exceeded. |
| */ |
| protected double computeObjectiveValue(double point) { |
| incrementEvaluationCount(); |
| return function.value(point); |
| } |
| |
| /** |
| * Prepare for computation. |
| * Subclasses must call this method if they override any of the |
| * {@code solve} methods. |
| * |
| * @param f Function to solve. |
| * @param min Lower bound for the interval. |
| * @param max Upper bound for the interval. |
| * @param startValue Start value to use. |
| * @param maxEval Maximum number of evaluations. |
| * @throws NullArgumentException if {@code f} is {@code null}. |
| */ |
| protected void setup(int maxEval, |
| FUNC f, |
| double min, double max, |
| double startValue) { |
| // Checks. |
| NullArgumentException.check(f); |
| |
| // Reset. |
| searchMin = min; |
| searchMax = max; |
| searchStart = startValue; |
| function = f; |
| evaluations = IntegerSequence.Incrementor.create() |
| .withMaximalCount(maxEval); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double solve(int maxEval, FUNC f, double min, double max, double startValue) { |
| // Initialization. |
| setup(maxEval, f, min, max, startValue); |
| |
| // Perform computation. |
| return doSolve(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double solve(int maxEval, FUNC f, double min, double max) { |
| return solve(maxEval, f, min, max, min + 0.5 * (max - min)); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public double solve(int maxEval, FUNC f, double startValue) { |
| return solve(maxEval, f, Double.NaN, Double.NaN, startValue); |
| } |
| |
| /** |
| * Method for implementing actual optimization algorithms in derived |
| * classes. |
| * |
| * @return the root. |
| * @throws TooManyEvaluationsException if the maximal number of evaluations |
| * is exceeded. |
| * @throws org.apache.commons.math4.legacy.exception.NoBracketingException |
| * if the initial search interval does not bracket a root and the |
| * solver requires it. |
| */ |
| protected abstract double doSolve(); |
| |
| /** |
| * Check whether the function takes opposite signs at the endpoints. |
| * |
| * @param lower Lower endpoint. |
| * @param upper Upper endpoint. |
| * @return {@code true} if the function values have opposite signs at the |
| * given points. |
| */ |
| protected boolean isBracketing(final double lower, |
| final double upper) { |
| return UnivariateSolverUtils.isBracketing(function, lower, upper); |
| } |
| |
| /** |
| * Check whether the arguments form a (strictly) increasing sequence. |
| * |
| * @param start First number. |
| * @param mid Second number. |
| * @param end Third number. |
| * @return {@code true} if the arguments form an increasing sequence. |
| */ |
| protected boolean isSequence(final double start, |
| final double mid, |
| final double end) { |
| return UnivariateSolverUtils.isSequence(start, mid, end); |
| } |
| |
| /** |
| * Check that the endpoints specify an interval. |
| * |
| * @param lower Lower endpoint. |
| * @param upper Upper endpoint. |
| * @throws org.apache.commons.math4.legacy.exception.NumberIsTooLargeException |
| * if {@code lower >= upper}. |
| */ |
| protected void verifyInterval(final double lower, |
| final double upper) { |
| UnivariateSolverUtils.verifyInterval(lower, upper); |
| } |
| |
| /** |
| * Check that {@code lower < initial < upper}. |
| * |
| * @param lower Lower endpoint. |
| * @param initial Initial value. |
| * @param upper Upper endpoint. |
| * @throws org.apache.commons.math4.legacy.exception.NumberIsTooLargeException |
| * if {@code lower >= initial} or {@code initial >= upper}. |
| */ |
| protected void verifySequence(final double lower, |
| final double initial, |
| final double upper) { |
| UnivariateSolverUtils.verifySequence(lower, initial, upper); |
| } |
| |
| /** |
| * Check that the endpoints specify an interval and the function takes |
| * opposite signs at the endpoints. |
| * |
| * @param lower Lower endpoint. |
| * @param upper Upper endpoint. |
| * @throws NullArgumentException if the function has not been set. |
| * @throws org.apache.commons.math4.legacy.exception.NoBracketingException |
| * if the function has the same sign at the endpoints. |
| */ |
| protected void verifyBracketing(final double lower, |
| final double upper) { |
| UnivariateSolverUtils.verifyBracketing(function, lower, upper); |
| } |
| |
| /** |
| * Increment the evaluation count by one. |
| * Method {@link #computeObjectiveValue(double)} calls this method internally. |
| * It is provided for subclasses that do not exclusively use |
| * {@code computeObjectiveValue} to solve the function. |
| * See e.g. {@link AbstractUnivariateDifferentiableSolver}. |
| * |
| * @throws TooManyEvaluationsException when the allowed number of function |
| * evaluations has been exhausted. |
| */ |
| protected void incrementEvaluationCount() { |
| try { |
| evaluations.increment(); |
| } catch (MaxCountExceededException e) { |
| throw new TooManyEvaluationsException(e.getMax()); |
| } |
| } |
| } |