Coverage Report - org.apache.commons.math.analysis.RiddersSolver

Classes in this File Line Coverage Branch Coverage Complexity
RiddersSolver
72% 
69% 
8.667

 1  
 /*
 2  
  * Copyright 2005 The Apache Software Foundation.
 3  
  *
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.apache.commons.math.analysis;
 17  
 
 18  
 import org.apache.commons.math.ConvergenceException;
 19  
 import org.apache.commons.math.FunctionEvaluationException;
 20  
 import org.apache.commons.math.util.MathUtils;
 21  
 
 22  
 /**
 23  
  * Implements the <a href="http://mathworld.wolfram.com/RiddersMethod.html">
 24  
  * Ridders' Method</a> for root finding of real univariate functions. For
 25  
  * reference, see C. Ridders, <i>A new algorithm for computing a single root
 26  
  * of a real continuous function </i>, IEEE Transactions on Circuits and
 27  
  * Systems, 26 (1979), 979 - 980.
 28  
  * <p>
 29  
  * The function should be continuous but not necessarily smooth.
 30  
  *  
 31  
  * @version $Revision$ $Date$
 32  
  */
 33  
 public class RiddersSolver extends UnivariateRealSolverImpl {
 34  
 
 35  
     /** serializable version identifier */
 36  
     static final long serialVersionUID = -4703139035737911735L;
 37  
 
 38  
     /**
 39  
      * Construct a solver for the given function.
 40  
      * 
 41  
      * @param f function to solve
 42  
      */
 43  
     public RiddersSolver(UnivariateRealFunction f) {
 44  8
         super(f, 100, 1E-6);
 45  8
     }
 46  
 
 47  
     /**
 48  
      * Find a root in the given interval with initial value.
 49  
      * <p>
 50  
      * Requires bracketing condition.
 51  
      * 
 52  
      * @param min the lower bound for the interval
 53  
      * @param max the upper bound for the interval
 54  
      * @param initial the start value to use
 55  
      * @return the point at which the function value is zero
 56  
      * @throws ConvergenceException if the maximum iteration count is exceeded
 57  
      * or the solver detects convergence problems otherwise
 58  
      * @throws FunctionEvaluationException if an error occurs evaluating the
 59  
      * function
 60  
      * @throws IllegalArgumentException if any parameters are invalid
 61  
      */
 62  
     public double solve(double min, double max, double initial) throws
 63  
         ConvergenceException, FunctionEvaluationException {
 64  
 
 65  
         // check for zeros before verifying bracketing
 66  0
         if (f.value(min) == 0.0) { return min; }
 67  0
         if (f.value(max) == 0.0) { return max; }
 68  0
         if (f.value(initial) == 0.0) { return initial; }
 69  
 
 70  0
         verifyBracketing(min, max, f);
 71  0
         verifySequence(min, initial, max);
 72  0
         if (isBracketing(min, initial, f)) {
 73  0
             return solve(min, initial);
 74  
         } else {
 75  0
             return solve(initial, max);
 76  
         }
 77  
     }
 78  
 
 79  
     /**
 80  
      * Find a root in the given interval.
 81  
      * <p>
 82  
      * Requires bracketing condition.
 83  
      * 
 84  
      * @param min the lower bound for the interval
 85  
      * @param max the upper bound for the interval
 86  
      * @return the point at which the function value is zero
 87  
      * @throws ConvergenceException if the maximum iteration count is exceeded
 88  
      * or the solver detects convergence problems otherwise
 89  
      * @throws FunctionEvaluationException if an error occurs evaluating the
 90  
      * function 
 91  
      * @throws IllegalArgumentException if any parameters are invalid
 92  
      */
 93  
     public double solve(double min, double max) throws ConvergenceException, 
 94  
         FunctionEvaluationException {
 95  
 
 96  
         // [x1, x2] is the bracketing interval in each iteration
 97  
         // x3 is the midpoint of [x1, x2]
 98  
         // x is the new root approximation and an endpoint of the new interval
 99  
         double x1, x2, x3, x, oldx, y1, y2, y3, y, delta, correction, tolerance;
 100  
 
 101  20
         x1 = min; y1 = f.value(x1);
 102  20
         x2 = max; y2 = f.value(x2);
 103  
 
 104  
         // check for zeros before verifying bracketing
 105  20
         if (y1 == 0.0) { return min; }
 106  20
         if (y2 == 0.0) { return max; }
 107  20
         verifyBracketing(min, max, f);
 108  
 
 109  16
         int i = 1;
 110  16
         oldx = Double.POSITIVE_INFINITY;
 111  82
         while (i <= maximalIterationCount) {
 112  
             // calculate the new root approximation
 113  82
             x3 = 0.5 * (x1 + x2);
 114  82
             y3 = f.value(x3);
 115  82
             if (Math.abs(y3) <= functionValueAccuracy) {
 116  0
                 setResult(x3, i);
 117  0
                 return result;
 118  
             }
 119  82
             delta = 1 - (y1 * y2) / (y3 * y3);  // delta > 1 due to bracketing
 120  82
             correction = (MathUtils.sign(y2) * MathUtils.sign(y3)) *
 121  
                          (x3 - x1) / Math.sqrt(delta);
 122  82
             x = x3 - correction;                // correction != 0
 123  82
             y = f.value(x);
 124  
 
 125  
             // check for convergence
 126  82
             tolerance = Math.max(relativeAccuracy * Math.abs(x), absoluteAccuracy);
 127  82
             if (Math.abs(x - oldx) <= tolerance) {
 128  16
                 setResult(x, i);
 129  16
                 return result;
 130  
             }
 131  66
             if (Math.abs(y) <= functionValueAccuracy) {
 132  0
                 setResult(x, i);
 133  0
                 return result;
 134  
             }
 135  
 
 136  
             // prepare the new interval for next iteration
 137  
             // Ridders' method guarantees x1 < x < x2
 138  66
             if (correction > 0.0) {             // x1 < x < x3
 139  42
                 if (MathUtils.sign(y1) + MathUtils.sign(y) == 0.0) {
 140  18
                     x2 = x; y2 = y;
 141  
                 } else {
 142  24
                     x1 = x; x2 = x3;
 143  24
                     y1 = y; y2 = y3;
 144  
                 }
 145  
             } else {                            // x3 < x < x2
 146  24
                 if (MathUtils.sign(y2) + MathUtils.sign(y) == 0.0) {
 147  16
                     x1 = x; y1 = y;
 148  
                 } else {
 149  8
                     x1 = x3; x2 = x;
 150  8
                     y1 = y3; y2 = y;
 151  
                 }
 152  
             }
 153  66
             oldx = x;
 154  66
             i++;
 155  
         }
 156  0
         throw new ConvergenceException("Maximum number of iterations exceeded.");
 157  
     }
 158  
 }