TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
brent_method_extrema.cpp File Reference

Find real extrema of a univariate real function in a given interval using Brent's method. More...

#include <cassert>
#include <cmath>
#include <cstdint>
#include <functional>
#include <iostream>
#include <limits>
Include dependency graph for brent_method_extrema.cpp:

Go to the source code of this file.

Macros

#define _USE_MATH_DEFINES
 required for MS Visual C++
 
#define EPSILON
 system accuracy limit
 

Functions

double get_minima (const std::function< double(double)> &f, double lim_a, double lim_b)
 Get the real root of a function in the given interval.
 
void test1 ()
 Test function to find root for the function \(f(x)= (x-2)^2\) in the interval \([1,5]\)
Expected result = 2.
 
void test2 ()
 Test function to find root for the function \(f(x)= x^{\frac{1}{x}}\) in the interval \([-2,10]\)
Expected result: \(e\approx 2.71828182845904509\).
 
void test3 ()
 Test function to find maxima for the function \(f(x)= \cos x\) in the interval \([0,12]\)
Expected result: \(\pi\approx 3.14159265358979312\).
 
int main ()
 

Detailed Description

Find real extrema of a univariate real function in a given interval using Brent's method.

Refer the algorithm discoverer's publication online and also associated book:

‍R. P. Brent, Algorithms for Minimization without Derivatives, Prentice-Hall, Englewood Cliffs, New Jersey, 1973

See also
golden_search_extrema.cpp
Author
Krishna Vedala

Definition in file brent_method_extrema.cpp.

Macro Definition Documentation

◆ _USE_MATH_DEFINES

#define _USE_MATH_DEFINES

required for MS Visual C++

Definition at line 16 of file brent_method_extrema.cpp.

◆ EPSILON

#define EPSILON
Value:
std::sqrt( \
std::numeric_limits<double>::epsilon())

system accuracy limit

Definition at line 24 of file brent_method_extrema.cpp.

24#define EPSILON \
25 std::sqrt( \
26 std::numeric_limits<double>::epsilon())

Function Documentation

◆ get_minima()

double get_minima ( const std::function< double(double)> & f,
double lim_a,
double lim_b )

Get the real root of a function in the given interval.

Parameters
ffunction to get root for
lim_alower limit of search window
lim_bupper limit of search window
Returns
root found in the interval

Definition at line 36 of file brent_method_extrema.cpp.

37 {
38 uint32_t iters = 0;
39
40 if (lim_a > lim_b) {
41 std::swap(lim_a, lim_b);
42 } else if (std::abs(lim_a - lim_b) <= EPSILON) {
43 std::cerr << "Search range must be greater than " << EPSILON << "\n";
44 return lim_a;
45 }
46
47 // golden ratio value
48 const double M_GOLDEN_RATIO = (3.f - std::sqrt(5.f)) / 2.f;
49
50 double v = lim_a + M_GOLDEN_RATIO * (lim_b - lim_a);
51 double u, w = v, x = v;
52 double fu, fv = f(v);
53 double fw = fv, fx = fv;
54
55 double mid_point = (lim_a + lim_b) / 2.f;
56 double p = 0, q = 0, r = 0;
57
58 double d, e = 0;
59 double tolerance, tolerance2;
60
61 do {
62 mid_point = (lim_a + lim_b) / 2.f;
63 tolerance = EPSILON * std::abs(x);
64 tolerance2 = 2 * tolerance;
65
66 if (std::abs(e) > tolerance2) {
67 // fit parabola
68 r = (x - w) * (fx - fv);
69 q = (x - v) * (fx - fw);
70 p = (x - v) * q - (x - w) * r;
71 q = 2.f * (q - r);
72 if (q > 0)
73 p = -p;
74 else
75 q = -q;
76 r = e;
77 e = d;
78 }
79
80 if (std::abs(p) < std::abs(0.5 * q * r) && p < q * (lim_b - x)) {
81 // parabolic interpolation step
82 d = p / q;
83 u = x + d;
84 if (u - lim_a < tolerance2 || lim_b - u < tolerance2)
85 d = x < mid_point ? tolerance : -tolerance;
86 } else {
87 // golden section interpolation step
88 e = (x < mid_point ? lim_b : lim_a) - x;
89 d = M_GOLDEN_RATIO * e;
90 }
91
92 // evaluate not too close to x
93 if (std::abs(d) >= tolerance)
94 u = d;
95 else if (d > 0)
96 u = tolerance;
97 else
98 u = -tolerance;
99 u += x;
100 fu = f(u);
101
102 // update variables
103 if (fu <= fx) {
104 if (u < x)
105 lim_b = x;
106 else
107 lim_a = x;
108 v = w;
109 fv = fw;
110 w = x;
111 fw = fx;
112 x = u;
113 fx = fu;
114 } else {
115 if (u < x)
116 lim_a = u;
117 else
118 lim_b = u;
119 if (fu <= fw || x == w) {
120 v = w;
121 fv = fw;
122 w = u;
123 fw = fu;
124 } else if (fu <= fv || v == x || v == w) {
125 v = u;
126 fv = fu;
127 }
128 }
129
130 iters++;
131 } while (std::abs(x - mid_point) > (tolerance - (lim_b - lim_a) / 2.f));
132
133 std::cout << " (iters: " << iters << ") ";
134
135 return x;
136}
#define EPSILON
system accuracy limit
double f(double x)
A function f(x) that will be used to test the method.

◆ main()

int main ( void )

Main function

Definition at line 205 of file brent_method_extrema.cpp.

205 {
206 std::cout.precision(18);
207
208 std::cout << "Computations performed with machine epsilon: " << EPSILON
209 << "\n";
210
211 test1();
212 test2();
213 test3();
214
215 return 0;
216}
void test2()
Test function to find root for the function in the interval Expected result: .
void test1()
Test function to find root for the function in the interval Expected result = 2.
void test3()
Test function to find maxima for the function in the interval Expected result: .

◆ test1()

void test1 ( )

Test function to find root for the function \(f(x)= (x-2)^2\) in the interval \([1,5]\)
Expected result = 2.

Definition at line 144 of file brent_method_extrema.cpp.

144 {
145 // define the function to minimize as a lambda function
146 std::function<double(double)> f1 = [](double x) {
147 return (x - 2) * (x - 2);
148 };
149
150 std::cout << "Test 1.... ";
151
152 double minima = get_minima(f1, -1, 5);
153
154 std::cout << minima << "...";
155
156 assert(std::abs(minima - 2) < EPSILON);
157 std::cout << "passed\n";
158}
double get_minima(const std::function< double(double)> &f, double lim_a, double lim_b)
Get the real root of a function in the given interval.

◆ test2()

void test2 ( )

Test function to find root for the function \(f(x)= x^{\frac{1}{x}}\) in the interval \([-2,10]\)
Expected result: \(e\approx 2.71828182845904509\).

Definition at line 166 of file brent_method_extrema.cpp.

166 {
167 // define the function to maximize as a lambda function
168 // since we are maximixing, we negated the function return value
169 std::function<double(double)> func = [](double x) {
170 return -std::pow(x, 1.f / x);
171 };
172
173 std::cout << "Test 2.... ";
174
175 double minima = get_minima(func, -2, 5);
176
177 std::cout << minima << " (" << M_E << ")...";
178
179 assert(std::abs(minima - M_E) < EPSILON);
180 std::cout << "passed\n";
181}

◆ test3()

void test3 ( )

Test function to find maxima for the function \(f(x)= \cos x\) in the interval \([0,12]\)
Expected result: \(\pi\approx 3.14159265358979312\).

Definition at line 189 of file brent_method_extrema.cpp.

189 {
190 // define the function to maximize as a lambda function
191 // since we are maximixing, we negated the function return value
192 std::function<double(double)> func = [](double x) { return std::cos(x); };
193
194 std::cout << "Test 3.... ";
195
196 double minima = get_minima(func, -4, 12);
197
198 std::cout << minima << " (" << M_PI << ")...";
199
200 assert(std::abs(minima - M_PI) < EPSILON);
201 std::cout << "passed\n";
202}