C++ workaround for doubles as template parameters - c++

I know that doubles can't be template parameters so I'm looking for another way to create a function with several parameters. My current (obviously wrong) code looks like this:
template<double B1, double B2, double B3, double C1, double C2, double C3>
double sellmeier(const double wavelength) {
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
}
Is there a way to create a function that takes several non integral type parameters and one argument without making every parameter an argument too?

What You want here is a policy class which will supply your function with the required values (SpecificConstants).
struct SpecificConstants
{
static constexpr double b1 { 0.6961663 };
static constexpr double b2 { 0.4079426 };
static constexpr double b3 { 0.8974794 };
static constexpr double c1 { 0.0684043 * 0.0684043 };
static constexpr double c2 { 0.1162414 * 0.1162414 };
static constexpr double c3 { 9.896161 * 9.896161 };
};
Your function will only require this policy class (Constants)
template< typename Constants >
double sellmeier( const double wavelength )
{
double refractive_index_sq = 1;
double lambda_sq = std::pow( wavelength, 2 );
refractive_index_sq += Constants::b1 * lambda_sq / ( lambda_sq - Constants::c1 );
refractive_index_sq += Constants::b2 * lambda_sq / ( lambda_sq - Constants::c2 );
refractive_index_sq += Constants::b3 * lambda_sq / ( lambda_sq - Constants::c3 );
return refractive_index_sq;
}
Then, the function can be called like this:
sellmeier< SpecificConstants >( 2.0 );

In c++14 you can do the following, shown with one parameter for brevity's sake:
constexpr double GetB1(int b1Index)
{
switch (b1Index)
{
case 0: return 1.2345;
case 1: return 2.3456;
default: return 3.4567;
}
}
template<int B1Index>
double obviouslyNotSellmeier(const double wavelength) {
return wavelength * GetB1(B1Index);
}
obviouslyNotSellmeier<1>(0.123)
Though it becomes very unfriendly to the caller.

Is there a way to create a function that takes several non integral type parameters and one argument without making every parameter an argument too?
I don't know if it's a good idea but... yes, I suppose you can wrap your floating points values as static constant inside struct's.
Starting from C++11 (constexpr) you can simply define
struct X1 { static constexpr double value { 1.2 }; };
struct X2 { static constexpr double value { 2.3 }; };
struct X3 { static constexpr double value { 3.4 }; };
struct Y1 { static constexpr double value { 4.5 }; };
struct Y2 { static constexpr double value { 5.6 }; };
struct Y3 { static constexpr double value { 6.7 }; };
pass they as template parameter to sellmeier()
sellmeier<X1, X2, X3, Y1, Y2, Y3>(1.0);
and use the value of types inside sellmeier()
template <typename B1, typename B2, typename B3,
typename C1, typename C2, typename C3>
double sellmeier (const double wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1::value*lambda_sq/(lambda_sq-C1::value);
refractive_index_sq += B2::value*lambda_sq/(lambda_sq-C2::value);
refractive_index_sq += B3::value*lambda_sq/(lambda_sq-C3::value);
return refractive_index_sq;
}
Before C++11 (no constexpr available) the syntax, to define the wrapping structs, is a little more annoying: you have to initialize the const value outside of the body of the structs
struct X1 { static double const value; };
struct X2 { static double const value; };
struct X3 { static double const value; };
struct Y1 { static double const value; };
struct Y2 { static double const value; };
struct Y3 { static double const value; };
double const X1::value = 1.2;
double const X2::value = 2.3;
double const X3::value = 3.4;
double const Y1::value = 4.5;
double const Y2::value = 5.6;
double const Y3::value = 6.7;

As I don't need the parameters at compile time I realized a functor is the better/correct solution:
struct sellmeier {
sellmeier(double B1, double B2, double B3, double C1, double C2, double C3) :
B1(B1), B2(B2), B3(B3), C1(C1), C2(C2), C3(C3) {}
double operator()(const double wavelength) {
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1 * lambda_sq / (lambda_sq - C1);
refractive_index_sq += B2 * lambda_sq / (lambda_sq - C2);
refractive_index_sq += B3 * lambda_sq / (lambda_sq - C3);
return refractive_index_sq;
}
private:
double B1, B2, B3, C1, C2, C3;
};
//functor with sellmeier coefficients for fused quartz
auto sellmeier_fused_quartz = sellmeier(0.6961663, 0.4079426, 0.8974794, 0.0684043*0.0684043, 0.1162414*0.1162414, 9.896161*9.896161);

As I don't need the parameters at compile time I realized a functor is the better/correct solution
In this case, if you can use C++11, you can simply write a lambda
#include <cmath>
int main ()
{
auto B1=0.6961663;
auto B2=0.4079426;
auto B3=0.8974794;
auto C1=0.0684043*0.0684043;
auto C2=0.1162414*0.1162414;
auto C3=9.896161*9.896161;
auto sellmeier = [=] (double const wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
};
sellmeier(1.0);
}
Starting from C++14, you can simplify (IMHO) as follows
#include <cmath>
int main ()
{
auto sellmeier = [B1=0.6961663,
B2=0.4079426,
B3=0.8974794,
C1=0.0684043*0.0684043,
C2=0.1162414*0.1162414,
C3=9.896161*9.896161] (double const wavelength)
{
double refractive_index_sq = 1;
double lambda_sq = std::pow(wavelength, 2);
refractive_index_sq += B1*lambda_sq/(lambda_sq-C1);
refractive_index_sq += B2*lambda_sq/(lambda_sq-C2);
refractive_index_sq += B3*lambda_sq/(lambda_sq-C3);
return refractive_index_sq;
};
sellmeier(1.0);
}

Related

Nonlinear least-squares fitting with two independent variables in C++: implementing GSL algorithm

Following up to a previous question I asked in Fixing parameters of a fitting function in Nonlinear Least-Square GSL (successfully answered by #zkoza), I would like to implement an algorithm that can fit data to a non-linear function, by fixing some of its parameters while leaving other parameters to change for finding the best fit to the data. The difference to my previous question is that I want to have two independent variables instead of one independent variable.
Non-linear function used to fit the data
double gaussian(double x, double b, double a, double c)
{
const double z = (x - b) / c;
return a * std::exp(-0.5 * z * z);
}
In my previous question I was considering that x was the only independent variable. Now I would like to consider two independent variables, x and b.
The original algorithm used to fit a non-linear function using only one independent variable (while fixing variable a) is a C++ wrapper of the GSL nonlinear least-squares algorithm (borrowed from https://github.com/Eleobert/gsl-curve-fit/blob/master/example.cpp):
template <typename F, size_t... Is>
auto gen_tuple_impl(F func, std::index_sequence<Is...> )
{
return std::make_tuple(func(Is)...);
}
template <size_t N, typename F>
auto gen_tuple(F func)
{
return gen_tuple_impl(func, std::make_index_sequence<N>{} );
}
template <class R, class... ARGS>
struct function_ripper {
static constexpr size_t n_args = sizeof...(ARGS);
};
template <class R, class... ARGS>
auto constexpr n_params(R (ARGS...) )
{
return function_ripper<R, ARGS...>();
}
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>
{
// This specifies a trust region method
const gsl_multifit_nlinear_type *T = gsl_multifit_nlinear_trust;
const size_t max_iter = 200;
const double xtol = 1.0e-8;
const double gtol = 1.0e-8;
const double ftol = 1.0e-8;
auto *work = gsl_multifit_nlinear_alloc(T, params, fdf->n, fdf->p);
int info;
// initialize solver
gsl_multifit_nlinear_init(initial_params, fdf, work);
//iterate until convergence
gsl_multifit_nlinear_driver(max_iter, xtol, gtol, ftol, nullptr, nullptr, &info, work);
// result will be stored here
gsl_vector * y = gsl_multifit_nlinear_position(work);
auto result = std::vector<double>(initial_params->size);
for(int i = 0; i < result.size(); i++)
{
result[i] = gsl_vector_get(y, i);
}
auto niter = gsl_multifit_nlinear_niter(work);
auto nfev = fdf->nevalf;
auto njev = fdf->nevaldf;
auto naev = fdf->nevalfvv;
// nfev - number of function evaluations
// njev - number of Jacobian evaluations
// naev - number of f_vv evaluations
//logger::debug("curve fitted after ", niter, " iterations {nfev = ", nfev, "} {njev = ", njev, "} {naev = ", naev, "}");
gsl_multifit_nlinear_free(work);
gsl_vector_free(initial_params);
return result;
}
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*
{
auto* result = gsl_vector_alloc(vec.size());
int i = 0;
for(const auto e: vec)
{
gsl_vector_set(result, i, e);
i++;
}
return result;
}
template<typename C1>
struct fit_data
{
const std::vector<double>& t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
template<typename FitData, int n_params>
int internal_f(const gsl_vector* x, void* params, gsl_vector *f)
{
auto* d = static_cast<FitData*>(params);
// Convert the parameter values from gsl_vector (in x) into std::tuple
auto init_args = [x](int index)
{
return gsl_vector_get(x, index);
};
auto parameters = gen_tuple<n_params>(init_args);
// Calculate the error for each...
for (size_t i = 0; i < d->t.size(); ++i)
{
double ti = d->t[i];
double yi = d->y[i];
auto func = [ti, &d](auto ...xs)
{
// call the actual function to be fitted
return d->f(ti, xs...);
};
auto y = std::apply(func, parameters);
gsl_vector_set(f, i, yi - y);
}
return GSL_SUCCESS;
}
using func_f_type = int (*) (const gsl_vector*, void*, gsl_vector*);
using func_df_type = int (*) (const gsl_vector*, void*, gsl_matrix*);
using func_fvv_type = int (*) (const gsl_vector*, const gsl_vector *, void *, gsl_vector *);
template<auto n>
auto internal_make_gsl_vector_ptr(const std::array<double, n>& vec) -> gsl_vector*;
auto internal_solve_system(gsl_vector* initial_params, gsl_multifit_nlinear_fdf *fdf,
gsl_multifit_nlinear_parameters *params) -> std::vector<double>;
template<typename C1>
auto curve_fit_impl(func_f_type f, func_df_type df, func_fvv_type fvv, gsl_vector* initial_params, fit_data<C1>& fd) -> std::vector<double>
{
assert(fd.t.size() == fd.y.size());
auto fdf = gsl_multifit_nlinear_fdf();
auto fdf_params = gsl_multifit_nlinear_default_parameters();
fdf.f = f;
fdf.df = df;
fdf.fvv = fvv;
fdf.n = fd.t.size();
fdf.p = initial_params->size;
fdf.params = &fd;
// "This selects the Levenberg-Marquardt algorithm with geodesic acceleration."
fdf_params.trs = gsl_multifit_nlinear_trs_lmaccel;
return internal_solve_system(initial_params, &fdf, &fdf_params);
}
template <typename Callable, auto n>
auto curve_fit(Callable f, const std::array<double, n>& initial_params, const std::vector<double>& x, const std::vector<double>& y) -> std::vector<double>
{
// We can't pass lambdas without convert to std::function.
//constexpr auto n = 3;//decltype(n_params(f))::n_args - 5;
//constexpr auto n = 2;
assert(initial_params.size() == n);
auto params = internal_make_gsl_vector_ptr(initial_params);
auto fd = fit_data<Callable>{x, y, f};
return curve_fit_impl(internal_f<decltype(fd), n>, nullptr, nullptr, params, fd);
}
In order to fix one of the parameters of the gaussian function, #zkoza proposed to use functors:
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(double x, double b, double c) const { return gaussian(x, b, a, c); }
};
And these last lines show how I would create a fake dataset of observed data (with some noise which is normally distributed) and test the fitting curve function with two independent variables, given by the vectors xs and bs.
int main()
{
auto device = std::random_device();
auto gen = std::mt19937(device());
auto xs = linspace<std::vector<double>>(0.0, 1.0, 300);
auto bs = linspace<std::vector<double>>(0.4, 1.4, 300);
auto ys = std::vector<double>(xs.size());
double a = 5.0, c = 0.15;
for(size_t i = 0; i < xs.size(); i++)
{
auto y = gaussian(xs[i], a, bs[i], c);
auto dist = std::normal_distribution(0.0, 0.1 * y);
ys[i] = y + dist(gen);
}
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{0.11}, xs, bs, ys);
std::cout << "result: " << r[0] << ' ' << '\n';
std::cout << "error : " << r[0] - c << '\n';
}
Do you have any idea on how I could implement the two-independent variables non-linear fitting?
The solution, as suggested in the comments by #BenVoigt, is to replace the x and b independent variables in the gaussian function with 'one independent variable' given as a vector, whose first element is x and the second element is b.
Also the backbone of the nonlinear fitting needs to be slightly edited. The edits consist:
Replace the fit_data functor with:
struct fit_data
{
const std::vector< vector<double> > &t;
const std::vector<double>& y;
// the actual function to be fitted
C1 f;
};
Such that, the independent variable is no longer a vector but rather a vector of a vector (aka a matrix).
Replace within the function internal_f.
a) double ti = d->t[i] with std::vector<double> ti = d->t[i]
b) auto func = [ti, &d](auto ...xs) with auto func = [ti, &d](auto ...xs_matrix)
c) return d->f(ti, xs...) with return d->f(ti, xs_matrix...)
Replace within curve_fit function:
a) const std::vector<double>& x with const std::vector< vector<double> > &xs_matrix
b) auto fd = fit_data<Callable>{x, y, f} with auto fd = fit_data<Callable>{xs_matrix, y, f}
Whereas the gaussian function, gaussian_fixed_a functor and the fitting function looks like:
double gaussian(std::vector<double> x_vector, double a, double c)
{
const double z = (x_vector[0] - x_vector[1]) / c;
return a * std::exp(-0.5 * z * z);
}
struct gaussian_fixed_a
{
double a;
gaussian_fixed_a(double a) : a{a} {}
double operator()(std::vector<double> x_vector, double c) const { return gaussian(x_vector, a, c); }
};
double fittingTest(const std::vector< vector<double> > &xs_matrix, const std::vector<double> ys, const double a){
gaussian_fixed_a g(a);
auto r = curve_fit(g, std::array{3.0}, xs_matrix, ys);
return r[0]);
}

C++ function that can take integer or float or double or any other castable to float

I am trying to implement a Vector3 struct in C++. I am overloading the "*" operator for handling multiplication with the scalar values. So it will work like this:
v1 = Vector3(1.0f, 1.0f, 1.0f);
v2 = 2*v1;
v3 = 2.4f*v1;
v4 = 2.4*v1;
All 3 operations will return a Vector3 instance. However, I don't want to implement 3 functions for this purpose.
Vector3 operator * (int& const val) {
float _val = static_cast<float> (val);
return Vector3(x * _val, y * _val, z * _val);
}
Vector3 operator * (double& const val) {
float _val = static_cast<float> (val);
return Vector3(x * _val, y * _val, z * _val);
}
Vector3 operator * (float& const val) {
return Vector3(x * val, y * val, z * val);
}
Is there a better way of doing this with one function?
Since you are casting all of the types to float again, you don't need that.
If you defined your function to accept a float, then passed an int or any convertible type, it would be cast to float automatically. The following code shows that
#include <typeinfo>
#include <iostream>
struct Vector3
{
Vector3(float x, float y, float z): x{x}, y{y}, z{z}{}
float x, y, z;
Vector3 operator*(float val)const{
return Vector3{val * x,val * y,val * z};
}
};
int main(){
Vector3 v1{1,2,3};
auto v2 = v1*2;
std::cout << typeid(v2.x).name();
}
Live
If you want to use the multiplication in reverse order
#include <typeinfo>
#include <iostream>
struct Vector3
{
Vector3(float x, float y, float z): x{x}, y{y}, z{z}{}
float x, y, z;
};
Vector3 operator*(float val, const Vector3& v){
return Vector3{val * v.x,val * v.y,val * v.z};
}
int main(){
Vector3 v1{1,2,3};
auto v2 = 2*v1;
std::cout << typeid(v2.x).name();
}
I used public members for simplicity. u may want to use private ones with setters and getters.
If you really must use reference parameters and the float data type internally, and you wish to avoid compiler warnings about implicit conversions, then you can use a templated operator function (note also the modified position of the const qualifier):
template<typename T>
Vector3 operator * (const T& val)
{
float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
return Vector3(x * mul, y * mul, z * mul);
}
You will also need to use a Vector3 object as the first operand of the * operator:
int main()
{
Vector3 v1 = Vector3(1.0f, 1.0f, 1.0f);
// Vector3 v2 = 2 * v1;
// Vector3 v3 = 2.4f * v1; // These won't work!
// Vector3 v4 = 2.4 * v1;
Vector3 v2 = v1 * 2;
Vector3 v3 = v1 * 2.4f; // But these will
Vector3 v4 = v1 * 2.4;
return 0;
}
EDIT: If you want a 'commutative' operator (that is, one in which you could use the scalar operand in either position), then you can declare a friend operator that takes two arguments (the constant and a class reference):
template<typename T>
friend Vector3 operator * (const T& val, const Vector3& vec)
{
float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
return Vector3(vec.x * mul, vec.y * mul, vec.z * mul);
}
As I see, it's enough to define/declare variant with double and it will work with floats and integers as well.
Here is compilable example (just test & demonstration):
class Vector3 {
public:
Vector3(double x, double y, double z): x(x), y(y), z(z) { }
Vector3 operator * (double val) {
return Vector3(x * val,
y * val,
z * val);
}
private:
double x { 0 };
double y { 0 };
double z { 0 };
};
int main()
{
int a = 1;
float b = 2.1;
double c = 3.5;
Vector3 vec1(1, 2.1f, 3);
Vector3 vec2(a, b, c);
auto vec3 = vec1 * a;
auto vec4 = vec1 * b;
auto vec5 = vec1 * c;
return 0;
}

Using function pointer forward declaration as lamba declaration

What's the closest I can get to something like this?
.h:
typedef bool (*DoWorkFunc)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork(DoWorkFunc { return c2.mVal < c1.mVal + fParam1 + fParam2; } );
auto f1 = DoWorkFunc { return (bParam ? dParam1 : c1.mVal) < mVal; };
auto f2 = DoWorkFunc { return ((dParam1 & dParam2) == 0) == bParam; };
auto f = val < 3 ? f1: f2;
DoWork(f);
}
This is the closest clean solution I've been able to get, which requires a mostly copy-pasted solution for the lambda forward declaration.
.h:
typedef bool (*DoWorkFunc)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
#define DoWorkLambda [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork(DoWorkLambda { return c2.mVal < c1.mVal + fParam1 + fParam2; } );
auto f1 = DoWorkLambda { return (bParam ? dParam1 : c1.mVal) < mVal; };
auto f2 = DoWorkLambda { return ((dParam1 & dParam2) == 0) == bParam; };
auto f = val < 3 ? f1: f2;
DoWork(f);
}
This works alright for one-off solution, but ends up with a pretty messy header for multiple functions declarations
.h:
typedef bool (*DoWorkFunc1)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
#define DoWorkLambda1 [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
void DoWork1(DoWorkFunc1 func);
typedef bool (*DoWorkFunc2)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass3& c2);
#define DoWorkLambda2 [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass3& c2) -> bool
void DoWork2(DoWorkFunc2 func);
...
For reference, this is what the code looks like without the preprocessor:
.h:
typedef bool (*DoWorkFunc)(uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2);
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork([](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return c2.mVal < c1.mVal + fParam1 + fParam2;
}
);
auto f1 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return (bParam ? dParam1 : c1.mVal) < mVal;
};
auto f2 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return ((dParam1 & dParam2) == 0) == bParam;
};
auto f = val < 3 ? f1: f2;
DoWork(f);
}
It should be possible to assign a lambda function to the equivalent raw function pointer, but ONLY if it does NOT use the scope arguments - i.e. the square brackets in the lambda declaration MUST be empty.
So you should be able to declare the function type. The using syntax is easiest:
using DoWorkFnType =bool (uint32_t , uint32_t , bool , float , float , MyClass& , MyClass2& );
void DoWork(DoWorkFnType* fn);
bool MyClass::MyFunc(uint32_t val) {
DoWorkFnType* f1 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return (bParam ? dParam1 : c1.mVal) < mVal;
};
DoWorkFnType* f2 = [](uint32_t dParam1, uint32_t dParam2, bool bParam, float fParam1, float fParam2, MyClass& c1, MyClass2& c2) -> bool
{
return ((dParam1 & dParam2) == 0) == bParam;
};
auto f = val < 3 ? f1: f2;
DoWork(f);
}
void DoWork(DoWorkFnType* fn)
{
bool res= fn(arg1,arg2,arg3,arg4,arg5.arg6,arg7);
}
If your lambda uses the local scope then only std::function will work to pass the lambda to a child function.
It is not clear at all from your code what you expect DoWork to do, or how it gathers the 7 argument values needed to call f, so I will need to leave it there.
.h:
struct DoWorkParams {
uint32_t dParam1;
uint32_t dParam2;
bool bParam;
float fParam1;
float fParam2;
MyClass& c1;
MyClass2& c2;
};
typedef bool (*DoWorkFunc)(DoWorkParams);
void DoWork(DoWorkFunc func);
.cpp:
bool MyClass::MyFunc(uint32_t val) {
DoWork([](auto p) { return p.c2.mVal < p.c1.mVal + p.fParam1 + p.fParam2; } );
auto f1 = [](auto p) { return (p.bParam ? p.dParam1 : p.c1.mVal) < p.mVal; };
auto f2 = [](auto p) { return ((p.dParam1 & p.dParam2) == 0) == p.bParam; };
auto f = val < 3 ? f1: f2;
DoWork(f);
}
in c++11 you need to change auto p to DoWorkParams p, but the auto feature of lambdas was one of the first c++14 features that compilers supported, so it probably works.
If multiple different functions share parameters, you can use inheritance.
struct DoWorkBaseParams {
uint32_t dParam1;
uint32_t dParam2;
bool bParam;
float fParam1;
float fParam2;
};
struct DoWorkParams1:DoWorkBaseParams {
MyClass& c1;
MyClass2& c2;
};
struct DoWorkParams2:DoWorkBaseParams {
MyClass& c1;
MyClass3& c3;
};
etc

passed parameters to boost odeint in C++

This answer is helpful, but I would like to know how to pass multiple parameters of different types to the ODE model, perhaps in a struct. For my immediate use case, I need to be able to pass one std::array<double, 6>, two std::vector<std::vector<double>> and two two double scalars for a total of four parameters to be passed. In the linked example, as well as in harmonic_oscillator.cpp, there is only a single double passed parameter. Thanks.
Here's an example of the struct I would need passed to the ODE force model and used within the rate equations.
struct T
{
std::array<double, 6> IC;
double S;
double M;
std::vector<std::vector<double>> C;
std::vector<std::vector<double>> WT;
};
I believe I've come up with a struct solution that works, but am not sure if it has any variable/memory scope no-no's. Here's an example:
#include <vector>
#include <boost/numeric/odeint.hpp>
// define structure
struct T
{
std::array<double, 6> IC;
double S;
};
// force model
class harm_osc
{
struct T T1;
public:
harm_osc(struct T G) : T1(G) {}
void operator() ( const std::vector< double > &x , std::vector< double > &dxdt , const double /* t */ )
{
dxdt[0] = x[1];
dxdt[1] = -x[0] - T1.IC[0]*x[1] + T1.S;
}
};
// print integrated state solution
void write_solution( const std::vector< double > &x , const double t )
{
printf("%-6.2f %-6.2f %-6.2f\n", t, x[0], x[1]);
}
// problem setup
int main()
{
std::vector< double > x(2);
x[0] = 1.0;
x[1] = 0.0;
struct T T2;
T2.IC = {0.15, 0.15, 0.15, 0.15, 0.15, 0.15};
T2.S = 0.0;
harm_osc ho(T2);
boost::numeric::odeint::integrate(ho, x, 0.0, 10.0, 0.1, write_solution);
}

GSL: Solving ODEs with time-dependent coefficients

I have an ODE of type:
x'(t) = a(t)x+g(t)
Which I am trying to solve. The only GSL ODE example isn't very helpful because the only coefficient (\mu) is not time dependent.
This question has been answered on the GSL mailing list however the answer is very unclear - g(t) is ignored and it has not been explained how to incorporate a(t) into func ( should it be passed in *params?).
Is there any example I can see where such an ODE is solved using GSL?
UPDATE: As has been pointed out below, this has been answered on the GSL mailing list. Here is a full example program of how this is done:
#include <stdio.h>
#include <math.h>
#include "gsl/gsl_errno.h"
#include "gsl/gsl_matrix.h"
#include "gsl/gsl_odeiv2.h"
int func(double t, const double y[], double f[], void *params) {
f[0] = -t* y[0];
return GSL_SUCCESS;
}
int jac(double t, const double y[], double *dfdy, double dfdt[], void
*params) {
gsl_matrix_view dfdy_mat = gsl_matrix_view_array(dfdy, 1, 1);
gsl_matrix * m = &dfdy_mat.matrix;
gsl_matrix_set(m, 0, 0, -t);
dfdt[0] = -1;
return GSL_SUCCESS;
}
int main(void) {
double mu = 0;
gsl_odeiv2_system sys = { func, jac, 1, &mu };
gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new(&sys,
gsl_odeiv2_step_rk1imp, 1e-7, 1e-7, 0.0);
int i;
double t = 0.0, t1 = 2.0;
const double x0 = 1.0;
double y[1] = {x0};
const int N = 100;
printf("time\t \tapprox solution \t exact solution\n");
for (i = 0; i <= N; i++) {
double ti = i * (t1 / N);
int status = gsl_odeiv2_driver_apply(d, &t, ti, y);
if (status != GSL_SUCCESS) {
printf("error, return value=%d\n", status);
break;
}
printf("%.5e\t%.5e\t\t%.5e\n", t, y[0], x0*exp(-0.5*t*t));
}
gsl_odeiv2_driver_free(d);
printf("\n...and done!\n");
return 0;
}
If you are not restricted to the GSL and/or C you can use http://odeint.com - a modern C++ library for ODEs. Odeint is part of boost, so it might be already installed on your system or can easily be installed be most of the package managers for Linux distributions.
You can simply define your coefficients and the ODE and use for example the RK4 method:
double coef_a( double t ) { /* return a(t) */ };
double coef_g( double t ) { /* return b(t) */ };
typedef std::array< double , 1 > state_type;
double ode( state_type const &x , state_type &dxdt , double )
{
dxdt[0] = coef_a( t ) * x[0] + coef_g( t );
}
state_type x;
double t_state , t_end , dt;
// initialize x
integrate_const( runge_kutta< state_type >() , ode , x , t_start , dt , t_end );