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

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

On 10/01/11 11:47, alfC wrote:
1) is this true? Yes
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.

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
. 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

On 10/01/11 22:42, alfC wrote:
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

On 11/01/11 08:01, alfC wrote:
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>
<snip>
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

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
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

On 1/11/2011 2:58 AM, alfC wrote:
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...
Read about expression extension: http://www.boost.org/doc/libs/1_45_0/doc/html/proto/users_guide.html#boost_p...
See attached. -- Eric Niebler BoostPro Computing http://www.boostpro.com

Hi Eric,
On Jan 11, 9:33 pm, Eric Niebler
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

On 1/12/2011 3:58 AM, alfC wrote:
<snip>
3) defines the domain (I don't know what this does) what it lacks:
<snip>
proto::terminal
::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