TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
brent_method_extrema.cpp
Go to the documentation of this file.
1
16#define _USE_MATH_DEFINES
17#include <cassert>
18#include <cmath>
19#include <cstdint>
20#include <functional>
21#include <iostream>
22#include <limits>
23
24#define EPSILON \
25 std::sqrt( \
26 std::numeric_limits<double>::epsilon())
27
36double get_minima(const std::function<double(double)> &f, double lim_a,
37 double lim_b) {
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}
137
144void test1() {
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}
159
166void test2() {
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}
182
189void test3() {
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}
203
205int main() {
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}
#define EPSILON
system accuracy limit
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.
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 test3()
Test function to find maxima for the function in the interval Expected result: .