Re: [eigen] about .lazy()

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


On Sat, Aug 15, 2009 at 11:48 PM, Benoit Jacob<jacob.benoit.1@xxxxxxxxx> wrote:
>>>> 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?
>>
>> hm, not really because:
>>
>> D.noalias() = A*B + C;
>>
>>  it is the same as:
>>
>> D.lazyAssign( (A*B) + C);
>>
>> which is the same as:
>>
>> D = (A*B).eval() + C;
>>
>> But here you can avoid a temporary and still have an efficient
>> evaluation of the product by doing:
>>
>> D = C;
>> D.noalias() += A*B;
>>
>> (best for dynamic sizes)
>>
>> or:
>>
>> D.noalias() += A*B;
>> D += C;
>>
>> (best for small fixed sizes)
>
> Hm. Rather fascinating! And do you have a plan to make Eigen decide
> that automatically?

Yes that could be done by top-down expression analyser, something
similar than ei_blas_traits but more sophisticated to automatically
re-organize the expression. For instance when it detects a
BinaryOp<ei_scalar_sum_op> with a product on one side, and the result
is "noalias", then it could assign one side to the result and then
performs a +=. To this end, we would also have to ignore the
EvalBeforeAssignBit during the construction of the expression. This
would allows to implement much more sophisticated optimizations but
I'm really scared about the compilation time....

>>> 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?
>>
>> this is because we have overloads for += <product> and -= <product> so
>> that you can have:
>>
>> c += (a*b).lazy()
>>
>> oops, now you should rather write:
>>
>> c.noalias() += a*b;
>>
>> and evaluate it without temporary because this what the underlying
>> optimized routine does.
>
> I see. So you're saying that in this case, a.noalias()+=b is not
> equivalent to a.noalias()=a+b, it also has the effect of ignoring the
> EvalBeforeNesting bit on b? And that's not a general rule but rather a
> property of the underlying optimized routine?
>
> I'm OK with this behavior but I think that it needs to be a little
> more predictable. Perhaps it could be explicitly said that
> a.noalias()+=b assumes that there is no aliasing between a and b. In
> this way, the decision of evaluating b or not becomes purely an
> optimization issue and we're free to do what we want in the backyard
> :)

that's precisely the definition of noalias().

gael

> Benoit
>
>
>
>
>>
>> And yes, if you write:
>>
>> c = c + a*b;
>>
>> then you lost this optimization, and a*b is evaluated into a temporary.
>>
>> However without noalias():
>>
>> c += a*b;
>>
>> is the same as:
>>
>> c += (a*b).eval();
>>
>>
>>
>>
>> Perhaps I should also say that:
>>
>> 2 * (a * b)
>>
>> actually returns a product expression, and not a CwiseUnaryOp because
>> the optimized routine performs this scaling anyway.
>>
>> ah, and another details: when you write c.noalias() = a*b (with c
>> large enough), it is actually evaluated as:
>>
>> c.setZero();
>> c.noalias() += 1 * a * b;
>>
>>
>> Gael
>>
>>
>>
>
>
>



-- 
Gaël Guennebaud
Iparla - INRIA Bordeaux
(+33)5 40 00 37 95



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