TRIQS/TRIQS 4.0.0
Researching Interacting Quantum Systems
Loading...
Searching...
No Matches
root_finder.hpp
1// Copyright (c) 2025--present, The Simons Foundation
2// This file is part of TRIQS/modest and is licensed under the terms of GPLv3 or later.
3// SPDX-License-Identifier: GPL-3.0-or-later
4// See LICENSE in the root of this distribution for details.
5
6#pragma once
7
9
10#include <fmt/core.h>
11
12#include <cmath>
13#include <functional>
14#include <iostream>
15#include <stdexcept>
16#include <string>
17#include <utility>
18
19namespace triqs::experimental::utility {
20
21 using std::abs;
22 using triqs::utility::report_stream;
23
28
29 //------------------------------------------------------
45 inline std::pair<double, double> find_bounds(std::function<double(double)> f, double x_init, double y_value, double delta_x, double precision,
46 long max_loops = 1000) {
47
48 double x = x_init;
49 delta_x = abs(delta_x);
50
51 double y1 = f(x);
52 double eps = (y1 - y_value >= 0) ? 1.0 : -1.0;
53
54 double x1 = x;
55 double y2 = y1;
56 double x2 = x1;
57
58 long nbre_loop = 0;
59 for (; nbre_loop <= max_loops && (y2 - y_value) * eps > 0 && abs(y2 - y_value) > precision; ++nbre_loop) {
60 x2 -= eps * delta_x;
61 y2 = f(x2);
62 }
63
64 if (x1 > x2) {
65 std::swap(x1, x2);
66 std::swap(y1, y2);
67 }
68 return {x1, x2};
69 }
70 //------------------------------------------------------
71
92 inline std::pair<double, double> dichotomy(std::function<double(double)> f, double x_low, double x_high, double y_target, double precision,
93 long max_loops, std::string x_name, std::string y_name, bool verbosity) {
94
95 auto out = report_stream(std::cout, verbosity);
96
97 auto x1 = x_low;
98 auto x2 = x_high;
99
100 auto y1 = f(x_low);
101 auto y2 = f(x_high);
102
103 out << fmt::format(" {:>4} | {:^24} | residual\n", "iter", fmt::format("{} interval", x_name));
104 out << fmt::format("------+--------------------------+----------\n");
105
106 double yfound = (abs(y1 - y_target) < abs(y2 - y_target)) ? y1 : y2;
107 double x = (abs(y1 - y_target) < abs(y2 - y_target)) ? x1 : x2;
108
109 long nbre_loop = 0;
110 for (; nbre_loop <= max_loops && abs(yfound - y_target) > precision; ++nbre_loop) {
111 x = x1 + (x2 - x1) * (y_target - y1) / (y2 - y1);
112 yfound = f(x);
113 if ((y1 - y_target) * (yfound - y_target) > 0) {
114 x1 = x;
115 y1 = yfound;
116 } else {
117 x2 = x;
118 y2 = yfound;
119 }
120 out << fmt::format(" {:4d} | [{:10g}, {:10g}] | {:8.2e}\n", nbre_loop + 1, x1, x2, abs(yfound - y_target));
121 }
122
123 if (abs(yfound - y_target) < precision) {
124 out << fmt::format("Converged ({} iters): {} = {:g}, {} = {:g}\n", nbre_loop, x_name, x, y_name, yfound);
125 return {x, yfound};
126 } else {
127 out << fmt::format("Failed: {} did not converge to {:g} after {} iters\n", x_name, y_target, nbre_loop);
128 throw std::runtime_error{fmt::format("Dichotomy adjustment for {} failed after {} iterations", x_name, nbre_loop)};
129 }
130 }
131 //------------------------------------------------------
132
153 inline std::pair<double, double> bisection(std::function<double(double)> f, double x_low, double x_high, double y_target, double precision,
154 long max_loops, std::string x_name, std::string y_name, bool verbosity) {
155
156 auto out = report_stream(std::cout, verbosity);
157
158 out << fmt::format(" {:>4} | {:^24} | residual\n", "iter", fmt::format("{} interval", x_name));
159 out << fmt::format("------+--------------------------+----------\n");
160
161 for (auto it = 0; it < max_loops; it++) {
162 auto x_mid = (x_high + x_low) / 2.0;
163 auto y_mid = f(x_mid);
164
165 if (abs(y_mid - y_target) <= precision) {
166 out << fmt::format("Converged ({} iters): {} = {:g}, {} = {:g}\n", it + 1, x_name, x_mid, y_name, y_mid);
167 return {x_mid, y_mid};
168 }
169
170 (y_mid - y_target >= 0 ? x_high : x_low) = x_mid;
171
172 out << fmt::format(" {:4d} | [{:10g}, {:10g}] | {:8.2e}\n", it + 1, x_low, x_high, abs(y_mid - y_target));
173 }
174
175 out << fmt::format("Failed: {} did not converge to {:g} after {} iters\n", x_name, y_target, max_loops);
176
177 throw std::runtime_error{fmt::format("Bisection adjustment for {} failed after {} iterations", x_name, max_loops)};
178 }
179 //------------------------------------------------------
180
201 inline std::pair<double, double> root_finder(std::string method, std::function<double(double)> f, double x_init, double y_value, double precision,
202 double delta_x, long max_loops = 1000, std::string x_name = "", std::string y_name = "",
203 bool verbosity = false) {
204
205 if (verbosity) fmt::print("Root finder: seeking {} s.t. {} = {:g} \u00b1 {:g}\n", x_name, y_name, y_value, precision);
206
207 auto [x1, x2] = find_bounds(f, x_init, y_value, delta_x, precision, max_loops);
208
209 if (method == "dichotomy") {
210 return dichotomy(f, x1, x2, y_value, precision, max_loops, x_name, y_name, verbosity);
211 } else if (method == "bisection") {
212 return bisection(f, x1, x2, y_value, precision, max_loops, x_name, y_name, verbosity);
213 } else {
214 throw std::runtime_error("Not a valid choice of root finder method!");
215 }
216 }
217
219
220} // namespace triqs::experimental::utility
Output stream with a configurable verbosity level.
std::pair< double, double > find_bounds(std::function< double(double)> f, double x_init, double y_value, double delta_x, double precision, long max_loops=1000)
Find a lower and an upper bound that bracket the solution of .
std::pair< double, double > dichotomy(std::function< double(double)> f, double x_low, double x_high, double y_target, double precision, long max_loops, std::string x_name, std::string y_name, bool verbosity)
Solve on a bracketing interval using the false-position (dichotomy) method.
std::pair< double, double > bisection(std::function< double(double)> f, double x_low, double x_high, double y_target, double precision, long max_loops, std::string x_name, std::string y_name, bool verbosity)
Solve on a bracketing interval using the bisection method.
std::pair< double, double > root_finder(std::string method, std::function< double(double)> f, double x_init, double y_value, double precision, double delta_x, long max_loops=1000, std::string x_name="", std::string y_name="", bool verbosity=false)
Find the value that solves using the requested root-finding method.
Verbosity-controlled output stream and an auto-indenting std::ostream.