1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.math.analysis.solvers;
19
20 import org.apache.commons.math.ConvergingAlgorithmImpl;
21 import org.apache.commons.math.FunctionEvaluationException;
22 import org.apache.commons.math.MathRuntimeException;
23 import org.apache.commons.math.analysis.UnivariateRealFunction;
24
25 /**
26 * Provide a default implementation for several functions useful to generic
27 * solvers.
28 *
29 * @version $Revision: 799857 $ $Date: 2009-08-01 09:07:12 -0400 (Sat, 01 Aug 2009) $
30 */
31 public abstract class UnivariateRealSolverImpl
32 extends ConvergingAlgorithmImpl implements UnivariateRealSolver {
33
34 /** Maximum error of function. */
35 protected double functionValueAccuracy;
36
37 /** Default maximum error of function. */
38 protected double defaultFunctionValueAccuracy;
39
40 /** Indicates where a root has been computed. */
41 protected boolean resultComputed = false;
42
43 /** The last computed root. */
44 protected double result;
45
46 /** Value of the function at the last computed result. */
47 protected double functionValue;
48
49 /** The function to solve.
50 * @deprecated as of 2.0 the function to solve is passed as an argument
51 * to the {@link #solve(UnivariateRealFunction, double, double)} or
52 * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
53 * method. */
54 @Deprecated
55 protected UnivariateRealFunction f;
56
57 /**
58 * Construct a solver with given iteration count and accuracy.
59 *
60 * @param f the function to solve.
61 * @param defaultAbsoluteAccuracy maximum absolute error
62 * @param defaultMaximalIterationCount maximum number of iterations
63 * @throws IllegalArgumentException if f is null or the
64 * defaultAbsoluteAccuracy is not valid
65 * @deprecated as of 2.0 the function to solve is passed as an argument
66 * to the {@link #solve(UnivariateRealFunction, double, double)} or
67 * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
68 * method.
69 */
70 @Deprecated
71 protected UnivariateRealSolverImpl(final UnivariateRealFunction f,
72 final int defaultMaximalIterationCount,
73 final double defaultAbsoluteAccuracy) {
74 super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
75 if (f == null) {
76 throw MathRuntimeException.createIllegalArgumentException("function to solve cannot be null");
77 }
78 this.f = f;
79 this.defaultFunctionValueAccuracy = 1.0e-15;
80 this.functionValueAccuracy = defaultFunctionValueAccuracy;
81 }
82
83 /**
84 * Construct a solver with given iteration count and accuracy.
85 *
86 * @param defaultAbsoluteAccuracy maximum absolute error
87 * @param defaultMaximalIterationCount maximum number of iterations
88 * @throws IllegalArgumentException if f is null or the
89 * defaultAbsoluteAccuracy is not valid
90 */
91 protected UnivariateRealSolverImpl(final int defaultMaximalIterationCount,
92 final double defaultAbsoluteAccuracy) {
93 super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
94 this.defaultFunctionValueAccuracy = 1.0e-15;
95 this.functionValueAccuracy = defaultFunctionValueAccuracy;
96 }
97
98 /** Check if a result has been computed.
99 * @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 result the result to set
138 * @param iterationCount the iteration count to set
139 */
140 protected final void setResult(final double result, final int iterationCount) {
141 this.result = result;
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 f 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 f)
181 throws FunctionEvaluationException {
182 final double f1 = f.value(lower);
183 final double f2 = f.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 f 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 f)
245 throws FunctionEvaluationException {
246
247 verifyInterval(lower, upper);
248 if (!isBracketing(lower, upper, f)) {
249 throw MathRuntimeException.createIllegalArgumentException(
250 "function values at endpoints do not have different signs. " +
251 "Endpoints: [{0}, {1}], Values: [{2}, {3}]",
252 lower, upper, f.value(lower), f.value(upper));
253 }
254 }
255 }