Brent.h
1//-*-C++-*-
2/***************************************************************************
3 *
4 * Copyright (C) 2006 by Willem van Straten
5 * Licensed under the Academic Free License version 2.1
6 *
7 ***************************************************************************/
8
9// psrchive/Util/genutil/Brent.h
10
11#ifndef __BrentMethod
12#define __BrentMethod
13
14#include "Error.h"
15#include <algorithm>
16#include <math.h>
17
18#define EPS 3.0e-8
19
20template<class T, class U>
21 T sign (T a, U b)
22{
23 if (b >= 0)
24 return fabs(a);
25 else
26 return -fabs(a);
27}
28
29static unsigned iter_max = 100;
30
31template<typename T, class Unary>
32 T Brent (Unary func, T x1, T x2, T tol, T root = 0)
33{
34 T a = x1;
35 T b = x2;
36 T c = x2;
37
38 T fa = func(a) - root;
39 T fb = func(b) - root;
40
41 if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0)) {
42 Error error (InvalidParam, "Brent", "Root must be bracketed:");
43 error << " f(" << x1 << ")=" << fa << " f(" << x2 << ")=" << fb;
44 throw error;
45 }
46
47 T fc = fb;
48
49 for (unsigned iter=0; iter<iter_max; iter++) {
50
51 T d=0, e=0;
52
53 if ((fb > 0.0 && fc > 0.0) || (fb < 0.0 && fc < 0.0)) {
54 c=a;
55 fc=fa;
56 e=d=b-a;
57 }
58 if (fabs(fc) < fabs(fb)) {
59 a=b;
60 b=c;
61 c=a;
62 fa=fb;
63 fb=fc;
64 fc=fa;
65 }
66 T tol1 = 2.0*EPS*fabs(b) + 0.5*tol;
67 T xm = 0.5*(c-b);
68 if (fabs(xm) <= tol1 || fb == 0.0) {
69 // std::cerr << "iter=" << iter << std::endl;
70 return b;
71 }
72 if (fabs(e) >= tol1 && fabs(fa) > fabs(fb)) {
73 T p, q, r, s=fb/fa;
74 if (a == c) {
75 p=2.0*xm*s;
76 q=1.0-s;
77 } else {
78 q=fa/fc;
79 r=fb/fc;
80 p=s*(2.0*xm*q*(q-r)-(b-a)*(r-1.0));
81 q=(q-1.0)*(r-1.0)*(s-1.0);
82 }
83
84 if (p > 0.0) q = -q;
85 p=fabs(p);
86 T min1=3.0*xm*q-fabs(tol1*q);
87 T min2=fabs(e*q);
88 if (2.0*p < (min1 < min2 ? min1 : min2)) {
89 e=d;
90 d=p/q;
91 } else {
92 d=xm;
93 e=d;
94 }
95 } else {
96 d=xm;
97 e=d;
98 }
99 a=b;
100 fa=fb;
101 if (fabs(d) > tol1)
102 b += d;
103 else
104 b += sign(tol1,xm);
105 fb = func(b) - root;
106 }
107
108 throw Error (InvalidState, "Brent", "maximum iterations exceeded");
109}
110
111/* Minimization (as opposed to root finding) with Brent's method.
112 * Set func_sign=-1 for maximization. Returns x value for which the
113 * function is minimized.
114 */
115#define CG (0.3819660)
116#define ZEPS 1e-10
117template<typename T, class Unary>
118 T Brent_min (Unary func, T x1, T x2, T x3, T tol, int func_sign=1)
119{
120 T a = x1;
121 T b = x3;
122 T u=x2, v=x2, w=x2, x=x2;
123 T d = 0.0, e=0.0;
124
125 T fu, fv, fw, fx;
126 fx = ((T)func_sign) * func(x);
127 fv = fx;
128 fw = fx;
129
130 /* TODO check for actual bracket */
131
132 for (unsigned ii=0; ii<iter_max; ii++) {
133 T xm = 0.5 * (a+b);
134 T tol1 = tol * fabs(x) + ZEPS;
135 T tol2 = 2.0 * tol1;
136
137 if (fabs(x-xm) <= (tol2-0.5*(b-a)))
138 return x;
139
140 if (fabs(e) > tol1) {
141 T r = (x-w)*(fx-fv);
142 T q = (x-v)*(fx-fw);
143 T p = (x-v)*q - (x-w)*r;
144 q = 2.0 * (q-r);
145 if (q>0.0) p = -p;
146 q = fabs(q);
147 T etemp=e;
148 e = d;
149 if (fabs(p) >= fabs(0.5*q*etemp) || p<=q*(a-x) || p>=q*(b-x)) {
150 e = x>=xm ? a-x : b-x;
151 d = CG * e;
152 } else {
153 d = p/q;
154 u = x+d;
155 if (u-a < tol2 || b-u < tol2)
156 d = sign(tol1,xm-x);
157 }
158 } else {
159 e = x>=xm ? a-x : b-x;
160 d = CG * e;
161 }
162
163 u = fabs(d)>=tol1 ? x+d : x+sign(tol1,d);
164 fu = ((T)func_sign) * func(u);
165
166 if (fu<=fx) {
167 if (u>=x) a=x;
168 else b=x;
169 v=w; w=x; x=u;
170 fv=fw; fw=fx; fx=fu;
171 } else {
172 if (u<x) a=u;
173 else b=u;
174 if (fu<=fw || w==x) {
175 v=w; w=u;
176 fv=fw; fw=fu;
177 } else if (fu<=fv || v==x || v==w) {
178 v=u;
179 fv=fu;
180 }
181 }
182 }
183 throw Error (InvalidState, "Brent_min", "maximum iterations exceeded");
184}
185#endif
A convenient exception handling class.
Definition Error.h:54

Generated using doxygen 1.14.0