RiddersSolver.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.analysis.solvers;

  22. import org.hipparchus.exception.MathIllegalArgumentException;
  23. import org.hipparchus.exception.MathIllegalStateException;
  24. import org.hipparchus.util.FastMath;

  25. /**
  26.  * Implements the <a href="http://mathworld.wolfram.com/RiddersMethod.html">
  27.  * Ridders' Method</a> for root finding of real univariate functions. For
  28.  * reference, see C. Ridders, <i>A new algorithm for computing a single root
  29.  * of a real continuous function </i>, IEEE Transactions on Circuits and
  30.  * Systems, 26 (1979), 979 - 980.
  31.  * <p>
  32.  * The function should be continuous but not necessarily smooth.</p>
  33.  *
  34.  */
  35. public class RiddersSolver extends AbstractUnivariateSolver {
  36.     /** Default absolute accuracy. */
  37.     private static final double DEFAULT_ABSOLUTE_ACCURACY = 1e-6;

  38.     /**
  39.      * Construct a solver with default accuracy (1e-6).
  40.      */
  41.     public RiddersSolver() {
  42.         this(DEFAULT_ABSOLUTE_ACCURACY);
  43.     }
  44.     /**
  45.      * Construct a solver.
  46.      *
  47.      * @param absoluteAccuracy Absolute accuracy.
  48.      */
  49.     public RiddersSolver(double absoluteAccuracy) {
  50.         super(absoluteAccuracy);
  51.     }
  52.     /**
  53.      * Construct a solver.
  54.      *
  55.      * @param relativeAccuracy Relative accuracy.
  56.      * @param absoluteAccuracy Absolute accuracy.
  57.      */
  58.     public RiddersSolver(double relativeAccuracy,
  59.                          double absoluteAccuracy) {
  60.         super(relativeAccuracy, absoluteAccuracy);
  61.     }

  62.     /**
  63.      * {@inheritDoc}
  64.      */
  65.     @Override
  66.     protected double doSolve()
  67.         throws MathIllegalArgumentException, MathIllegalStateException {
  68.         double min = getMin();
  69.         double max = getMax();
  70.         // [x1, x2] is the bracketing interval in each iteration
  71.         // x3 is the midpoint of [x1, x2]
  72.         // x is the new root approximation and an endpoint of the new interval
  73.         double x1 = min;
  74.         double y1 = computeObjectiveValue(x1);
  75.         double x2 = max;
  76.         double y2 = computeObjectiveValue(x2);

  77.         // check for zeros before verifying bracketing
  78.         if (y1 == 0) {
  79.             return min;
  80.         }
  81.         if (y2 == 0) {
  82.             return max;
  83.         }
  84.         verifyBracketing(min, max);

  85.         final double absoluteAccuracy = getAbsoluteAccuracy();
  86.         final double functionValueAccuracy = getFunctionValueAccuracy();
  87.         final double relativeAccuracy = getRelativeAccuracy();

  88.         double oldx = Double.POSITIVE_INFINITY;
  89.         while (true) {
  90.             // calculate the new root approximation
  91.             final double x3 = 0.5 * (x1 + x2);
  92.             final double y3 = computeObjectiveValue(x3);
  93.             if (FastMath.abs(y3) <= functionValueAccuracy) {
  94.                 return x3;
  95.             }
  96.             final double delta = 1 - (y1 * y2) / (y3 * y3);  // delta > 1 due to bracketing
  97.             final double correction = (FastMath.signum(y2) * FastMath.signum(y3)) *
  98.                                       (x3 - x1) / FastMath.sqrt(delta);
  99.             final double x = x3 - correction;                // correction != 0
  100.             final double y = computeObjectiveValue(x);

  101.             // check for convergence
  102.             final double tolerance = FastMath.max(relativeAccuracy * FastMath.abs(x), absoluteAccuracy);
  103.             if (FastMath.abs(x - oldx) <= tolerance) {
  104.                 return x;
  105.             }
  106.             if (FastMath.abs(y) <= functionValueAccuracy) {
  107.                 return x;
  108.             }

  109.             // prepare the new interval for next iteration
  110.             // Ridders' method guarantees x1 < x < x2
  111.             if (correction > 0.0) {             // x1 < x < x3
  112.                 if (FastMath.signum(y1) + FastMath.signum(y) == 0.0) {
  113.                     x2 = x;
  114.                     y2 = y;
  115.                 } else {
  116.                     x1 = x;
  117.                     x2 = x3;
  118.                     y1 = y;
  119.                     y2 = y3;
  120.                 }
  121.             } else {                            // x3 < x < x2
  122.                 if (FastMath.signum(y2) + FastMath.signum(y) == 0.0) {
  123.                     x1 = x;
  124.                     y1 = y;
  125.                 } else {
  126.                     x1 = x3;
  127.                     x2 = x;
  128.                     y1 = y3;
  129.                     y2 = y;
  130.                 }
  131.             }
  132.             oldx = x;
  133.         }
  134.     }
  135. }