Re: [eigen] about .lazy()

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


2009/8/14 Gael Guennebaud <gael.guennebaud@xxxxxxxxx>:
> know this is not a very nice situation, and my suggestion to solve
> this mess is to remove the .lazy() function. Here are some arguments
> against ".lazy()":
>
> a - it is generic concept, but it only makes sense for product expressions

Mostly, indeed. Initially we didn't know to which expressions it would
apply. Indeed it turns out that it's almost only product expressions.
There are exceptions too: at least the Random expression (more
generally any non-repeatable nullaryExpr, but afaik it's the only one
so far).

>
> b - it is quite difficult to fully understand, and so it's difficult
> to use it well

Agree.

>
> c - it covers two different features at once:
>
>  c1 - it means that the result does not alias with the operands of
> the product, but for that purpose it makes more sense to control that
> via a special operator=, like res.noalias() = ...
>
>  c2 - it also means that the product should not be evaluated
> immediately, but evaluated as a standard expression. However, in
> practice it is (almost) never a good idea to do so, and when it is not
> the case the speed difference is negligible.

I don't really understand the difference between c1 and c2, indeed
lazy() used to do 2 things, remove EvalBeforeAssigning and
EvalBeforeNesting flags, i guess that's what you meant. Anyway it
doesn't matter.

> So to summary, I'd be in favor in removing .lazy(), replace the
> EvalBeforeAssignBit flag by a MightAliasBit flag, and add a no-alias
> mechanism on the result side.

OK so a.noalias() = xpr would be the way to obtain what you called the
"optimal" solution, right?

I agree with this change: indeed, if we agree that lazy() only removed
evalbeforeassigning, then indeed it's best placed in front of the = ,
so noalias() makes perfect sense.

Here's one further remark. In many cases, the creation of the
temporary was decided by the cost analysis (ei_nested<...>) and
therefore couldn't be prevented by lazy(). Just mentioning one more
reason why lazy() was at most a hint.

However there's one (small) aspect of your changes about which I don't
agree (at the moment): it's the renaming of EvalBeforeAssigningBit to
MayAliasBit. The old name described exactly what it does while the new
name seems imprecise to me. Indeed there are a lot of expressions that
"may alias" but still don't have the MayAliasBit. For example the
Transpose expression. And even Block if you take blocks on both sides
of an assignment (think row(i) = col(j)). So actually, a lot of
expressions "may alias", so the name MayAliasBit isn't what we mean.
Also in this documentation:

 /** \ingroup flags
   *
-  * means the expression should be evaluated before any assignement */
-const unsigned int EvalBeforeAssigningBit = 0x4;
+  * Means the expression cannot be evaluated safely if the result alias one
+  * of the operands of the expression. Therefore it should be evaluated
+  * before any assignement. */
+const unsigned int MayAliasBit = 0x4;

According to this doc, the Transpose expression should have the
MayAliasBit! (Which i'm not advocating! Just explaining why i think
this part of the changes is wrong).

> Finally, there is also the question whether operator+= and -= should
> be "no-alias" by default ? This because I think that in 99% of the
> case, when you write:
>
> m += <product>
>
> it's very unlikely that m is one of the operand of the product. The
> drawback is that might be confusing for the user, (because operator=
> and operator+= would behave differently wrt aliasing).

Yes, i'm afraid of this drawback. I'd rather not make += noalias by
default since = isn't.

But I have a question. since a+=b expands to a=a+b, as soon as b has
the EvalBeforeNestingBit, there can be no aliasing problem. b will
just be evaluated into a temporary c which won't have any
EvalBefore... bit, and from there one we have a=a+c which will be
lazy. On the other hand, noalias() allows to ignore
EvalBeforeAssigning on the sum expression. So basically the only case
where noalias() might be useful in a.noalias()+=b, is a case where b
has EvalBeforeAssigning and NOT EvalBeforeNesting. I don't think
there's any example of that??? So basically i'm saying that I don't
see any use case for a.noalias()+=b. Do you see any?

Benoit



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/