[eigen] Re: still the solve() API debate |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen <eigen@xxxxxxxxxxxxxxxxxxx>
- Subject: [eigen] Re: still the solve() API debate
- From: Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
- Date: Thu, 10 Sep 2009 15:09:04 -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=TFlj/Ntip1Kr+FtAlBdN8Wsk2xAcchI4AJFIskvq5ns=; b=H30ET/0HdZ9wyzXN5XJno+32AUfoht7yrWeolcQdVFVPE8riQiU5iCiqYOR+0/gOBP i6NisMe8+W15A7TI7wL8XsgKlkdFScyO7U0TQgErTzCN18DSL4KtCmd/w50htGbUHnbx x0o6IvxaIpf5ZJtl6tBZeoDLe9heIYI5faoiE=
- 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=a2Px/YT3gOWnHMDBKy2oQ8dfIExfusiG3gNm3zBXDreOGuH/wQmEF7nUg9HJUNMmPG mM2iRObH6FWpPEmE2ODIhN778uepgXZXQ91g81GWXUh14ylee14L79TLVt6KTY4GULRU QTUySVdrwjI5P5wGoY1v0HTQguAkY02l/C9q0=
I forgot to say that this is assuming that the ReturnByValue proxy
doesn't inherit MatrixBase.
I take this for granted because Gael already advocated this during this debate.
Gael -- feel free to change your mind as many times as you like :)
Benoit
2009/9/10 Benoit Jacob <jacob.benoit.1@xxxxxxxxx>:
> Hi,
>
> we really need to make a decision here to be able to move on...
>
> *** The options ***
>
> Here are the options on the table:
>
> 1.
> A.solve(b, &result)
> Pro: simple, functional, predictable
> Con: not very nice API; some object that passing ptrs isn't C++-ish.
>
> 2.
> result = A.solve(b) // returning a plain Matrix
> Pro: most natural, simple, nice API
> Con: the result may be copied redundantly which hurts performance.
>
> 3.
> result = A.solve(b) // returning a proxy object
> Pro: nice, natural API in this case; no performance problem
> Con: Unpredictable since A.solve(b) can't be used in an expression;
> adds more code complexity
>
> 4.
> A.solve(b, result.ref())
> Pro: combines the advantages of 1. while pleasing people who don't like pointers
> Con: ref() is more wordy than &; and It's still not as convenient as 2.
>
>
> *** My proposal ***
>
> I propose that we keep 1., where we actually put the implementation
> (this is how we currently do), and alongside it, also offer 2. in the
> API, as a trivial wrapper around 1.
>
> Like this:
>
> template<typename RightHandSideType, typename ResultType>
> void Solver::solve(const RightHandSideType& b, ResultType *result)
> {
> /// bla bla, put the solver implementation there
> }
>
> template<typename RightHandSideType>
> PlainMatrixType solve(const RightHandSideType& b)
> {
> PlainMatrixType m;
> solve(b, &m);
> return m;
> }
>
> Here are my arguments. Sorry if this contradicts opinions that i
> expressed before.
>
> I see 2 nontrivial points that I need to justify:
> a) why plain pointer and not .ref()
> b) why return by value and not ReturnByValue
>
> Let's start with b). The advantage of returning a plain matrix is
> obvious; the drawback is the potential performance problem. What
> happens in practice? There are two cases, either the result is a
> fixed-size matrix or it is dynamic-size. If the result is a fixed-size
> matrix then (i did some experiments...) it seems that the RVO works
> perfectly, so there's no performance issue at all. If the matrix is
> dynamic-size (array on the heap) then indeed the RVO doesn't seem to
> happen (by the way that's mysterious to me, why is that?) so we indeed
> pay for a redundant malloc/copy/free. But does it matter? We're
> talking about dynamic size, so we optimize for large sizes, where this
> overhead is relatively small (the solving itself has cubic complexity
> for matrix solve and quadratic complexity for a vector solve, so it's
> always bigger!) Thus, I don't really believe anymore in the
> performance argument against 2.
>
> Plus, we still offer 1. in the API for the user who's concerned about
> explicitly avoiding this potential performance issue.
>
> Now let's discuss a). Really my only argument for &result instead of
> result.ref() is that it's shorter to type and the result is more
> obvious to everybody. What would be arguments for ref() in this case?
>
> If I remember well the arguments for ref() were to honor constness in
> swap() and have a single, uniform syntax for output args everywhere.
> But there's a problem: it's heavy to write, especially in swap().
> We're not going to force the user to write
> mat.row(i).ref().swap(mat.row(j).ref());
> So at least swap would have to escape that uniformization... so after
> all, sorry, i'm afraid that the ref() idea is blocked by how heavy it
> makes the API :( internally, I agree that it was a very good idea.
>
> Anyway, in this particular case: A.solve(b,&result), there's no const
> correctness issue, and the only intrinsic advantage of ref() over a
> pointer is that many people don't like pointers in C++. But, here i
> need to be honest: i don't really understand why. They're almost the
> same thing as references (at least, _const_ pointers are. do you like
> it better if we make it a const pointer)? I understand that they don't
> have the same nice properties in some cases, but does any of that
> matter in the present use case?
>
> If you would prefer us to standardize on references instead of
> pointers, speak up, i don't want to impose a decision onto the rest of
> people here. I just thought that the advantage of using pointers here,
> namely that in A.solve(b, &result) it is immediately clear which one
> is the result, would outweigh the drawbacks (tell me if i'm missing
> something).
>
> Benoit
>