001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.math.analysis.solvers; 019 020 import org.apache.commons.math.ConvergingAlgorithmImpl; 021 import org.apache.commons.math.FunctionEvaluationException; 022 import org.apache.commons.math.MathRuntimeException; 023 import org.apache.commons.math.analysis.UnivariateRealFunction; 024 025 /** 026 * Provide a default implementation for several functions useful to generic 027 * solvers. 028 * 029 * @version $Revision: 811833 $ $Date: 2009-09-06 12:27:50 -0400 (Sun, 06 Sep 2009) $ 030 */ 031 public abstract class UnivariateRealSolverImpl 032 extends ConvergingAlgorithmImpl implements UnivariateRealSolver { 033 034 /** Maximum error of function. */ 035 protected double functionValueAccuracy; 036 037 /** Default maximum error of function. */ 038 protected double defaultFunctionValueAccuracy; 039 040 /** Indicates where a root has been computed. */ 041 protected boolean resultComputed = false; 042 043 /** The last computed root. */ 044 protected double result; 045 046 /** Value of the function at the last computed result. */ 047 protected double functionValue; 048 049 /** The function to solve. 050 * @deprecated as of 2.0 the function to solve is passed as an argument 051 * to the {@link #solve(UnivariateRealFunction, double, double)} or 052 * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)} 053 * method. */ 054 @Deprecated 055 protected UnivariateRealFunction f; 056 057 /** 058 * Construct a solver with given iteration count and accuracy. 059 * 060 * @param f the function to solve. 061 * @param defaultAbsoluteAccuracy maximum absolute error 062 * @param defaultMaximalIterationCount maximum number of iterations 063 * @throws IllegalArgumentException if f is null or the 064 * defaultAbsoluteAccuracy is not valid 065 * @deprecated as of 2.0 the function to solve is passed as an argument 066 * to the {@link #solve(UnivariateRealFunction, double, double)} or 067 * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)} 068 * method. 069 */ 070 @Deprecated 071 protected UnivariateRealSolverImpl(final UnivariateRealFunction f, 072 final int defaultMaximalIterationCount, 073 final double defaultAbsoluteAccuracy) { 074 super(defaultMaximalIterationCount, defaultAbsoluteAccuracy); 075 if (f == null) { 076 throw MathRuntimeException.createIllegalArgumentException("function to solve cannot be null"); 077 } 078 this.f = f; 079 this.defaultFunctionValueAccuracy = 1.0e-15; 080 this.functionValueAccuracy = defaultFunctionValueAccuracy; 081 } 082 083 /** 084 * Construct a solver with given iteration count and accuracy. 085 * 086 * @param defaultAbsoluteAccuracy maximum absolute error 087 * @param defaultMaximalIterationCount maximum number of iterations 088 * @throws IllegalArgumentException if f is null or the 089 * defaultAbsoluteAccuracy is not valid 090 */ 091 protected UnivariateRealSolverImpl(final int defaultMaximalIterationCount, 092 final double defaultAbsoluteAccuracy) { 093 super(defaultMaximalIterationCount, defaultAbsoluteAccuracy); 094 this.defaultFunctionValueAccuracy = 1.0e-15; 095 this.functionValueAccuracy = defaultFunctionValueAccuracy; 096 } 097 098 /** Check if a result has been computed. 099 * @exception IllegalStateException if no result has been computed 100 */ 101 protected void checkResultComputed() throws IllegalStateException { 102 if (!resultComputed) { 103 throw MathRuntimeException.createIllegalStateException("no result available"); 104 } 105 } 106 107 /** {@inheritDoc} */ 108 public double getResult() { 109 checkResultComputed(); 110 return result; 111 } 112 113 /** {@inheritDoc} */ 114 public double getFunctionValue() { 115 checkResultComputed(); 116 return functionValue; 117 } 118 119 /** {@inheritDoc} */ 120 public void setFunctionValueAccuracy(final double accuracy) { 121 functionValueAccuracy = accuracy; 122 } 123 124 /** {@inheritDoc} */ 125 public double getFunctionValueAccuracy() { 126 return functionValueAccuracy; 127 } 128 129 /** {@inheritDoc} */ 130 public void resetFunctionValueAccuracy() { 131 functionValueAccuracy = defaultFunctionValueAccuracy; 132 } 133 134 /** 135 * Convenience function for implementations. 136 * 137 * @param newResult the result to set 138 * @param iterationCount the iteration count to set 139 */ 140 protected final void setResult(final double newResult, final int iterationCount) { 141 this.result = newResult; 142 this.iterationCount = iterationCount; 143 this.resultComputed = true; 144 } 145 146 /** 147 * Convenience function for implementations. 148 * 149 * @param x the result to set 150 * @param fx the result to set 151 * @param iterationCount the iteration count to set 152 */ 153 protected final void setResult(final double x, final double fx, 154 final int iterationCount) { 155 this.result = x; 156 this.functionValue = fx; 157 this.iterationCount = iterationCount; 158 this.resultComputed = true; 159 } 160 161 /** 162 * Convenience function for implementations. 163 */ 164 protected final void clearResult() { 165 this.iterationCount = 0; 166 this.resultComputed = false; 167 } 168 169 /** 170 * Returns true iff the function takes opposite signs at the endpoints. 171 * 172 * @param lower the lower endpoint 173 * @param upper the upper endpoint 174 * @param function the function 175 * @return true if f(lower) * f(upper) < 0 176 * @throws FunctionEvaluationException if an error occurs evaluating the 177 * function at the endpoints 178 */ 179 protected boolean isBracketing(final double lower, final double upper, 180 final UnivariateRealFunction function) 181 throws FunctionEvaluationException { 182 final double f1 = function.value(lower); 183 final double f2 = function.value(upper); 184 return (f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0); 185 } 186 187 /** 188 * Returns true if the arguments form a (strictly) increasing sequence 189 * 190 * @param start first number 191 * @param mid second number 192 * @param end third number 193 * @return true if the arguments form an increasing sequence 194 */ 195 protected boolean isSequence(final double start, final double mid, final double end) { 196 return (start < mid) && (mid < end); 197 } 198 199 /** 200 * Verifies that the endpoints specify an interval, 201 * throws IllegalArgumentException if not 202 * 203 * @param lower lower endpoint 204 * @param upper upper endpoint 205 * @throws IllegalArgumentException 206 */ 207 protected void verifyInterval(final double lower, final double upper) { 208 if (lower >= upper) { 209 throw MathRuntimeException.createIllegalArgumentException( 210 "endpoints do not specify an interval: [{0}, {1}]", 211 lower, upper); 212 } 213 } 214 215 /** 216 * Verifies that <code>lower < initial < upper</code> 217 * throws IllegalArgumentException if not 218 * 219 * @param lower lower endpoint 220 * @param initial initial value 221 * @param upper upper endpoint 222 * @throws IllegalArgumentException 223 */ 224 protected void verifySequence(final double lower, final double initial, final double upper) { 225 if (!isSequence(lower, initial, upper)) { 226 throw MathRuntimeException.createIllegalArgumentException( 227 "invalid interval, initial value parameters: lower={0}, initial={1}, upper={2}", 228 lower, initial, upper); 229 } 230 } 231 232 /** 233 * Verifies that the endpoints specify an interval and the function takes 234 * opposite signs at the enpoints, throws IllegalArgumentException if not 235 * 236 * @param lower lower endpoint 237 * @param upper upper endpoint 238 * @param function function 239 * @throws IllegalArgumentException 240 * @throws FunctionEvaluationException if an error occurs evaluating the 241 * function at the endpoints 242 */ 243 protected void verifyBracketing(final double lower, final double upper, 244 final UnivariateRealFunction function) 245 throws FunctionEvaluationException { 246 247 verifyInterval(lower, upper); 248 if (!isBracketing(lower, upper, function)) { 249 throw MathRuntimeException.createIllegalArgumentException( 250 "function values at endpoints do not have different signs. " + 251 "Endpoints: [{0}, {1}], Values: [{2}, {3}]", 252 lower, upper, function.value(lower), function.value(upper)); 253 } 254 } 255 }