Reputation: 21
I am trying to build some nested functions like so (reduced example):
// the actual functions come from particle physics and are extremely ugly
double f(double x){
return 2*x+1;
}
//in reality a numerical derivative term
double F(const std::function<double(double)>& f, double x){
return f(x) - f(x+1);
}
// in reality another higher order numerical derivative
double G(const std::function<double(double)>& f, double x){
return f(x) + f(x+1);
}
// in reality a function where the index is supposed to control the degree of derivatives of the function
double H(const std::function<double(double)>& f, double x, int switch){
if(0 == switch){
return G(f(x));
} else {
return F(f(x));
}
}
this is the goal (2d for demonstration):
double sum=0;
for(int i=0; i<1;++i){
for(int j=0; j<1;++j){
sum += H(H(f,i),j);
}
}
So two things:
H
to switch between F
and G
(my actual problem has 3 cases).H(H(...)...)
the problem with that is the type of the function f
which is the first argument of H
, when I pass it a second time the type is no longer double(double)
but double(std::function<double(double)>,double(double),double)
or so...Or in other terms: https://i.sstatic.net/XkbmJ.gif (cannot post images, not enough rep)
Upvotes: 2
Views: 132
Reputation: 15587
Firstly, don't explicitly use std::function
, but make your function argument templated instead, like
template <typename Arg>
double F(Arg const & f, double x){
return f(x) - f(x+1);
}
This enables a lot more room to both optimization and genericity.
Secondly, turn all your functions into returning a lambda:
template <typename Arg>
auto F(Arg const & f){
return [f](double x){ return f(x) - f(x+1); };
}
template <typename Arg>
auto G(Arg const & f){
return [f](double x){ return f(x) + f(x+1); };
}
template <typename Arg>
std::function<double(double)> H(Arg const & f, int which){
if(0 == which){
return F(f);
} else {
return G(f);
}
}
Note the auto
return type: this is needed for returning lambdas to work.
Now you don't call F(f,x)
, but rather F
transforms f
into it's derivative (or something else), which can be now applied to an x
. These can now be used like
F(f)(0.1); // apply F(f) to x=0.1
F(F(G(f)))(0.5); // apply F(F(G(f))) to x=0.5
H(H(f,0),1)(4.2); // apply H(H(f,0),1) to x=4.2
Upvotes: 2
Reputation: 63162
If you have a value for the inner f
and switch
(N.B. change that name, switch
is a flow control construct), then you can partially apply H
and then pass that to H
std::function<double(double)> partial_H(std::function<double(double)> f, int choice)
{
return [f, choice](double x) { return H(f, x, choice); };
}
Upvotes: 1