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: 1.15 $ $Date: 2004/07/17 21:19:39 $
    28   */
    29  public abstract class UnivariateRealSolverImpl implements UnivariateRealSolver,
    30      Serializable {
    31
    32      /*** Serializable version identifier */
    33      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         return  (f.value(lower) * f.value(upper) < 0);
    269     }
    270
    271     /***
    272      * Returns true if the arguments form a (strictly) increasing sequence
    273      *
    274      * @param start  first number
    275      * @param mid   second number
    276      * @param end  third number
    277      * @return true if the arguments form an increasing sequence
    278      */
    279     protected boolean isSequence(double start, double mid, double end) {
    280         return (start < mid) && (mid < end);
    281     }
    282
    283     /***
    284      * Verifies that the endpoints specify an interval,
    285      * throws IllegalArgumentException if not
    286      *
    287      * @param lower  lower endpoint
    288      * @param upper upper endpoint
    289      * @throws IllegalArgumentException
    290      */
    291     protected void verifyInterval(double lower, double upper) {
    292         if (lower >= upper) {
    293             throw new IllegalArgumentException
    294                 ("Endpoints do not specify an interval: [" + lower +
    295                         "," + upper + "]");
    296         }
    297     }
    298
    299     /***
    300      * Verifies that <code>lower < initial < upper</code>
    301      * throws IllegalArgumentException if not
    302      *
    303      * @param lower  lower endpoint
    304      * @param initial initial value
    305      * @param upper upper endpoint
    306      * @throws IllegalArgumentException
    307      */
    308     protected void verifySequence(double lower, double initial, double upper) {
    309         if (!isSequence(lower, initial, upper)) {
    310             throw new IllegalArgumentException
    311                 ("Invalid interval, initial value parameters:  lower=" +
    312                    lower + " initial=" + initial + " upper=" + upper);
    313         }
    314     }
    315
    316     /***
    317      * Verifies that the endpoints specify an interval and the function takes
    318      * opposite signs at the enpoints, throws IllegalArgumentException if not
    319      *
    320      * @param lower  lower endpoint
    321      * @param upper upper endpoint
    322      * @param f function
    323      * @throws IllegalArgumentException
    324      * @throws FunctionEvaluationException if an error occurs evaluating the
    325      * function at the endpoints
    326      */
    327     protected void verifyBracketing(double lower, double upper,
    328             UnivariateRealFunction f) throws FunctionEvaluationException {
    329
    330         verifyInterval(lower, upper);
    331         if (!isBracketing(lower, upper, f)) {
    332             throw new IllegalArgumentException
    333             ("Function values at endpoints do not have different signs." +
    334                     "  Endpoints: [" + lower + "," + upper + "]" +
    335                     "  Values: [" + f.value(lower) + "," + f.value(upper) + "]");
    336         }
    337     }
    338 }