Re: [eigen] about .lazy() |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen@xxxxxxxxxxxxxxxxxxx
- Subject: Re: [eigen] about .lazy()
- From: Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
- Date: Sat, 15 Aug 2009 17:48:34 -0400
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:in-reply-to:references :date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=M/9HYyrmD0ettvo1JXrronmDMv3BLWhH3qgMDciDuIo=; b=UuuJKLvpw6Rksx3xVzJP3XsdXA0tk2Rp7NOaSTN9xAkNae1+pE3NI5uTi5RO3IYWEP vAaRPijG1Qfcu9hmQUF/RCI6xQrk7i6p0vkYJDz9HErykotDSgp+Fwtd8alOeBOegxkT WciGFRZBiTS1WaOgCrn6Wu0rKgX/cVuoTJM9Q=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; b=vXa6VYm3cAbAphOfxxhU0IUT3auQJD1gTqIeMtbIpKpVxlL3DlCK+G7sKP9gUaxZcU O+OzOt9eTc9lKNrnsGppHVUENjLjdoFkiV2Dsy6TgC5WGvSI3MsT9vLTBP04KSB/TbhO 782wFM2oSWqzBwZmp3WL/tPWa7UChq2d6asvU=
2009/8/15 Gael Guennebaud <gael.guennebaud@xxxxxxxxx>:
> On Sat, Aug 15, 2009 at 10:48 PM, Benoit Jacob<jacob.benoit.1@xxxxxxxxx> wrote:
>> 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).
>
> hm, right I forgot about that, but Random only have the
> EvalBeforeNestingBit flags, so do we still need a way to remove that
> flag ? If so .lazy() would be perfect but if we keep .lazy() for that
> purpose we'll have strong backward compatibility issues. Unless we
> overload .lazy() in CwiseNullaryOp...
Oh I wasn't advocating keeping lazy(), even for that. Probably nobody
cares that much about the performance of random matrices. The use case
is very niche. If by now we haven't found a better use case, that
probably means that it's OK to remove lazy().
>> 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.
>
> yes that's what I meant, and basically .lazy() would be good at
> removing EvalBeforeNestingBit only (e.g., for Random) and .noalias()
> to bypass EvalBeforeAssigning. Our mistake was to use .lazy() for
> both.
OK. You decide if you want to keep such a lazy() or remove it
altogether (keeping it deprecated for now), I don't have a strong
preference.
>>> 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?
>> 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
:)
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
>
>
>