The idea is to call similar Runge-Kutta function templates in a loop instead of doing it one by one. I've looked at similar solutions, I also tried void*
, but was not able to apply to my problem due to conversion errors.
EDIT: these function templates are supposed to be used with fixed types, it's an overkill, but I would like to see whether there is an elegant solution.
Here is the full code:
#include <iostream>
#include <iomanip>
#include <cmath>
#include <functional>
template <typename X, typename F, typename H = double>
X runge_kutta1(const X &x, const F &f, H h)
{
return x + h * f(x);
}
template <typename X, typename F, typename H = double>
X runge_kutta2(const X &x, const F &f, H h)
{
X k1 = f(x);
return x + 0.5 * h * (k1 + f(x + h * k1));
}
struct pair
{
double v;
double w;
pair(double v, double w)
: v{v}, w{w}
{
}
};
inline pair operator*(double h, pair p)
{
return {h * p.v, h * p.w};
}
inline pair operator+(pair p1, pair p2)
{
return {p1.v + p2.v, p1.w + p2.w};
}
inline std::ostream &operator<<(std::ostream &stream, const pair &p)
{
stream << p.v << ", " << p.w;
return stream;
}
int main() {
{
double x = 0.0;
double x1 = 1.0;
double lambda = 2;
double h = 1.0E-3;
pair p{1.0 / lambda, 0.0};
const std::function<pair(pair)> cat =
[&lambda](const pair &p) { return pair{p.w, lambda * sqrt(1.0 + p.w * p.w)}; };
while (x + h < x1)
{
p = runge_kutta1(p, cat, h);
x = x + h;
}
p = runge_kutta1(p, cat, x1 - x);
pair expected = {cosh(lambda * x1) / lambda, sinh(lambda * x1)};
pair error = p + -1.0 * expected;
std::cout << std::setprecision(18) << "runge_kutta1:\nFinal result: " << p << "\n";
std::cout << "Error: " << error << "\n\n";
}
{
double x = 0.0;
double x1 = 1.0;
double lambda = 2;
double h = 1.0E-3;
pair p{1.0 / lambda, 0.0};
const std::function<pair(pair)> cat =
[&lambda](const pair &p) { return pair{p.w, lambda * sqrt(1.0 + p.w * p.w)}; };
while (x + h < x1)
{
p = runge_kutta2(p, cat, h);
x = x + h;
}
p = runge_kutta2(p, cat, x1 - x);
pair expected = {cosh(lambda * x1) / lambda, sinh(lambda * x1)};
pair error = p + -1.0 * expected;
std::cout << "runge_kutta2:\nFinal result: " << p << "\n";
std::cout << "Error: " << error << "\n";
}
}
What I would like to have (the actual algorithm is simplified for the sake of readability):
std::vector<?> functions{runge_kutta1, runge_kutta2}; // two just as an example
double p = 1.0;
double h = 1.0E-3;
double lambda = 2;
const std::function<pair(pair)> cat =
[&lambda](const pair &p) { return pair{p.w, lambda * sqrt(1.0 + p.w * p.w)}; };
for (const auto& func : functions) {
double t = func(p, cat, h);
std::cout << t << "\n";
}