19namespace triqs::experimental::utility {
22 using triqs::utility::report_stream;
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) {
49 delta_x = abs(delta_x);
52 double eps = (y1 - y_value >= 0) ? 1.0 : -1.0;
59 for (; nbre_loop <= max_loops && (y2 - y_value) * eps > 0 && abs(y2 - y_value) > precision; ++nbre_loop) {
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) {
103 out << fmt::format(
" {:>4} | {:^24} | residual\n",
"iter", fmt::format(
"{} interval", x_name));
104 out << fmt::format(
"------+--------------------------+----------\n");
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;
110 for (; nbre_loop <= max_loops && abs(yfound - y_target) > precision; ++nbre_loop) {
111 x = x1 + (x2 - x1) * (y_target - y1) / (y2 - y1);
113 if ((y1 - y_target) * (yfound - y_target) > 0) {
120 out << fmt::format(
" {:4d} | [{:10g}, {:10g}] | {:8.2e}\n", nbre_loop + 1, x1, x2, abs(yfound - y_target));
123 if (abs(yfound - y_target) < precision) {
124 out << fmt::format(
"Converged ({} iters): {} = {:g}, {} = {:g}\n", nbre_loop, x_name, x, y_name, yfound);
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)};
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) {
158 out << fmt::format(
" {:>4} | {:^24} | residual\n",
"iter", fmt::format(
"{} interval", x_name));
159 out << fmt::format(
"------+--------------------------+----------\n");
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);
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};
170 (y_mid - y_target >= 0 ? x_high : x_low) = x_mid;
172 out << fmt::format(
" {:4d} | [{:10g}, {:10g}] | {:8.2e}\n", it + 1, x_low, x_high, abs(y_mid - y_target));
175 out << fmt::format(
"Failed: {} did not converge to {:g} after {} iters\n", x_name, y_target, max_loops);
177 throw std::runtime_error{fmt::format(
"Bisection adjustment for {} failed after {} iterations", x_name, max_loops)};
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) {
205 if (verbosity) fmt::print(
"Root finder: seeking {} s.t. {} = {:g} \u00b1 {:g}\n", x_name, y_name, y_value, precision);
207 auto [x1, x2] =
find_bounds(f, x_init, y_value, delta_x, precision, max_loops);
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);
214 throw std::runtime_error(
"Not a valid choice of root finder method!");
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.