[lambda] make lambda play well with std::complex, imag, real, abs, etc.

Hi, I need some complex arithmetic in lambda expressions, for that I implemented this to make some std::complex functions work with Boost.Lambda. namespace boost{ namespace lambda{ #define BOOST_LAMBDA_COMPLEX_IMPL(function_name) \ template<typename Arg> \ lambda_functor<lambda_functor_base< \ action<2, function_action<2> >, \ boost::tuples::tuple< \ const double& (* const)(const std::complex<double>&), \ const lambda_functor<Arg> \ > \
function_name(const lambda_functor<Arg>& f){ \ return boost::lambda::bind(static_cast<double const&(*) (std::complex<double> const&)>(&std::function_name<double>), f); \ } BOOST_LAMBDA_COMPLEX_IMPL(real) BOOST_LAMBDA_COMPLEX_IMPL(imag) BOOST_LAMBDA_COMPLEX_IMPL(abs) BOOST_LAMBDA_COMPLEX_IMPL(norm) } }
use as boost::function<double(complex)> f = imag(_1) + real(_1) + abs(_1+2.); I have two questions about it: 1) Is this something that is implemented in some other way already? 2) it seem imposible to generalized to other template overloads of imag<T>, real<T> (i.e. something that can be used for std::complex<T>) because the template parameter Arg doesn't have information about the actual type. is it so? (comments on the code and alternatives also accepted) Thank you, Alfredo

On Jun 2, 2:01 pm, alfC <alfredo.cor...@gmail.com> wrote:
Hi, I need some complex arithmetic in lambda expressions, for that I implemented this to make some std::complex functions work with Boost.Lambda. ... 2) it seem imposible to generalized to other template overloads of imag<T>, real<T> (i.e. something that can be used for std::complex<T>) because the template parameter Arg doesn't have information about the actual type. is it so?
I think I now appreciate what Joel DG. refers to when he says that bind functions are monomorphic, and why they cannot do what I pointed in 2). The following is the Phoenix equivalent, i.e. the code that makes std::complex play well with Phoenix, moreover it is truly polymorphic, they work for all std::complex<T> types, (in fact it should work for any type that has the nested type ::value_type) #ifndef BOOST_PHOENIX_COMPLEX_HPP #define BOOST_PHOENIX_COMPLEX_HPP #include<boost/spirit/home/phoenix.hpp> #include<complex> namespace boost{ namespace phoenix{ #define BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( FunctionnamE ) \ struct FunctionnamE##_eval{ \ template <typename Env, typename Arg_> struct result{typedef typename boost::mpl::at_c<typename Env::args_type, 0>::type::value_type type;}; \ template <typename RT, typename Env, typename Arg_> static RT eval(Env const& env, Arg_ const& arg_){ \ return FunctionnamE(arg_.eval(env)); \ } \ }; \ template <typename Arg_> actor<typename as_composite<FunctionnamE##_eval, Arg_>::type> \ FunctionnamE(Arg_ const& arg_){ \ return compose<FunctionnamE##_eval>(arg_); \ } //as listed in http://www.cplusplus.com/reference/std/complex/ BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( real ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( imag ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( abs ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( norm ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( arg ) //argument complex function, do not confuse with arg_ #undef BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL #define BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( FunctionnamE ) \ struct FunctionnamE##_eval{ \ template <typename Env, typename Arg_> struct result{typedef typename boost::mpl::at_c<typename Env::args_type, 0>::type type;}; \ template <typename RT, typename Env, typename Arg_> static RT eval(Env const& env, Arg_ const& arg_){ \ return FunctionnamE(arg_.eval(env)); \ } \ }; \ template <typename Arg_> actor<typename as_composite<FunctionnamE##_eval, Arg_>::type> \ FunctionnamE(Arg_ const& arg_){ \ return compose<FunctionnamE##_eval>(arg_); \ } BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( conj ) //todo: polar BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( cos ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( cosh ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( exp ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( log ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( log10 ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( pow ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( sin ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( sinh ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( sqrt ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( tan ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( tanh ) #undef BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX }} #endif

On 6/6/10 10:10 AM, alfC wrote:
On Jun 2, 2:01 pm, alfC<alfredo.cor...@gmail.com> wrote:
Hi, I need some complex arithmetic in lambda expressions, for that I implemented this to make some std::complex functions work with Boost.Lambda. ... 2) it seem imposible to generalized to other template overloads of imag<T>, real<T> (i.e. something that can be used for std::complex<T>) because the template parameter Arg doesn't have information about the actual type. is it so?
I think I now appreciate what Joel DG. refers to when he says that bind functions are monomorphic, and why they cannot do what I pointed in 2). The following is the Phoenix equivalent, i.e. the code that makes std::complex play well with Phoenix, moreover it is truly polymorphic, they work for all std::complex<T> types, (in fact it should work for any type that has the nested type ::value_type)
#ifndef BOOST_PHOENIX_COMPLEX_HPP #define BOOST_PHOENIX_COMPLEX_HPP #include<boost/spirit/home/phoenix.hpp> #include<complex> namespace boost{ namespace phoenix{ #define BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( FunctionnamE ) \ struct FunctionnamE##_eval{ \ template<typename Env, typename Arg_> struct result{typedef typename boost::mpl::at_c<typename Env::args_type, 0>::type::value_type type;}; \ template<typename RT, typename Env, typename Arg_> static RT eval(Env const& env, Arg_ const& arg_){ \ return FunctionnamE(arg_.eval(env)); \ } \ }; \ template<typename Arg_> actor<typename as_composite<FunctionnamE##_eval, Arg_>::type> \ FunctionnamE(Arg_ const& arg_){ \ return compose<FunctionnamE##_eval>(arg_); \ } //as listed in http://www.cplusplus.com/reference/std/complex/ BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( real ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( imag ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( abs ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( norm ) BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL( arg ) //argument complex function, do not confuse with arg_ #undef BOOST_PHOENIX_UNARY_COMPLEX_TO_REAL
#define BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( FunctionnamE ) \ struct FunctionnamE##_eval{ \ template<typename Env, typename Arg_> struct result{typedef typename boost::mpl::at_c<typename Env::args_type, 0>::type type;}; \ template<typename RT, typename Env, typename Arg_> static RT eval(Env const& env, Arg_ const& arg_){ \ return FunctionnamE(arg_.eval(env)); \ } \ }; \ template<typename Arg_> actor<typename as_composite<FunctionnamE##_eval, Arg_>::type> \ FunctionnamE(Arg_ const& arg_){ \ return compose<FunctionnamE##_eval>(arg_); \ } BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( conj ) //todo: polar
BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( cos ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( cosh ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( exp ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( log ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( log10 ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( pow ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( sin ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( sinh ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( sqrt ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( tan ) BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX( tanh ) #undef BOOST_PHOENIX_UNARY_COMPLEX_TO_COMPLEX }} #endif
Is there a reason why you are not using plain phoenix::function(s) for this? Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Sun, Jun 6, 2010 at 4:41 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Is there a reason why you are not using plain phoenix::function(s) for this?
good point, I am still phoenix-challenged I guess. I got driven by the "Composite" example in the manual. This is the alternative implementation using phoenix::function: namespace boost{namespace phoenix{ struct real_impl{ template <typename Arg> struct result{ typedef double type; //can be generalized }; template <typename Arg> typename result<Arg>::type operator()(Arg z) const{ return real(z); } }; function<real_impl> real_; // "real" as name doesn't work }} int main(){ std::complex<double> z(1.,2.); cout << real_(arg1)(z) <<endl; return 0; } which works. ...But there is a problem it seem that I can not call "real_" as "real", so the resulting syntax is degraded. (Either I have to call the phoenix::function real_ or put std::real in the operator()) It seems that the overload get confused. Is there a way to go around this? (my poorly written first version --with no phoenix::function-- at least didn't have this limitation) Thank you, Alfredo

On 6/7/10 3:42 PM, Alfredo Correa wrote:
On Sun, Jun 6, 2010 at 4:41 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Is there a reason why you are not using plain phoenix::function(s) for this?
good point, I am still phoenix-challenged I guess. I got driven by the "Composite" example in the manual. This is the alternative implementation using phoenix::function:
namespace boost{namespace phoenix{ struct real_impl{ template<typename Arg> struct result{ typedef double type; //can be generalized }; template<typename Arg> typename result<Arg>::type operator()(Arg z) const{ return real(z); } }; function<real_impl> real_; // "real" as name doesn't work }} int main(){ std::complex<double> z(1.,2.); cout<< real_(arg1)(z)<<endl; return 0; }
which works. ...But there is a problem it seem that I can not call "real_" as "real", so the resulting syntax is degraded. (Either I have to call the phoenix::function real_ or put std::real in the operator()) It seems that the overload get confused. Is there a way to go around this? (my poorly written first version --with no phoenix::function-- at least didn't have this limitation)
Good point. Well, you can make real_ and friends use the extension mechanism as before, then use functions for all else. Duly noted. In phoenix3, we'll have an easy way to have nullary functions which do not require (). Thanks for working on this! Very good timing! :-) Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net

On Jun 7, 12:52 am, Joel de Guzman <j...@boost-consulting.com> wrote:
On 6/7/10 3:42 PM, Alfredo Correa wrote:
On Sun, Jun 6, 2010 at 4:41 PM, Joel de Guzman <j...@boost-consulting.com> wrote:
Is there a reason why you are not using plain phoenix::function(s) for this?
good point, I am still phoenix-challenged I guess. I got driven by the "Composite" example in the manual. This is the alternative implementation using phoenix::function:
namespace boost{namespace phoenix{ struct real_impl{ template<typename Arg> struct result{ typedef double type; //can be generalized }; template<typename Arg> typename result<Arg>::type operator()(Arg z) const{ return real(z); } }; function<real_impl> real_; // "real" as name doesn't work }} int main(){ std::complex<double> z(1.,2.); cout<< real_(arg1)(z)<<endl; return 0; }
which works. ...But there is a problem it seem that I can not call "real_" as "real", so the resulting syntax is degraded. (Either I have to call the phoenix::function real_ or put std::real in the operator()) It seems that the overload get confused. Is there a way to go around this? (my poorly written first version --with no phoenix::function-- at least didn't have this limitation)
Good point. Well, you can make real_ and friends use the extension mechanism as before, then use functions for all else.
nice to see that I found the workaround before knowing about the limitation. Now, that seems also to be the case for all functions (for example in std::) for which we need a phoenix counterpart with the *same name* (with no underscore).
Duly noted. In phoenix3, we'll have an easy way to have nullary functions which do not require ().
interesting. but I don't see how this can be applied to these examples. Thanks, Alfredo

On Mon, Jun 7, 2010 at 12:52 AM, Joel de Guzman <joel@boost-consulting.com> wrote:
On 6/7/10 3:42 PM, Alfredo Correa wrote:
On Sun, Jun 6, 2010 at 4:41 PM, Joel de Guzman <joel@boost-consulting.com> wrote:
Is there a reason why you are not using plain phoenix::function(s) for this?
good point, I am still phoenix-challenged I guess. I got driven by the "Composite" example in the manual. This is the alternative implementation using phoenix::function:
namespace boost{namespace phoenix{ struct real_impl{ template<typename Arg> struct result{ typedef double type; //can be generalized }; template<typename Arg> typename result<Arg>::type operator()(Arg z) const{ return real(z); } }; function<real_impl> real_; // "real" as name doesn't work }} int main(){ std::complex<double> z(1.,2.); cout<< real_(arg1)(z)<<endl; return 0; }
which works. ...But there is a problem it seem that I can not call "real_" as "real", so the resulting syntax is degraded. (Either I have to call the phoenix::function real_ or put std::real in the operator()) It seems that the overload get confused. Is there a way to go around this? (my poorly written first version --with no phoenix::function-- at least didn't have this limitation)
Good point. Well, you can make real_ and friends use the extension mechanism as before, then use functions for all else.
I understand the underscore is necessary for reserved keywords, but using it for everything is a pity. So I stick with the solution that allows the same phoenix and (rest of) C++ the same name. In fact I realized that if I need any function (from example in std cmath) it is good to define the following macro to "register" existing functions, to be used in phoenix expressions. #include<boost/spirit/home/phoenix.hpp> #include <boost/utility/enable_if.hpp> /// Extends any endomorphic function as a phoenix function, endomorphic in the sense that the input and output are of the same type #define BOOST_PHOENIX_REGISTER_ENDOMORPHISM(FN) \ namespace boost{ \ namespace phoenix{ \ struct FN##_eval{ \ template <typename Env, typename Arg_> struct result{typedef typename boost::mpl::at_c<typename Env::args_type, 0>::type type;}; \ template <typename RT, typename Env, typename Arg_> static RT eval(Env const& env, Arg_ const& arg_){ \ return FN(arg_.eval(env)); \ } \ }; \ template <typename Arg_> \ typename boost::enable_if_c<is_actor<Arg_>::value, \ actor<typename as_composite<FN##_eval, Arg_>::type> \ >::type \ FN(Arg_ const& arg_){ \ return compose<FN##_eval>(arg_); \ } \ }} and then register any arbitrary function (this solution work if the input/output type are the same. maybe with upcoming decltype we can do better). BOOST_PHOENIX_REGISTER_ENDOMORPHISM(cos); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(cosh); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(exp); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(log); BOOST_PHOENIX_REGISTER_ENDOMORPHISM(log10); ... This could be useful to make phoenix support a large portion of STL (in this case cmath), I don't know if it is planned. Also there is no necessity of the underscore. Note two things: 1) I had to put an "enable_if_c" in order to avoid huge error messages when the function is not really defined outside Phoenix. When the function is not defined then the 'return FN(...)' line get confused with the phoenix function with the same name. 2) I have a confusion with the namespaces, the phoenix function (e.g. "cos") is in the namespace boost::phoenix which is good because the function is resolved correctly most of the time. but the real function (e.g. "std::cos") has no information about the namespace, which is good but I guess sometimes we need need to be specific of the namespace of the function we are trying to register. But adding the namespace will break the macro. One alternative is to add a second parameter to the macro so BOOST_PHOENIX_REGISTER_ENDOMORPHISM(std::cos, cos); //first the fully qualified name, second the boost::phoenix the other possibility is to try to define the phoenix function in the same namespace as the original function. The fact that a function with the same name can appear in different namespaces and the fact that there no concept of namespace in phoenix then it seems the last possibility is the only general one. Thanks, Alfredo
participants (4)
-
alfC
-
Alfredo Correa
-
Alfredo Correa
-
Joel de Guzman