Boost logo

Ublas :

Subject: Re: [ublas] Questions on the internal design of Boost.uBLAS
From: Nasos Iliopoulos (nasos_i_at_[hidden])
Date: 2010-10-29 09:25:46


Sebastian,
I think that many of your questions cannot be answered, as the ppl that started uBlas are not around the list anymore, but I can share my understanding just in case it helps you. My discussion contains only items I have inferred and I can't talk with certainty.

> After checking the Boost.uBLAS code I noticed that every vector or
> matrix expression offers two additional typedefs: closure_type and
> const_closure_type. .......

Closure type is the type the expression is supposed to return when evaluated. For unary Blas operations this is usually the same as the self_type, but for binary this may differ depending on the two expressions closure types and the operation. For example, there is the need to define the return type of an binary expression involving a scalar and a vector because uBlas meta-mechanism have no way of knowing what it should be. Maybe this can change in the future by the use of the new "auto" keyword.

> the expression object will contain a dangling reference because the
> closure_type of ublas::vector<..> is a vector_reference and the
> returned object will be destroyed after the full expression has been
> evaluated. So, this closure_type approach doesn't really solve the
> problem, it only minimizes the occurence of dangling
> pointers/references. Is that what the authors intended or does it
> serve another purpose as well?

Hmm... At first this seems like a nice catch. Have you tried to run some code to evaluate it? Anyway when uBlas was developed, auto functionality was not even a thought . The new standard brings nice new things and great potential for big revamps in uBlas.

> I suppose that in C++0x we could use rvalue references to detect the
> value category of an expression object. If the expression object is an
> lvalue vector container, we could store a pointer and in the other
> cases move the expression object into a new expression object. That
> should get rid of the danling reference problem in the second example.

I second that. There was some discussion in the past in the list: look for move semantics in older posts.

> I suppose that in C++0x we could use rvalue references to detect the
> value category of an expression object. If the expression object is an
> lvalue vector container, we could store a pointer and in the other
> cases move the expression object into a new expression object. That
> should get rid of the danling reference problem in the second example.

I think this is an implementation detail that helps the various types to store temporaries when things are evaluated. I think if the bounded types where not there, a separate typedef for temporaries would not be necessary (don't take my word for the latter).

> It
> seems all the expression types expose a constant expression named
> "complexity".
I think this is the computational complexity of the expressions, that looks never got attention and most expressions don't really refine this concept.

Hope those help,

Best,
Nasos

On Oct 29, 2010, at 7:00 AM, Sebastian Gesemann wrote:

> Hello!
>
> I'm currently in the process of building a library on top of uBLAS. I
> also started using expression templates for special vector expressions
> that carry additional information ("vectorad expression", ad =
> automatic differentiation, stores partial derivatives). The code works
> so far. But I just noticed that I did do something differently
> compared to how expression templates are handled in uBLAS -- hence
> this question.
>
> My operator+ which takes two "vectorad expressions" returns an
> expression object that stores two pointers to the argument expression
> objects. Storing pointers is desirable in case the argument was an
> lvalue "vectorad container". This is how expensive copies/temporaries
> are avoided after all. But I also store pointers in other cases which
> might be a dangerous thing to do (possible life-time issues, dangling
> pointers).
>
> After checking the Boost.uBLAS code I noticed that every vector or
> matrix expression offers two additional typedefs: closure_type and
> const_closure_type. These don't seem to be mentioned anywhere in the
> documentation but it seems that they are required. Instead of storing
> pointers or references to other expression objects, their respective
> closure_type objects are stored. In case of vector containers this
> will be a vector_reference. But if the expression object is NOT a
> vector container, its closure_type is its self_type. I wonder why this
> is. What was the motivation to do that? Was it to minimize dangling
> pointers/references? In the light of C++0x people might be tempted to
> use auto like this:
>
> auto sum = 3*vector1 + 4*vector2;
>
> where sum will be a vector expression (but not a container) which
> indirectly refers to vector1 and vector2 but nothing else. It contains
> all non-container expressions. So that's a good thing. No danling
> pointers here. But if we use a function that returns a vector
> container by value
>
> ublas::vector<double> source();
> ...
> auto sum = 3*source() + 4*vector2;
>
> the expression object will contain a dangling reference because the
> closure_type of ublas::vector<..> is a vector_reference and the
> returned object will be destroyed after the full expression has been
> evaluated. So, this closure_type approach doesn't really solve the
> problem, it only minimizes the occurence of dangling
> pointers/references. Is that what the authors intended or does it
> serve another purpose as well?
>
> I suppose that in C++0x we could use rvalue references to detect the
> value category of an expression object. If the expression object is an
> lvalue vector container, we could store a pointer and in the other
> cases move the expression object into a new expression object. That
> should get rid of the danling reference problem in the second example.
>
> Another question is regarding "temporary_type" we can find as nested
> typedefs in expression classes. I also don't find anything about this
> in the documentation. Is this considered an implementation detail or
> part of the vector expression concept? I'm asking because I could use
> such a type information to turn an expression object into a container
> so that the expression is not evaluated many times. But I would also
> like to avoid this in case evaluating the expression is cheap. It
> seems all the expression types expose a constant expression named
> "complexity". Can somebody explain what this is about? Even if it's an
> implementation detail, there might be something to learn about for my
> own expression templates.
>
> Thanks in advance!
> Sebastian
> _______________________________________________
> ublas mailing list
> ublas_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/ublas
> Sent to: athanasios.iliopoulos.ctr.gr_at_[hidden]