From 4eee4ee7dabfca9835618f471a0e8671a2237b51 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sat, 20 Jun 2020 22:16:37 -0400 Subject: [PATCH 01/10] enable AlignConsecutiveMacros --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6d75a1390..245be1a04 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "C_Cpp.clang_format_style": "{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: true, ColumnLimit: 80, AccessModifierOffset: -3 }", + "C_Cpp.clang_format_style": "{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: true, ColumnLimit: 80, AccessModifierOffset: -3, AlignConsecutiveMacros: true }", "editor.formatOnSave": true, "editor.formatOnType": true, "editor.formatOnPaste": true From b5e25f44cfcc251f3e47c24bdebb455f2fd601bd Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 00:09:09 -0400 Subject: [PATCH 02/10] added minima algorithm using golden section search --- numerical_methods/golden_search_extrema.cpp | 128 ++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 numerical_methods/golden_search_extrema.cpp diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp new file mode 100644 index 000000000..2d4611561 --- /dev/null +++ b/numerical_methods/golden_search_extrema.cpp @@ -0,0 +1,128 @@ +/** + * \file + * \brief Find extrema of a univariate real function in a given interval using + * [golden section search + * algorithm](https://en.wikipedia.org/wiki/Golden-section_search). + * + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#define _USE_MATH_DEFINES //< required for MS Visual C++ +#include +#include +#include +#include +#include +#include + +#define EPSILON 1e-7 ///< solution accuracy limit +#define M_GOLDEN_RATIO \ + static_cast(1.618033988749894848204586834) ///< golden ratio value + +/** + * @brief Get the minima of a function in the given interval. To get the maxima, + * simply negate the function. + * + * @param f function to get minima for + * @param lim_a lower limit of search window + * @param lim_b upper limit of search window + * @return local minima found in the interval + */ +double get_minima(const std::function &f, double lim_a, + double lim_b) { + double c, d; + double prev_mean, mean = std::numeric_limits::infinity(); + + do { + prev_mean = mean; + + c = lim_b - (lim_b - lim_a) / M_GOLDEN_RATIO; + d = lim_a + (lim_b - lim_a) / M_GOLDEN_RATIO; + + if (f(c) < f(d)) { + lim_b = d; + } else { + lim_a = c; + } + + mean = (lim_a + lim_b) * 0.5f; + } while (std::abs(mean - prev_mean) > EPSILON); + + return mean; +} + +/** + * @brief Test function to find minima for the function + * \f$f(x)= (x-2)^2\f$ + * in the interval \f$[1,5]\f$ + * \n Expected result = 2 + */ +void test1() { + // define the function to minimize as a lambda function + std::function f1 = [](double x) { + return (x - 2) * (x - 2); + }; + + std::cout << "Test 1.... "; + + double minima = get_minima(f1, 1, 5); + + std::cout << minima << "..."; + + assert(std::abs(minima - 2) < EPSILON); + std::cout << "passed\n"; +} + +/** + * @brief Test function to find *maxima* for the function + * \f$f(x)= x^{\frac{1}{x}}\f$ + * in the interval \f$[-2,10]\f$ + * \n Expected result: \f$e\approx 2.71828182845904509\f$ + */ +void test2() { + // define the function to maximize as a lambda function + // since we are maximixing, we negated the function return value + std::function func = [](double x) { + return -std::pow(x, 1.f / x); + }; + + std::cout << "Test 2.... "; + + double minima = get_minima(func, -2, 10); + + std::cout << minima << " (" << M_E << ")..."; + + assert(std::abs(minima - M_E) < EPSILON); + std::cout << "passed\n"; +} + +/** + * @brief Test function to find *maxima* for the function + * \f$f(x)= \cos x\f$ + * in the interval \f$[0,12]\f$ + * \n Expected result: \f$\pi\approx 3.14159265358979312\f$ + */ +void test3() { + // define the function to maximize as a lambda function + // since we are maximixing, we negated the function return value + std::function func = [](double x) { return std::cos(x); }; + + std::cout << "Test 3.... "; + + double minima = get_minima(func, 0, 12); + + std::cout << minima << " (" << M_PI << ")..."; + + assert(std::abs(minima - M_PI) < EPSILON); + std::cout << "passed\n"; +} + +/** Main function */ +int main() { + std::cout.precision(18); + + test1(); + test2(); + test3(); + + return 0; +} From 33b8169f41b429b70f97fef40a484ed6e4dbda26 Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Sun, 21 Jun 2020 04:10:37 +0000 Subject: [PATCH 03/10] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 071ee8b95..1ba34af53 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -132,6 +132,7 @@ * [Durand Kerner Roots](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/durand_kerner_roots.cpp) * [False Position](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/false_position.cpp) * [Gaussian Elimination](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/gaussian_elimination.cpp) + * [Golden Search Extrema](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/golden_search_extrema.cpp) * [Lu Decompose](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/lu_decompose.cpp) * [Newton Raphson Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/newton_raphson_method.cpp) * [Ode Forward Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/numerical_methods/ode_forward_euler.cpp) From bf2b70313181cc31ce42a2807078df2770e8357f Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 00:18:34 -0400 Subject: [PATCH 04/10] remove redundant header includes --- numerical_methods/golden_search_extrema.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 2d4611561..538c53961 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -9,10 +9,8 @@ #define _USE_MATH_DEFINES //< required for MS Visual C++ #include #include -#include #include #include -#include #define EPSILON 1e-7 ///< solution accuracy limit #define M_GOLDEN_RATIO \ From d8e76eda6f3d4091c0b61579a10bce895d7c16a8 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 00:21:54 -0400 Subject: [PATCH 05/10] added limits header file --- numerical_methods/golden_search_extrema.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 538c53961..5a327c1ef 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #define EPSILON 1e-7 ///< solution accuracy limit #define M_GOLDEN_RATIO \ From 00dda54f4f1f52ad497747a2316309cc2d0cbf05 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 17:12:18 -0400 Subject: [PATCH 06/10] ensure search window is increasing and greater than tolerance --- numerical_methods/golden_search_extrema.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 5a327c1ef..5d84c5572 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -31,6 +31,14 @@ double get_minima(const std::function &f, double lim_a, double c, d; double prev_mean, mean = std::numeric_limits::infinity(); + // ensure that lim_a < lim_b + if (lim_a > lim_b) { + std::swap(lim_a, lim_b); + } else if (std::abs(lim_a - lim_b) <= EPSILON) { + std::cerr << "Search range must be greater than " << EPSILON << "\n"; + return lim_a; + } + do { prev_mean = mean; From 9c186095a806e293e3da3c6fdf3562b864789f0a Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 17:31:53 -0400 Subject: [PATCH 07/10] print number of steps taken for convergence --- numerical_methods/golden_search_extrema.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 5d84c5572..44e8e2c12 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -28,6 +28,7 @@ */ double get_minima(const std::function &f, double lim_a, double lim_b) { + uint32_t iters = 0; double c, d; double prev_mean, mean = std::numeric_limits::infinity(); @@ -51,10 +52,12 @@ double get_minima(const std::function &f, double lim_a, lim_a = c; } - mean = (lim_a + lim_b) * 0.5f; + mean = (lim_a + lim_b) / 2.f; + iters++; } while (std::abs(mean - prev_mean) > EPSILON); - return mean; + std::cout << " (iters: " << iters << ") "; + return prev_mean; } /** @@ -115,7 +118,7 @@ void test3() { std::cout << "Test 3.... "; - double minima = get_minima(func, 0, 12); + double minima = get_minima(func, -4, 12); std::cout << minima << " (" << M_PI << ")..."; @@ -127,6 +130,9 @@ void test3() { int main() { std::cout.precision(18); + std::cout << "Computations performed with machine epsilon: " << EPSILON + << "\n"; + test1(); test2(); test3(); From 21e93919f3255103d0442733eec0952b3b9c75d2 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 17:50:04 -0400 Subject: [PATCH 08/10] limit print precision to 9 decimals --- numerical_methods/golden_search_extrema.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 44e8e2c12..41bf9c8d3 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -128,7 +128,7 @@ void test3() { /** Main function */ int main() { - std::cout.precision(18); + std::cout.precision(9); std::cout << "Computations performed with machine epsilon: " << EPSILON << "\n"; From e71ee9ccb0aa58aeb10fff22d5c48e2e65fe44bb Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 18:30:31 -0400 Subject: [PATCH 09/10] better documentation of algorithm --- numerical_methods/golden_search_extrema.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 41bf9c8d3..0969544e5 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -14,12 +14,11 @@ #include #define EPSILON 1e-7 ///< solution accuracy limit -#define M_GOLDEN_RATIO \ - static_cast(1.618033988749894848204586834) ///< golden ratio value /** * @brief Get the minima of a function in the given interval. To get the maxima, - * simply negate the function. + * simply negate the function. The golden ratio used here is:\f[ + * k=\frac{3-\sqrt{5}}{2} \approx 0.381966\ldots\f] * * @param f function to get minima for * @param lim_a lower limit of search window @@ -32,6 +31,9 @@ double get_minima(const std::function &f, double lim_a, double c, d; double prev_mean, mean = std::numeric_limits::infinity(); + // golden ratio value + const double M_GOLDEN_RATIO = (1.f + std::sqrt(5.f)) / 2.f; + // ensure that lim_a < lim_b if (lim_a > lim_b) { std::swap(lim_a, lim_b); @@ -43,18 +45,24 @@ double get_minima(const std::function &f, double lim_a, do { prev_mean = mean; - c = lim_b - (lim_b - lim_a) / M_GOLDEN_RATIO; - d = lim_a + (lim_b - lim_a) / M_GOLDEN_RATIO; + // compute the section ratio width + double ratio = (lim_b - lim_a) / M_GOLDEN_RATIO; + c = lim_b - ratio; // right-side section start + d = lim_a + ratio; // left-side section end if (f(c) < f(d)) { + // select left section lim_b = d; } else { + // selct right section lim_a = c; } mean = (lim_a + lim_b) / 2.f; iters++; - } while (std::abs(mean - prev_mean) > EPSILON); + + // continue till the interval width is greater than sqrt(system epsilon) + } while (std::abs(lim_a - lim_b) > EPSILON); std::cout << " (iters: " << iters << ") "; return prev_mean; From 744da70bbf744c77579edd9540ce9d757106dbe4 Mon Sep 17 00:00:00 2001 From: Krishna Vedala <7001608+kvedala@users.noreply.github.com> Date: Sun, 21 Jun 2020 22:28:50 -0400 Subject: [PATCH 10/10] added see-also reference to brents method --- numerical_methods/golden_search_extrema.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/numerical_methods/golden_search_extrema.cpp b/numerical_methods/golden_search_extrema.cpp index 0969544e5..1ca47949f 100644 --- a/numerical_methods/golden_search_extrema.cpp +++ b/numerical_methods/golden_search_extrema.cpp @@ -4,6 +4,7 @@ * [golden section search * algorithm](https://en.wikipedia.org/wiki/Golden-section_search). * + * \see brent_method_extrema.cpp * \author [Krishna Vedala](https://github.com/kvedala) */ #define _USE_MATH_DEFINES //< required for MS Visual C++