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 }