• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package org.apache.commons.math.optimization.univariate;
18 
19 import org.apache.commons.math.FunctionEvaluationException;
20 import org.apache.commons.math.exception.NotStrictlyPositiveException;
21 import org.apache.commons.math.MaxIterationsExceededException;
22 import org.apache.commons.math.analysis.UnivariateRealFunction;
23 import org.apache.commons.math.optimization.GoalType;
24 
25 /**
26  * Provide an interval that brackets a local optimum of a function.
27  * This code is based on a Python implementation (from <em>SciPy</em>,
28  * module {@code optimize.py} v0.5).
29  * @version $Revision$ $Date$
30  * @since 2.2
31  */
32 public class BracketFinder {
33     /** Tolerance to avoid division by zero. */
34     private static final double EPS_MIN = 1e-21;
35     /**
36      * Golden section.
37      */
38     private static final double GOLD = 1.618034;
39     /**
40      * Factor for expanding the interval.
41      */
42     private final double growLimit;
43     /**
44      * Maximum number of iterations.
45      */
46     private final int maxIterations;
47     /**
48      * Number of iterations.
49      */
50     private int iterations;
51     /**
52      * Number of function evaluations.
53      */
54     private int evaluations;
55     /**
56      * Lower bound of the bracket.
57      */
58     private double lo;
59     /**
60      * Higher bound of the bracket.
61      */
62     private double hi;
63     /**
64      * Point inside the bracket.
65      */
66     private double mid;
67     /**
68      * Function value at {@link #lo}.
69      */
70     private double fLo;
71     /**
72      * Function value at {@link #hi}.
73      */
74     private double fHi;
75     /**
76      * Function value at {@link #mid}.
77      */
78     private double fMid;
79 
80     /**
81      * Constructor with default values {@code 100, 50} (see the
82      * {@link #BracketFinder(double,int) other constructor}).
83      */
BracketFinder()84     public BracketFinder() {
85         this(100, 50);
86     }
87 
88     /**
89      * Create a bracketing interval finder.
90      *
91      * @param growLimit Expanding factor.
92      * @param maxIterations Maximum number of iterations allowed for finding
93      * a bracketing interval.
94      */
BracketFinder(double growLimit, int maxIterations)95     public BracketFinder(double growLimit,
96                          int maxIterations) {
97         if (growLimit <= 0) {
98             throw new NotStrictlyPositiveException(growLimit);
99         }
100         if (maxIterations <= 0) {
101             throw new NotStrictlyPositiveException(maxIterations);
102         }
103 
104         this.growLimit = growLimit;
105         this.maxIterations = maxIterations;
106     }
107 
108     /**
109      * Search new points that bracket a local optimum of the function.
110      *
111      * @param func Function whose optimum should be bracketted.
112      * @param goal {@link GoalType Goal type}.
113      * @param xA Initial point.
114      * @param xB Initial point.
115      * @throws MaxIterationsExceededException if the maximum iteration count
116      * is exceeded.
117      * @throws FunctionEvaluationException if an error occurs evaluating the function.
118      */
search(UnivariateRealFunction func, GoalType goal, double xA, double xB)119     public void search(UnivariateRealFunction func,
120                        GoalType goal,
121                        double xA,
122                        double xB)
123         throws MaxIterationsExceededException, FunctionEvaluationException {
124         reset();
125         final boolean isMinim = goal == GoalType.MINIMIZE;
126 
127         double fA = eval(func, xA);
128         double fB = eval(func, xB);
129         if (isMinim ?
130             fA < fB :
131             fA > fB) {
132             double tmp = xA;
133             xA = xB;
134             xB = tmp;
135 
136             tmp = fA;
137             fA = fB;
138             fB = tmp;
139         }
140 
141         double xC = xB + GOLD * (xB - xA);
142         double fC = eval(func, xC);
143 
144         while (isMinim ? fC < fB : fC > fB) {
145             if (++iterations > maxIterations) {
146                 throw new MaxIterationsExceededException(maxIterations);
147             }
148 
149             double tmp1 = (xB - xA) * (fB - fC);
150             double tmp2 = (xB - xC) * (fB - fA);
151 
152             double val = tmp2 - tmp1;
153             double denom = Math.abs(val) < EPS_MIN ? 2 * EPS_MIN : 2 * val;
154 
155             double w = xB - ((xB - xC) * tmp2 - (xB -xA) * tmp1) / denom;
156             double wLim = xB + growLimit * (xC - xB);
157 
158             double fW;
159             if ((w - xC) * (xB - w) > 0) {
160                 fW = eval(func, w);
161                 if (isMinim ?
162                     fW < fC :
163                     fW > fC) {
164                     xA = xB;
165                     xB = w;
166                     fA = fB;
167                     fB = fW;
168                     break;
169                 } else if (isMinim ?
170                            fW > fB :
171                            fW < fB) {
172                     xC = w;
173                     fC = fW;
174                     break;
175                 }
176                 w = xC + GOLD * (xC - xB);
177                 fW = eval(func, w);
178             } else if ((w - wLim) * (wLim - xC) >= 0) {
179                 w = wLim;
180                 fW = eval(func, w);
181             } else if ((w - wLim) * (xC - w) > 0) {
182                 fW = eval(func, w);
183                 if (isMinim ?
184                     fW < fC :
185                     fW > fC) {
186                     xB = xC;
187                     xC = w;
188                     w = xC + GOLD * (xC -xB);
189                     fB = fC;
190                     fC =fW;
191                     fW = eval(func, w);
192                 }
193             } else {
194                 w = xC + GOLD * (xC - xB);
195                 fW = eval(func, w);
196             }
197 
198             xA = xB;
199             xB = xC;
200             xC = w;
201             fA = fB;
202             fB = fC;
203             fC = fW;
204         }
205 
206         lo = xA;
207         mid = xB;
208         hi = xC;
209         fLo = fA;
210         fMid = fB;
211         fHi = fC;
212     }
213 
214     /**
215      * @return the number of iterations.
216      */
getIterations()217     public int getIterations() {
218         return iterations;
219     }
220     /**
221      * @return the number of evaluations.
222      */
getEvaluations()223     public int getEvaluations() {
224         return evaluations;
225     }
226 
227     /**
228      * @return the lower bound of the bracket.
229      * @see #getFLow()
230      */
getLo()231     public double getLo() {
232         return lo;
233     }
234 
235     /**
236      * Get function value at {@link #getLo()}.
237      * @return function value at {@link #getLo()}
238      */
getFLow()239     public double getFLow() {
240         return fLo;
241     }
242 
243     /**
244      * @return the higher bound of the bracket.
245      * @see #getFHi()
246      */
getHi()247     public double getHi() {
248         return hi;
249     }
250 
251     /**
252      * Get function value at {@link #getHi()}.
253      * @return function value at {@link #getHi()}
254      */
getFHi()255     public double getFHi() {
256         return fHi;
257     }
258 
259     /**
260      * @return a point in the middle of the bracket.
261      * @see #getFMid()
262      */
getMid()263     public double getMid() {
264         return mid;
265     }
266 
267     /**
268      * Get function value at {@link #getMid()}.
269      * @return function value at {@link #getMid()}
270      */
getFMid()271     public double getFMid() {
272         return fMid;
273     }
274 
275     /**
276      * @param f Function.
277      * @param x Argument.
278      * @return {@code f(x)}
279      * @throws FunctionEvaluationException if function cannot be evaluated at x
280      */
eval(UnivariateRealFunction f, double x)281     private double eval(UnivariateRealFunction f, double x)
282         throws FunctionEvaluationException {
283 
284         ++evaluations;
285         return f.value(x);
286     }
287 
288     /**
289      * Reset internal state.
290      */
reset()291     private void reset() {
292         iterations = 0;
293         evaluations = 0;
294     }
295 }
296