View Javadoc

    1   /*
    2    * Copyright 2003-2004 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
    17  package org.apache.commons.math.analysis;
    18
    19  import java.io.Serializable;
    20
    21  import org.apache.commons.math.FunctionEvaluationException;
    22
    23  /***
    24   * Provide a default implementation for several functions useful to generic
    25   * solvers.
    26   *
    27   * @version $Revision: 348888 $ $Date: 2005-11-24 23:21:25 -0700 (Thu, 24 Nov 2005) $
    28   */
    29  public abstract class UnivariateRealSolverImpl implements UnivariateRealSolver,
    30      Serializable {
    31
    32      /*** Serializable version identifier */
    33      private static final long serialVersionUID = 1112491292565386596L;
    34
    35      /*** Maximum absolute error. */
    36      protected double absoluteAccuracy;
    37
    38      /*** Maximum relative error. */
    39      protected double relativeAccuracy;
    40
    41      /*** Maximum error of function. */
    42      protected double functionValueAccuracy;
    43
    44      /*** Maximum number of iterations. */
    45      protected int maximalIterationCount;
    46
    47      /*** Default maximum absolute error. */
    48      protected double defaultAbsoluteAccuracy;
    49
    50      /*** Default maximum relative error. */
    51      protected double defaultRelativeAccuracy;
    52
    53      /*** Default maximum error of function. */
    54      protected double defaultFunctionValueAccuracy;
    55
    56      /*** Default maximum number of iterations. */
    57      protected int defaultMaximalIterationCount;
    58
    59      /*** Indicates where a root has been computed. */
    60      protected boolean resultComputed = false;
    61
    62      /*** The last computed root. */
    63      protected double result;
    64
    65      // Mainly for test framework.
    66      /*** The last iteration count. */
    67      protected int iterationCount;
    68
    69      /*** The function to solve. */
    70      protected UnivariateRealFunction f;
    71
    72      /***
    73       * Construct a solver with given iteration count and accuracy.
    74       *
    75       * @param f the function to solve.
    76       * @param defaultAbsoluteAccuracy maximum absolute error
    77       * @param defaultMaximalIterationCount maximum number of iterations
    78       * @throws IllegalArgumentException if f is null or the
    79       * defaultAbsoluteAccuracy is not valid
    80       */
    81      protected UnivariateRealSolverImpl(
    82          UnivariateRealFunction f,
    83          int defaultMaximalIterationCount,
    84          double defaultAbsoluteAccuracy) {
    85
    86          super();
    87
    88          if (f == null) {
    89              throw new IllegalArgumentException("function can not be null.");
    90          }
    91
    92          this.f = f;
    93          this.defaultAbsoluteAccuracy = defaultAbsoluteAccuracy;
    94          this.defaultRelativeAccuracy = 1E-14;
    95          this.defaultFunctionValueAccuracy = 1E-15;
    96          this.absoluteAccuracy = defaultAbsoluteAccuracy;
    97          this.relativeAccuracy = defaultRelativeAccuracy;
    98          this.functionValueAccuracy = defaultFunctionValueAccuracy;
    99          this.defaultMaximalIterationCount = defaultMaximalIterationCount;
    100         this.maximalIterationCount = defaultMaximalIterationCount;
    101     }
    102
    103     /***
    104      * Access the last computed root.
    105      *
    106      * @return the last computed root
    107      * @throws IllegalStateException if no root has been computed
    108      */
    109     public double getResult() {
    110         if (resultComputed) {
    111             return result;
    112         } else {
    113             throw new IllegalStateException("No result available");
    114         }
    115     }
    116
    117     /***
    118      * Access the last iteration count.
    119      *
    120      * @return the last iteration count
    121      * @throws IllegalStateException if no root has been computed
    122      *
    123      */
    124     public int getIterationCount() {
    125         if (resultComputed) {
    126             return iterationCount;
    127         } else {
    128             throw new IllegalStateException("No result available");
    129         }
    130     }
    131
    132     /***
    133      * Convenience function for implementations.
    134      *
    135      * @param result the result to set
    136      * @param iterationCount the iteration count to set
    137      */
    138     protected final void setResult(double result, int iterationCount) {
    139         this.result = result;
    140         this.iterationCount = iterationCount;
    141         this.resultComputed = true;
    142     }
    143
    144     /***
    145      * Convenience function for implementations.
    146      */
    147     protected final void clearResult() {
    148         this.resultComputed = false;
    149     }
    150
    151     /***
    152      * Set the absolute accuracy.
    153      *
    154      * @param accuracy the accuracy.
    155      * @throws IllegalArgumentException if the accuracy can't be achieved by
    156      *  the solver or is otherwise deemed unreasonable.
    157      */
    158     public void setAbsoluteAccuracy(double accuracy) {
    159         absoluteAccuracy = accuracy;
    160     }
    161
    162     /***
    163      * Get the actual absolute accuracy.
    164      *
    165      * @return the accuracy
    166      */
    167     public double getAbsoluteAccuracy() {
    168         return absoluteAccuracy;
    169     }
    170
    171     /***
    172      * Reset the absolute accuracy to the default.
    173      */
    174     public void resetAbsoluteAccuracy() {
    175         absoluteAccuracy = defaultAbsoluteAccuracy;
    176     }
    177
    178     /***
    179      * Set the upper limit for the number of iterations.
    180      *
    181      * @param count maximum number of iterations
    182      */
    183     public void setMaximalIterationCount(int count) {
    184         maximalIterationCount = count;
    185     }
    186
    187     /***
    188      * Get the upper limit for the number of iterations.
    189      *
    190      * @return the actual upper limit
    191      */
    192     public int getMaximalIterationCount() {
    193         return maximalIterationCount;
    194     }
    195
    196     /***
    197      * Reset the upper limit for the number of iterations to the default.
    198      */
    199     public void resetMaximalIterationCount() {
    200         maximalIterationCount = defaultMaximalIterationCount;
    201     }
    202
    203     /***
    204      * Set the relative accuracy.
    205      *
    206      * @param accuracy the relative accuracy.
    207      * @throws IllegalArgumentException if the accuracy can't be achieved by
    208      *  the solver or is otherwise deemed unreasonable.
    209      */
    210     public void setRelativeAccuracy(double accuracy) {
    211         relativeAccuracy = accuracy;
    212     }
    213
    214     /***
    215      * Get the actual relative accuracy.
    216      * @return the accuracy
    217      */
    218     public double getRelativeAccuracy() {
    219         return relativeAccuracy;
    220     }
    221
    222     /***
    223      * Reset the relative accuracy to the default.
    224      */
    225     public void resetRelativeAccuracy() {
    226         relativeAccuracy = defaultRelativeAccuracy;
    227     }
    228
    229     /***
    230      * Set the function value accuracy.
    231      *
    232      * @param accuracy the accuracy.
    233      * @throws IllegalArgumentException if the accuracy can't be achieved by
    234      * the solver or is otherwise deemed unreasonable.
    235      */
    236     public void setFunctionValueAccuracy(double accuracy) {
    237         functionValueAccuracy = accuracy;
    238     }
    239
    240     /***
    241      * Get the actual function value accuracy.
    242      * @return the accuracy
    243      */
    244     public double getFunctionValueAccuracy() {
    245         return functionValueAccuracy;
    246     }
    247
    248     /***
    249      * Reset the actual function accuracy to the default.
    250      */
    251     public void resetFunctionValueAccuracy() {
    252         functionValueAccuracy = defaultFunctionValueAccuracy;
    253     }
    254
    255
    256     /***
    257      * Returns true iff the function takes opposite signs at the endpoints.
    258      *
    259      * @param lower  the lower endpoint
    260      * @param upper  the upper endpoint
    261      * @param f the function
    262      * @return true if f(lower) * f(upper) < 0
    263      * @throws FunctionEvaluationException if an error occurs evaluating the
    264      * function at the endpoints
    265      */
    266     protected boolean isBracketing(double lower, double upper,
    267             UnivariateRealFunction f) throws FunctionEvaluationException {
    268         double f1 = f.value(lower);
    269         double f2 = f.value(upper);
    270         return ((f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0));
    271     }
    272
    273     /***
    274      * Returns true if the arguments form a (strictly) increasing sequence
    275      *
    276      * @param start  first number
    277      * @param mid   second number
    278      * @param end  third number
    279      * @return true if the arguments form an increasing sequence
    280      */
    281     protected boolean isSequence(double start, double mid, double end) {
    282         return (start < mid) && (mid < end);
    283     }
    284
    285     /***
    286      * Verifies that the endpoints specify an interval,
    287      * throws IllegalArgumentException if not
    288      *
    289      * @param lower  lower endpoint
    290      * @param upper upper endpoint
    291      * @throws IllegalArgumentException
    292      */
    293     protected void verifyInterval(double lower, double upper) {
    294         if (lower >= upper) {
    295             throw new IllegalArgumentException
    296                 ("Endpoints do not specify an interval: [" + lower +
    297                         "," + upper + "]");
    298         }
    299     }
    300
    301     /***
    302      * Verifies that <code>lower < initial < upper</code>
    303      * throws IllegalArgumentException if not
    304      *
    305      * @param lower  lower endpoint
    306      * @param initial initial value
    307      * @param upper upper endpoint
    308      * @throws IllegalArgumentException
    309      */
    310     protected void verifySequence(double lower, double initial, double upper) {
    311         if (!isSequence(lower, initial, upper)) {
    312             throw new IllegalArgumentException
    313                 ("Invalid interval, initial value parameters:  lower=" +
    314                    lower + " initial=" + initial + " upper=" + upper);
    315         }
    316     }
    317
    318     /***
    319      * Verifies that the endpoints specify an interval and the function takes
    320      * opposite signs at the enpoints, throws IllegalArgumentException if not
    321      *
    322      * @param lower  lower endpoint
    323      * @param upper upper endpoint
    324      * @param f function
    325      * @throws IllegalArgumentException
    326      * @throws FunctionEvaluationException if an error occurs evaluating the
    327      * function at the endpoints
    328      */
    329     protected void verifyBracketing(double lower, double upper,
    330             UnivariateRealFunction f) throws FunctionEvaluationException {
    331
    332         verifyInterval(lower, upper);
    333         if (!isBracketing(lower, upper, f)) {
    334             throw new IllegalArgumentException
    335             ("Function values at endpoints do not have different signs." +
    336                     "  Endpoints: [" + lower + "," + upper + "]" +
    337                     "  Values: [" + f.value(lower) + "," + f.value(upper) + "]");
    338         }
    339     }
    340 }