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 23 package org.hipparchus.analysis.solvers; 24 25 import org.hipparchus.analysis.UnivariateFunction; 26 import org.hipparchus.exception.MathIllegalArgumentException; 27 import org.hipparchus.exception.MathIllegalStateException; 28 import org.hipparchus.exception.NullArgumentException; 29 import org.hipparchus.util.Incrementor; 30 import org.hipparchus.util.MathUtils; 31 32 /** 33 * Provide a default implementation for several functions useful to generic 34 * solvers. 35 * The default values for relative and function tolerances are 1e-14 36 * and 1e-15, respectively. It is however highly recommended to not 37 * rely on the default, but rather carefully consider values that match 38 * user's expectations, as well as the specifics of each implementation. 39 * 40 * @param <F> Type of function to solve. 41 * 42 */ 43 public abstract class BaseAbstractUnivariateSolver<F extends UnivariateFunction> 44 implements BaseUnivariateSolver<F> { 45 /** Default relative accuracy. */ 46 private static final double DEFAULT_RELATIVE_ACCURACY = 1e-14; 47 /** Default function value accuracy. */ 48 private static final double DEFAULT_FUNCTION_VALUE_ACCURACY = 1e-15; 49 /** Function value accuracy. */ 50 private final double functionValueAccuracy; 51 /** Absolute accuracy. */ 52 private final double absoluteAccuracy; 53 /** Relative accuracy. */ 54 private final double relativeAccuracy; 55 /** Evaluations counter. */ 56 private Incrementor evaluations; 57 /** Lower end of search interval. */ 58 private double searchMin; 59 /** Higher end of search interval. */ 60 private double searchMax; 61 /** Initial guess. */ 62 private double searchStart; 63 /** Function to solve. */ 64 private F function; 65 66 /** 67 * Construct a solver with given absolute accuracy. 68 * 69 * @param absoluteAccuracy Maximum absolute error. 70 */ 71 protected BaseAbstractUnivariateSolver(final double absoluteAccuracy) { 72 this(DEFAULT_RELATIVE_ACCURACY, 73 absoluteAccuracy, 74 DEFAULT_FUNCTION_VALUE_ACCURACY); 75 } 76 77 /** 78 * Construct a solver with given accuracies. 79 * 80 * @param relativeAccuracy Maximum relative error. 81 * @param absoluteAccuracy Maximum absolute error. 82 */ 83 protected BaseAbstractUnivariateSolver(final double relativeAccuracy, 84 final double absoluteAccuracy) { 85 this(relativeAccuracy, 86 absoluteAccuracy, 87 DEFAULT_FUNCTION_VALUE_ACCURACY); 88 } 89 90 /** 91 * Construct a solver with given accuracies. 92 * 93 * @param relativeAccuracy Maximum relative error. 94 * @param absoluteAccuracy Maximum absolute error. 95 * @param functionValueAccuracy Maximum function value error. 96 */ 97 protected BaseAbstractUnivariateSolver(final double relativeAccuracy, 98 final double absoluteAccuracy, 99 final double functionValueAccuracy) { 100 this.absoluteAccuracy = absoluteAccuracy; 101 this.relativeAccuracy = relativeAccuracy; 102 this.functionValueAccuracy = functionValueAccuracy; 103 this.evaluations = new Incrementor(); 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 public int getEvaluations() { 109 return evaluations.getCount(); 110 } 111 /** Get lower end of the search interval. 112 * @return the lower end of the search interval 113 */ 114 public double getMin() { 115 return searchMin; 116 } 117 /** Get higher end of the search interval. 118 * @return the higher end of the search interval 119 */ 120 public double getMax() { 121 return searchMax; 122 } 123 /** Get initial guess. 124 * @return the initial guess 125 */ 126 public double getStartValue() { 127 return searchStart; 128 } 129 /** 130 * {@inheritDoc} 131 */ 132 @Override 133 public double getAbsoluteAccuracy() { 134 return absoluteAccuracy; 135 } 136 /** 137 * {@inheritDoc} 138 */ 139 @Override 140 public double getRelativeAccuracy() { 141 return relativeAccuracy; 142 } 143 /** 144 * {@inheritDoc} 145 */ 146 @Override 147 public double getFunctionValueAccuracy() { 148 return functionValueAccuracy; 149 } 150 151 /** 152 * Compute the objective function value. 153 * 154 * @param point Point at which the objective function must be evaluated. 155 * @return the objective function value at specified point. 156 * @throws MathIllegalStateException if the maximal number of evaluations 157 * is exceeded. 158 */ 159 protected double computeObjectiveValue(double point) 160 throws MathIllegalStateException { 161 incrementEvaluationCount(); 162 return function.value(point); 163 } 164 165 /** 166 * Prepare for computation. 167 * Subclasses must call this method if they override any of the 168 * {@code solve} methods. 169 * 170 * @param f Function to solve. 171 * @param min Lower bound for the interval. 172 * @param max Upper bound for the interval. 173 * @param startValue Start value to use. 174 * @param maxEval Maximum number of evaluations. 175 * @exception NullArgumentException if f is null 176 */ 177 protected void setup(int maxEval, 178 F f, 179 double min, double max, 180 double startValue) 181 throws NullArgumentException { 182 // Checks. 183 MathUtils.checkNotNull(f); 184 185 // Reset. 186 searchMin = min; 187 searchMax = max; 188 searchStart = startValue; 189 function = f; 190 evaluations = evaluations.withMaximalCount(maxEval); 191 } 192 193 /** {@inheritDoc} */ 194 @Override 195 public double solve(int maxEval, F f, double min, double max, double startValue) 196 throws MathIllegalArgumentException, MathIllegalStateException { 197 // Initialization. 198 setup(maxEval, f, min, max, startValue); 199 200 // Perform computation. 201 return doSolve(); 202 } 203 204 /** {@inheritDoc} */ 205 @Override 206 public double solve(int maxEval, F f, double min, double max) { 207 return solve(maxEval, f, min, max, min + 0.5 * (max - min)); 208 } 209 210 /** {@inheritDoc} */ 211 @Override 212 public double solve(int maxEval, F f, double startValue) 213 throws MathIllegalArgumentException, MathIllegalStateException { 214 return solve(maxEval, f, Double.NaN, Double.NaN, startValue); 215 } 216 217 /** 218 * Method for implementing actual optimization algorithms in derived 219 * classes. 220 * 221 * @return the root. 222 * @throws MathIllegalStateException if the maximal number of evaluations 223 * is exceeded. 224 * @throws MathIllegalArgumentException if the initial search interval does not bracket 225 * a root and the solver requires it. 226 */ 227 protected abstract double doSolve() 228 throws MathIllegalArgumentException, MathIllegalStateException; 229 230 /** 231 * Check whether the function takes opposite signs at the endpoints. 232 * 233 * @param lower Lower endpoint. 234 * @param upper Upper endpoint. 235 * @return {@code true} if the function values have opposite signs at the 236 * given points. 237 */ 238 protected boolean isBracketing(final double lower, 239 final double upper) { 240 return UnivariateSolverUtils.isBracketing(function, lower, upper); 241 } 242 243 /** 244 * Check whether the arguments form a (strictly) increasing sequence. 245 * 246 * @param start First number. 247 * @param mid Second number. 248 * @param end Third number. 249 * @return {@code true} if the arguments form an increasing sequence. 250 */ 251 protected boolean isSequence(final double start, 252 final double mid, 253 final double end) { 254 return UnivariateSolverUtils.isSequence(start, mid, end); 255 } 256 257 /** 258 * Check that the endpoints specify an interval. 259 * 260 * @param lower Lower endpoint. 261 * @param upper Upper endpoint. 262 * @throws MathIllegalArgumentException if {@code lower >= upper}. 263 */ 264 protected void verifyInterval(final double lower, 265 final double upper) 266 throws MathIllegalArgumentException { 267 UnivariateSolverUtils.verifyInterval(lower, upper); 268 } 269 270 /** 271 * Check that {@code lower < initial < upper}. 272 * 273 * @param lower Lower endpoint. 274 * @param initial Initial value. 275 * @param upper Upper endpoint. 276 * @throws MathIllegalArgumentException if {@code lower >= initial} or 277 * {@code initial >= upper}. 278 */ 279 protected void verifySequence(final double lower, 280 final double initial, 281 final double upper) 282 throws MathIllegalArgumentException { 283 UnivariateSolverUtils.verifySequence(lower, initial, upper); 284 } 285 286 /** 287 * Check that the endpoints specify an interval and the function takes 288 * opposite signs at the endpoints. 289 * 290 * @param lower Lower endpoint. 291 * @param upper Upper endpoint. 292 * @throws NullArgumentException if the function has not been set. 293 * @throws MathIllegalArgumentException if the function has the same sign at 294 * the endpoints. 295 */ 296 protected void verifyBracketing(final double lower, 297 final double upper) 298 throws MathIllegalArgumentException, NullArgumentException { 299 UnivariateSolverUtils.verifyBracketing(function, lower, upper); 300 } 301 302 /** 303 * Increment the evaluation count by one. 304 * Method {@link #computeObjectiveValue(double)} calls this method internally. 305 * It is provided for subclasses that do not exclusively use 306 * {@code computeObjectiveValue} to solve the function. 307 * See e.g. {@link AbstractUnivariateDifferentiableSolver}. 308 * 309 * @throws MathIllegalStateException when the allowed number of function 310 * evaluations has been exhausted. 311 */ 312 protected void incrementEvaluationCount() 313 throws MathIllegalStateException { 314 evaluations.increment(); 315 } 316 }