[proto] learning proto slowly, a small (math)complex library

From a mathematical point of view the complex z is a complex number of course, and z/|z| (z/abs(z)) is not only also a complex number but also potentially a complex_unit_circle element with very spefic
Hi, I find proto pretty intriguing and I can see the power in it but I am still not able to create a context in which it can help in my design. I also find the Boost.Proto examples very confusing and not usually in the context I always imagine to use the library. There are several concepts that I don't yet fully understand like "context" and "grammars". Also besides the power I see in the library sometimes the resulting syntax in the examples is pretty disappointing, with all those "eval" functions. In general I can't see whether this is a result of limitations of the library or a tool to make the examples more pedagogical. If someone is kind enough to follow me and help me during this discovery of the library along these posts I will continue. The idea of this post is try to bring a simple example of boost at a context that I am able to understand. In order to be useful for many other people I will try to bring proto to a purely mathematical level. Suppose I want to build a new (kind of mathematical) library. Typically I would start defining a lots of arithmetical objects and members and friends operators, all of them eager (member)functions, lots of operators (many bugs also), also use boost.operators (to make less bugs) and then realise that the library has not any real deep mathematical structure on it, not to the compile-time/programmer level. Yes, the program will be able to do a lot of mathematics at runtime via numerical representations but there will be no insight from the point of view of the program code or the "type system". Let's start by an example, I define a complex type, after a lot of work I would have made the equivalent of std::complex<T>. Then the program replaces T by double and the program can (at runtime) do some "math". The problem is that I as a programmer can not do any math with that type. Let me give a concrete example, the complex_unit_circle is a set of complex numbers with modulus =1. One is tempted to implement complex_unit_circle in terms of the "complex type" or some parameterisation (angle). properties. For example the product of two elements of the unit circle can be interpreted as a unit circle element again. The only way to express this potentiality at compile time is by expression templates, i.e. in its most glorious state by Boost.Proto. z/abs(z) is really an expression that eventually can be used to construct either another complex number (as type) or a unit circle number (as type). But lets start slower than that, lets build an expression that can be used (potentially) to build a complex number instead. The concrete question of this post will be how to obtain the desired syntax by adding layers to the original posted code. This is what I have done so far: #include <boost/proto/core.hpp> namespace pretty{ namespace proto = boost::proto; struct i_tag{}; proto::terminal< i_tag >::type const i = {{}}; } int main(){ using namespace pretty; 4. + 5.*i; //this will be a complex number (in some sense) return 0; } of course this program does nothing, it is just to show that I can create a expression template with a symbol called "i", this symbol will have properties that will eventually make it equivalent to one of the roots of -1 (mathematically speaking) (but not yet). Note that I didn't define any so called "grammar" or "context" yet. Since the first concern is to be able to use the new code with old code at all intermediate steps in the development, duppose I want to use this kind of expression to construct (in the c++ sense) an existing type, namely std::complex<double>. i.e. I want to be able to write: std::complex<double> z = 4. + 5.*i; or std::complex<double> z(4. + 5.*i); (forget about alternative notations, like 5.*i + 4. or 4. + i*5) The only ways I see this is possible is by adding either a constructor to std::complex<double> or a cast operator of the "expression of type 4.+5.*i" to std::complex<double>. The question for this post, 1) is this true? 2) if yes, then that means that one of the 2 types (type complex or typeof(4.+5.*i) ), will have to be modified (or extendended) in other to accept this syntax. 3) if no , how can I allow this syntax? 4) if the std::complex type is not modifiable, what is the mechanism in proto to define a cast over a certain set of expressions, e.g. of the type of 4.+5.*i. 5) if not, is this syntax not possible at all? is it here where we need to introduce those "eval" functions such as std::complex<double> z = eval_as_complex(4. + 5.*i). The idea is that once I resolve this general questions about the library I will continue building up. (And excuse me for these naive questions along the way). (Note: I know that std::complex<double> had constructor std::complex<double>(4.,5.) and that should be the preferred use, but this post is all about "syntax" and how to use proto, these are just examples). Thank you, Alfredo

On 10/01/11 11:47, alfC wrote:
1) is this true? Yes
2) if yes, then that means that one of the 2 types (type complex or typeof(4.+5.*i) ), will have to be modified (or extendended) in other to accept this syntax. 3) if no , how can I allow this syntax?
See the boostcon slides of Eric last year. All you need is to give your complex expression an operator to cast itself to std::complex in which you evaluate the expression real and imag part and retrun the newly constructed std::complex out of it. Incidentally, i am using this very same example in a courses on DSEL design in C++ i am starting to write atm. So i can shed some light if you want.

See the boostcon slides of Eric last year. All you need is to give your complex expression an operator to cast itself to std::complex in which you evaluate the expression real and imag part and retrun the newly constructed std::complex out of it.
great, nice resource. I translated the map_list_of example into the complex example. There is still work to do, the code doesn't work yet. I guess I have to still tell proto that "complex_cartesian_expr" (didn't know what other name to put) is of type proto::plus< proto::terminal<double> , proto::multiplies<proto::terminal<double>, proto::terminal<i_tag> >
. I don't know how to do that. complete code at the end of the email.
Incidentally, i am using this very same example in a courses on DSEL design in C++ i am starting to write atm.
I knew it could be a natural example since most people know simple complex arithmetic and std::complex<double>.
So i can shed some light if you want.
That would be great. Any help is greatly appreciated and I promise my feedback. ---- #include <boost/proto/core.hpp> #include <complex> namespace pretty{ namespace proto = boost::proto; struct i_tag{}; proto::terminal< i_tag >::type const i = {{}}; template< typename Expr > struct complex_cartesian_expr; struct complex_cartesian_domain : proto::domain< proto::generator< complex_cartesian_expr > > {}; template<typename Expr> struct complex_cartesian_expr : proto::extends< Expr, complex_cartesian_expr< Expr >, complex_cartesian_domain >{ complex_cartesian_expr( Expr const & expr = Expr() ) : proto::extends< Expr, complex_cartesian_expr< Expr >, complex_cartesian_domain >( expr ){} template<class K, class V, class C, class A> operator std::complex<K>() const{ std::complex<K> m(proto::value( proto::child_c<1>(*this) ), proto::value( proto::child_c<1>(proto::child_c<2>(*this)) ) ); return m; } }; } int main(){ using namespace pretty; std::complex<double> z(4. + 5.*i); return 0; }

On 10/01/11 22:42, alfC wrote:
I translated the map_list_of example into the complex example. There is still work to do, the code doesn't work yet. I guess I have to still tell proto that "complex_cartesian_expr" (didn't know what other name to put) is of type proto::plus< proto::terminal<double> , proto::multiplies<proto::terminal<double>, proto::terminal<i_tag> > I don't know how to do that. complete code at the end of the email.
try std::complex<double> z = 4. + 5.i; Incidentally, you should have a real transform able to turn any complex_expression into a complex and not rely on a given fixed AST structure. What if i do z = i + i + 3 + 4*i ? You have to look up transform.

Oh and you make a small oversight : template<class K, class V, class C, class A> operator std::complex<K>() const{ std::complex<K> m(proto::value( proto::child_c<1>(*this) ), proto::value( proto::child_c<1>(proto::child_c<2>(*this)) ) ); return m; } should be template<class K> operator std::complex<K>() const{ std::complex<K> m(proto::value( proto::child_c<1>(*this) ), proto::value( proto::child_c<1>(proto::child_c<2>(*this)) ) ); return m; } you dont need the C,V,A parameters

try
std::complex<double> z = 4. + 5.i;
ok, I put that but still doesn't work.
Incidentally, you should have a real transform able to turn any complex_expression into a complex and not rely on a given fixed AST structure.
What if i do z = i + i + 3 + 4*i ?
I know, but I want to keep it simple, std::complex<double> z = 4. + 5.*i; will be just a glorified constructor.

On 11/01/11 08:01, alfC wrote:
try
std::complex<double> z = 4. + 5.i;
ok, I put that but still doesn't work.
See my other mail, your operator complex<T> has too many useless template parameter.
I know, but I want to keep it simple, std::complex<double> z = 4. + 5.*i; will be just a glorified constructor.
Sure, but the actual tranform is not harder

alfC wrote:
Hi,
<snip>
This is what I have done so far:
#include <boost/proto/core.hpp> namespace pretty{ namespace proto = boost::proto; struct i_tag{}; proto::terminal< i_tag >::type const i = {{}}; }
int main(){ using namespace pretty; 4. + 5.*i; //this will be a complex number (in some sense) return 0; }
<snip>
Since the first concern is to be able to use the new code with old code at all intermediate steps in the development, duppose I want to use this kind of expression to construct (in the c++ sense) an existing type, namely std::complex<double>. i.e. I want to be able to write:
std::complex<double> z = 4. + 5.*i; or std::complex<double> z(4. + 5.*i); (forget about alternative notations, like 5.*i + 4. or 4. + i*5)
The only ways I see this is possible is by adding either a constructor to std::complex<double> or a cast operator of the "expression of type 4.+5.*i" to std::complex<double>. The question for this post,
1) is this true? 2) if yes, then that means that one of the 2 types (type complex or typeof(4.+5.*i) ), will have to be modified (or extendended) in other to accept this syntax. 3) if no , how can I allow this syntax? 4) if the std::complex type is not modifiable, what is the mechanism in proto to define a cast over a certain set of expressions, e.g. of the type of 4.+5.*i. 5) if not, is this syntax not possible at all? is it here where we need to introduce those "eval" functions such as std::complex<double> z = eval_as_complex(4. + 5.*i).
The idea is that once I resolve this general questions about the library I will continue building up. (And excuse me for these naive questions along the way).
(Note: I know that std::complex<double> had constructor std::complex<double>(4.,5.) and that should be the preferred use, but this post is all about "syntax" and how to use proto, these are just examples).
As Joel pointed out already, you need to wrap your expression templates to give them their domain specific meaning. In your case, the cast operator. This cast operator would need to have a context, or preferably a transform (a transform is a grammar is a transform) to evaluate your expression to std::complex<double>. See: http://www.boost.org/doc/libs/1_45_0/doc/html/proto/users_guide.html#boost_p... for an example with contexts. The steps to define a grammar that does the transformation are the following: 1) define a grammar that matches your expression (proto::matches, proto::display_expr are a great help here, i also use std::cout << typeid(Expr).name() << "\n"; quite often). 2) attach semantic actions, step by step to your grammar rules That's it :) HTH, Thomas
Thank you, Alfredo

As Joel pointed out already, you need to wrap your expression templates to give them their domain specific meaning. In your case, the cast operator. This cast operator would need to have a context, or preferably a transform (a transform is a grammar is a transform) to evaluate your expression to std::complex<double>. See:http://www.boost.org/doc/libs/1_45_0/doc/html/proto/users_guide.html#... for an example with contexts.
The steps to define a grammar that does the transformation are the following: 1) define a grammar that matches your expression
ok, at the level I am working it seem that the following grammar is what I need. note that it is not recursive and it is a completely rigid structure. struct complex_cartesian_grammar : proto::plus< proto::terminal<double>, proto::multiplies< proto::terminal<double>, proto::terminal<i_tag> > >{}; (complete code at the end)
2) attach semantic actions, step by step to your grammar rules
not so fast, how do I do that? I also defined the "domain" struct complex_cartesian_domain : proto::domain< proto::generator< complex_cartesian_expr >, complex_cartesian_grammar >{}; I still have to somehow connect the define grammar with the expression itself. how? I also understand that the expression convertible to std::complex<double> must match double + double*i (the simple grammar) but again I don't understand how to do it. What follows is the complete code I have far. -- Thank you | Alfredo #include <boost/proto/core.hpp> #include <complex> namespace pretty{ namespace proto = boost::proto; struct i_tag{}; proto::terminal< i_tag >::type const i = {{}}; template< typename Expr > struct complex_cartesian_expr; struct complex_cartesian_grammar : proto::plus< proto::terminal<double>, proto::multiplies< proto::terminal<double>, proto::terminal<i_tag> > >{}; struct complex_cartesian_domain : proto::domain< proto::generator< complex_cartesian_expr >, complex_cartesian_grammar >{}; template<typename Expr> struct complex_cartesian_expr : proto::extends< Expr, complex_cartesian_expr< Expr >, complex_cartesian_domain >{ complex_cartesian_expr( Expr const & expr = Expr() ) : proto::extends< Expr, complex_cartesian_expr< Expr >, complex_cartesian_domain >( expr ){} template<typename T> operator std::complex<T>() const{ return std::complex<T>( proto::value( proto::child_c<1>(*this) ), proto::value( proto::child_c<1>(proto::child_c<2>(*this)) ) ) ; } }; } int main(){ using namespace pretty; std::complex<double> z = 4. + 5.*i; return 0; }

On 1/11/2011 2:58 AM, alfC wrote:
As Joel pointed out already, you need to wrap your expression templates to give them their domain specific meaning. In your case, the cast operator. This cast operator would need to have a context, or preferably a transform (a transform is a grammar is a transform) to evaluate your expression to std::complex<double>. See:http://www.boost.org/doc/libs/1_45_0/doc/html/proto/users_guide.html#... for an example with contexts.
The steps to define a grammar that does the transformation are the following: 1) define a grammar that matches your expression
ok, at the level I am working it seem that the following grammar is what I need. note that it is not recursive and it is a completely rigid structure.
struct complex_cartesian_grammar : proto::plus< proto::terminal<double>, proto::multiplies< proto::terminal<double>, proto::terminal<i_tag> >
{}; (complete code at the end)
Like Joel says, it's just as simple to make this correct and general. This is artifically constrained.
2) attach semantic actions, step by step to your grammar rules
not so fast, how do I do that?
Read about transforms: http://www.boost.org/doc/libs/1_45_0/doc/html/proto/users_guide.html#boost_p...
I also defined the "domain" struct complex_cartesian_domain : proto::domain< proto::generator< complex_cartesian_expr >, complex_cartesian_grammar
{};
I still have to somehow connect the define grammar with the expression itself. how?
Read about expression extension: http://www.boost.org/doc/libs/1_45_0/doc/html/proto/users_guide.html#boost_p...
I also understand that the expression convertible to std::complex<double> must match double + double*i (the simple grammar) but again I don't understand how to do it.
See attached. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Hi Eric, On Jan 11, 9:33 pm, Eric Niebler <e...@boostpro.com> wrote:
See attached.
Thank you very much for the example, it definitely works and does even more that I was expecting to achieve in this example. However, just in order to make it more understandable (to me) at the beginning I want to go even simpler that what you did. I understand that proto is ideal for recursive expression (grammars?) but I just want to define a fixed/rigid grammar that only accepts a rigid expression of the type of 4. + 5.*i. Besides that I don't want proto to evaluate things for me, I want to be able to "see" the expression structure and contained values from a single place. In other words I want a glorified (simulated) constructor. std::complex<double> z = 5. + 6.*i; I guess the "grammar" is simply (correct me if I am wrong): struct i_tag{}; struct complex_cartesian_grammar : proto::plus< proto::terminal<double>, proto::multiplies<proto::terminal<double>, proto::terminal<i_tag> > > {}; yes, it is a very stupid rigid expression. (It just should accept a certain expression.). For this, I striped down your version, to the point it didn't compile but I think the intention of the code is there. The complete code is attached below. In my opinion... what it has: 1) defines abstract symbol "i" 2) defines the only allowed expression in the syntax. 3) defines the domain (I don't know what this does) what it lacks: 4) be able to compile 5) proper conversion of the expression tree to extract the relevant data. 6) expression matches verification?? for the future: 7) allow a few more allowable expressions compatible with the constructor of std::complex<double>, just of the types 4.+5.*i, 4., 5.*i and that's it. Sorry to using your powerful library for such an unpowerful application, I am just trying to learn. The current code gives naturally this error: error: conversion from ‘const boost::proto::exprns_::expr<boost::proto::tag::plus, ... >’ to non- scalar type ‘std::complex<double>’ requested The code follows // Thank you // Alfredo #include <complex> #include <boost/proto/proto.hpp> namespace proto=boost::proto; namespace pretty{ struct i_tag{}; struct complex_cartesian_grammar : proto::plus< proto::terminal<double>, proto::multiplies<proto::terminal<double>, proto::terminal<i_tag> > > {}; template< typename Expr > struct complex_cartesian_expr; struct complex_cartesian_domain : proto::domain< proto::pod_generator< complex_cartesian_expr >, complex_cartesian_grammar > {}; template<typename Expr> struct complex_cartesian_expr { BOOST_PROTO_EXTENDS( Expr, complex_cartesian_expr, complex_cartesian_domain ) template<typename T> operator std::complex<T>() const{ return std::complex<double>(proto::child_c<0>(*this), proto::child_c<0>(*this)); } }; proto::terminal<i_tag>::type const i = {{}}; } int main(){ using namespace pretty; std::complex<double> z = 5. + 6.*i; std::cout << z << std::endl; return 0; }

On 1/12/2011 3:58 AM, alfC wrote:
Hi Eric,
On Jan 11, 9:33 pm, Eric Niebler <e...@boostpro.com> wrote:
See attached.
<snip>
3) defines the domain (I don't know what this does) what it lacks:
<snip>
proto::terminal<i_tag>::type const i = {{}};
If you don't know what the domain is for, and you aren't wrapping i in your expression adaptor, I have to wonder if you actually read the links I sent you. Your "simpler" example is actually a little trickier because the simple expression "i" is not valid according to your desired grammar. So grammar checking cannot be done early but must be delayed until the full expression is known. I'm running out the door right now and can't say more, but I encourage you to re-read the links I sent in my last email and take another shot at solving this. -- Eric Niebler BoostPro Computing http://www.boostpro.com
participants (4)
-
alfC
-
Eric Niebler
-
Joel Falcou
-
Thomas Heller