1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math4.legacy.optim.univariate;
18
19 import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
20 import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException;
21 import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
22 import org.apache.commons.math4.legacy.optim.ConvergenceChecker;
23 import org.apache.commons.math4.legacy.optim.nonlinear.scalar.GoalType;
24 import org.apache.commons.math4.core.jdkmath.JdkMath;
25 import org.apache.commons.numbers.core.Precision;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class BrentOptimizer extends UnivariateOptimizer {
45
46
47
48 private static final double GOLDEN_SECTION = 0.5 * (3 - JdkMath.sqrt(5));
49
50
51
52 private static final double MIN_RELATIVE_TOLERANCE = 2 * JdkMath.ulp(1d);
53
54
55
56 private final double relativeThreshold;
57
58
59
60 private final double absoluteThreshold;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 public BrentOptimizer(double rel,
79 double abs,
80 ConvergenceChecker<UnivariatePointValuePair> checker) {
81 super(checker);
82
83 if (rel < MIN_RELATIVE_TOLERANCE) {
84 throw new NumberIsTooSmallException(rel, MIN_RELATIVE_TOLERANCE, true);
85 }
86 if (abs <= 0) {
87 throw new NotStrictlyPositiveException(abs);
88 }
89
90 relativeThreshold = rel;
91 absoluteThreshold = abs;
92 }
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public BrentOptimizer(double rel,
109 double abs) {
110 this(rel, abs, null);
111 }
112
113
114 @Override
115 protected UnivariatePointValuePair doOptimize() {
116 final boolean isMinim = getGoalType() == GoalType.MINIMIZE;
117 final double lo = getMin();
118 final double mid = getStartValue();
119 final double hi = getMax();
120 final UnivariateFunction func = getObjectiveFunction();
121
122
123 final ConvergenceChecker<UnivariatePointValuePair> checker
124 = getConvergenceChecker();
125
126 double a;
127 double b;
128 if (lo < hi) {
129 a = lo;
130 b = hi;
131 } else {
132 a = hi;
133 b = lo;
134 }
135
136 double x = mid;
137 double v = x;
138 double w = x;
139 double d = 0;
140 double e = 0;
141 double fx = func.value(x);
142 if (!isMinim) {
143 fx = -fx;
144 }
145 double fv = fx;
146 double fw = fx;
147
148 UnivariatePointValuePair previous = null;
149 UnivariatePointValuePair current
150 = new UnivariatePointValuePair(x, isMinim ? fx : -fx);
151
152 UnivariatePointValuePair best = current;
153
154 while (true) {
155 final double m = 0.5 * (a + b);
156 final double tol1 = relativeThreshold * JdkMath.abs(x) + absoluteThreshold;
157 final double tol2 = 2 * tol1;
158
159
160 final boolean stop = JdkMath.abs(x - m) <= tol2 - 0.5 * (b - a);
161 if (!stop) {
162 double p = 0;
163 double q = 0;
164 double r = 0;
165 double u = 0;
166
167 if (JdkMath.abs(e) > tol1) {
168 r = (x - w) * (fx - fv);
169 q = (x - v) * (fx - fw);
170 p = (x - v) * q - (x - w) * r;
171 q = 2 * (q - r);
172
173 if (q > 0) {
174 p = -p;
175 } else {
176 q = -q;
177 }
178
179 r = e;
180 e = d;
181
182 if (p > q * (a - x) &&
183 p < q * (b - x) &&
184 JdkMath.abs(p) < JdkMath.abs(0.5 * q * r)) {
185
186 d = p / q;
187 u = x + d;
188
189
190 if (u - a < tol2 || b - u < tol2) {
191 if (x <= m) {
192 d = tol1;
193 } else {
194 d = -tol1;
195 }
196 }
197 } else {
198
199 if (x < m) {
200 e = b - x;
201 } else {
202 e = a - x;
203 }
204 d = GOLDEN_SECTION * e;
205 }
206 } else {
207
208 if (x < m) {
209 e = b - x;
210 } else {
211 e = a - x;
212 }
213 d = GOLDEN_SECTION * e;
214 }
215
216
217 if (JdkMath.abs(d) < tol1) {
218 if (d >= 0) {
219 u = x + tol1;
220 } else {
221 u = x - tol1;
222 }
223 } else {
224 u = x + d;
225 }
226
227 double fu = func.value(u);
228 if (!isMinim) {
229 fu = -fu;
230 }
231
232
233 previous = current;
234 current = new UnivariatePointValuePair(u, isMinim ? fu : -fu);
235 best = best(best,
236 best(previous,
237 current,
238 isMinim),
239 isMinim);
240
241 if (checker != null && checker.converged(getIterations(), previous, current)) {
242 return best;
243 }
244
245
246 if (fu <= fx) {
247 if (u < x) {
248 b = x;
249 } else {
250 a = x;
251 }
252 v = w;
253 fv = fw;
254 w = x;
255 fw = fx;
256 x = u;
257 fx = fu;
258 } else {
259 if (u < x) {
260 a = u;
261 } else {
262 b = u;
263 }
264 if (fu <= fw ||
265 Precision.equals(w, x)) {
266 v = w;
267 fv = fw;
268 w = u;
269 fw = fu;
270 } else if (fu <= fv ||
271 Precision.equals(v, x) ||
272 Precision.equals(v, w)) {
273 v = u;
274 fv = fu;
275 }
276 }
277 } else {
278 return best(best,
279 best(previous,
280 current,
281 isMinim),
282 isMinim);
283 }
284
285 incrementIterationCount();
286 }
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300 private UnivariatePointValuePair best(UnivariatePointValuePair a,
301 UnivariatePointValuePair b,
302 boolean isMinim) {
303 if (a == null) {
304 return b;
305 }
306 if (b == null) {
307 return a;
308 }
309
310 if (isMinim) {
311 return a.getValue() <= b.getValue() ? a : b;
312 } else {
313 return a.getValue() >= b.getValue() ? a : b;
314 }
315 }
316 }