Re: [eigen] Eigen Types as Parameters for Functions |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen@xxxxxxxxxxxxxxxxxxx
- Subject: Re: [eigen] Eigen Types as Parameters for Functions
- From: Gael Guennebaud <gael.guennebaud@xxxxxxxxx>
- Date: Wed, 27 Jun 2012 14:41:34 +0200
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :content-type:content-transfer-encoding; bh=t3KRWRhvUzbCsdZAt5tCItUXrxbJox3kdkaW8HBd8ZM=; b=x21h6KhQhzy/MuBScIdAQW4w2i3mOeCSD5hA2Nvk2aukVEjfA/NP+g9zlj8FdpkQt/ eyirOCXjSWZPm8Qc+VY+XPmv4Uws9FKj8mZng1PCmFkDUyOJUtQHdJMVrqU9yF9h2pJt ydLu4rOZ4vzNu1uEWCiH7sNyDz5rP0gZuG/8l4joe3pec4wzn5qYv6+kzBgrTKtWCzK5 VyIaTjXZFN2px4SkpgUsIr3qKvFydCb+PoODFS7M3qvVpaQ4bBkGvyH9cfwwubpS/M72 WkvI/vNEUeWTsad2GE2bv98QhXPuaevRclGIGwTbT3YbCof/ysi0T1jrTNe+pvm9aqyc 2abw==
The current implementation is only a first draft which clearly needs
some improvements.
On Wed, Jun 27, 2012 at 11:14 AM, Christoph Hertzberg
<chtz@xxxxxxxxxxxxxxxxxxxxxxxx> wrote:
> some questions/notes:
> * Does A.row(3); change after calling foo1(A.row(3))? (i.e. is it
> copied back?) -- you could simply copy it back in the destructor, if
> match_helper<Derived>::type() is false_type.
> If you think back-copying causes too much performance penalty, you
> need to forbid this.
> Furthermore, it sometimes might be useful to mark Ref as a pure
> "out-ref" in this case, saving the copy from A.row() to m_object.
That's a very good remark, and currently I don't have a strong opinion
whether we should copy-back or forbid it. The copy-back option is ok
when Ref is used for function arguments and in sequential algorithms,
but very dangerous in all other cases. For instance, I was thinking
about Ref<> inside Eigen itself to reduce template instantiations. In
this case you clearly don't want the copy-back approach.
On the other hand, I known it would be very convenient for many
users. Proposing both might be overkill.
> * If you pass, for example, a Ref<Vector4d>, don't you have a Vector4d
> (the m_object member) lying on the stack then? That might cause
> alignment issues if the stack is not aligned (I did not test it yet).
I don't think that's a problem because if the compiler does not know
how to align the stack then we cannot use aligned objects at all, not
only inside Ref<>.
>
>
> Christoph
>
>
>
>
>
> On 27.06.2012 10:25, Gael Guennebaud wrote:
>>
>> Hi all,
>>
>> I've implemented a solution fully described there:
>> http://eigen.tuxfamily.org/bz/show_bug.cgi?id=481
>>
>> feedback more than welcome!
>>
>> For the lazy ones, here is a self-explanatory example of the proposed
>> solution:
>>
>> #include <iostream>
>> #include <Eigen/Dense>
>> using namespace Eigen;
>>
>> // read-write access to 'a'
>> void foo1(Ref<VectorXf> a) { }
>>
>> // read-only access to 'a'
>> void foo2(Ref<const VectorXf> a) { }
>>
>> int main()
>> {
>> VectorXf a(10);
>> const VectorXf& ac(a);
>> VectorBlock<VectorXf> ab(a,0,3);
>> MatrixXf A(10,10);
>> const VectorBlock<VectorXf> abc(a,0,3);
>>
>> foo1(a);
>> //foo1(ac); // does not compile because ac is const
>> foo1(ab);
>> foo1(a.head(4));
>> foo1(abc);
>> foo1(A.col(3));
>> foo1(A.row(3)); // copied into a temp because innerstride!=1
>>
>> foo2(A*A.col(1)); // evaluated into a temp
>> foo2(ac.head(5));
>> foo2(ac);
>> foo2(a);
>> foo2(ab);
>> foo2(a.head(4));
>> foo2(a+a); // evaluated into a temp
>>
>> return 0;
>> }
>>
>> cheers,
>> Gaël
>>
>> On Mon, Feb 27, 2012 at 7:44 PM, Gael Guennebaud
>> <gael.guennebaud@xxxxxxxxx> wrote:
>>>
>>> btw,
>>>
>>> this more or less what Christian suggested but more restrictions because:
>>> 1 - the storage order really has to be known at compile time otherwise
>>> we cannot construct an expression
>>> 2 - same for the alignment, especially for small fixed sizes.
>>> Otherwise the alignment is already determined at runtime by checking
>>> the pointers, so no need to specify it.
>>> 3 - a runtime inner-stride can really kill the performance so it is
>>> important to let the user decide whether he can tolerate that or not.
>>> 4 - distinguishing at compile-time between vectors and matrices is
>>> fundamental too
>>>
>>> So if we go for a specific class (not Map) it could had 5 template
>>> parameters:
>>> - typename scalar
>>> - int rows
>>> - int cols
>>> - int storage_order
>>> - int inner_stride = 1
>>>
>>> cheers
>>> gael
>>>
>>> On Mon, Feb 27, 2012 at 7:34 PM, Gael Guennebaud
>>> <gael.guennebaud@xxxxxxxxx> wrote:
>>>>
>>>> Alright, I thought I had already replied to this thread but I haven't
>>>> so here I go.
>>>>
>>>> My general idea to offer the ability to write non template function
>>>> while still offering some flexibility on the input is really simple:
>>>> simply add constructors to Map<> that can take Eigen's objects such as
>>>> Matrix, Block, Map, etc. Then it is up to user to specify the level of
>>>> flexibility he wants for his arguments: dynamic/fixed sizes,
>>>> outer-stride? inner-stride? matrix/vector?
>>>>
>>>> For instance:
>>>>
>>>> void foo(const Map<MatrixXd,0,OuterStride<> >& arg);
>>>>
>>>> should accept any MatrixXd, Matrix4d, Block, Map, etc.
>>>>
>>>> There are some limitations though:
>>>> - No template is possible at all, in particular it is not possible to
>>>> templatize the scalar type, but this is fine to me since if the user
>>>> can tolerate some template parameter then why not allowing everything.
>>>> - The storage order has to be fixed too. I understand a runtime
>>>> storage order might be convenient, but this is really not the Eigen
>>>> philosophy, so this limitation will have to stay.
>>>>
>>>> However, I have question regarding the handling of non compatible
>>>> expressions. For instance what should we do with:
>>>>
>>>> foo(A+B); // this is a pure expression without direct access
>>>>
>>>> or
>>>>
>>>> MatrixXcf C;
>>>> foo(C.real()); // C.real() has an inner-stride, but foo does not accept
>>>> that
>>>>
>>>> If we stick with Map<> I think that there is only one possible
>>>> solution: compilation error. Then it is up to the user to explicitly
>>>> evaluate it.
>>>>
>>>> Another approach would be to add a variant of Map tailored for this
>>>> use case that would allow to silently evaluate the argument into a
>>>> temporary. This is what happen if the user declare his argument as a
>>>> const MatrixXd&.
>>>>
>>>> Any opinion on which approach we should follow?
>>>>
>>>> cheers,
>>>> gael
>>>>
>>>> On Thu, Jan 26, 2012 at 3:12 PM, Christoph Hertzberg
>>>> <chtz@xxxxxxxxxxxxxxxxxxxxxxxx> wrote:
>>>>>
>>>>> On 26.01.2012 14:50, Benoit Jacob wrote:
>>>>>>
>>>>>>
>>>>>> 2012/1/26 Christoph Hertzberg<chtz@xxxxxxxxxxxxxxxxxxxxxxxx>:
>>>>>>>
>>>>>>>
>>>>>>> On 26.01.2012 14:33, Benoit Jacob wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> 2012/1/26 Christian Seiler<christian@xxxxxxxx>:
>>>>>>>>
>>>>>>>>> - subclass of MatrixBase, i.e. can be used inside the function
>>>>>>>>> like a
>>>>>>>>> Matrix object
>>>>>>>>> - has private members containing the above-mentioned bits of
>>>>>>>>> information (pointer to first element, dimension, ...)
>>>>>>>>> - can be implicitly converetd to from any compatible MatrixBase
>>>>>>>>> (i.e.
>>>>>>>>> foo(mat) and foo(mat.block(...)) can be used directly)
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> Just note that this is only possible for those matrix expressions
>>>>>>>> whose coefficients are stored in memory with a simple enough layout
>>>>>>>> that can be described in terms of strides. That is what we call a
>>>>>>>> "Direct Access" matrix expression; the test is
>>>>>>>> ExpressionType::Flags&
>>>>>>>> DirectAccessBit.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Yes, and I would say this would be the main application, if you have
>>>>>>> complicated-enough functions (i.e. where you don't really bother
>>>>>>> about
>>>>>>> evaluating expressions to a temporary if required).
>>>>>>> And more importantly, when having parameters that are actually output
>>>>>>> parameters, you are more or less stuck to direct access types anyway
>>>>>>> --
>>>>>>> and
>>>>>>> this is a very important point, where currently const-correctness is
>>>>>>> ignored
>>>>>>> (almost) entirely.
>>>>>>>
>>>>>>>
>>>>>>>> With that said, yes, we have been considering doing this, that's bug
>>>>>>>> 58:
>>>>>>>> http://eigen.tuxfamily.org/bz/show_bug.cgi?id=58
>>>>>>>>
>>>>>>>> If someone wants to do this and needs mentoring, I should find time
>>>>>>>> to
>>>>>>>> do at least that mentoring.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I'd be interested at least to join the "specification committee" ;)
>>>>>>
>>>>>>
>>>>>>
>>>>>> Really, I haven't thought about this in a long time so your thoughts
>>>>>> on this subject are probably a lot fresher than mine. From the top of
>>>>>> my head, the starting point is to look at MapBase (which is inherited
>>>>>> both by Map and by Block<direct access type>) and ask: how much of the
>>>>>> templated stuff there can we replace by runtime variables (data
>>>>>> members), and try to make all direct-access types inherit the
>>>>>> resulting base class (in particular, Matrix should inherit it).
>>>>>
>>>>>
>>>>>
>>>>> Yes, my thoughts were about the same. Actually, the only difference
>>>>> between
>>>>> a Map/Block and a Matrix should be that the Matrix "owns" its memory,
>>>>> i.e.
>>>>> has to deallocate it on destruction (with a special case of fixed size
>>>>> matrices having static memory).
>>>>>
>>>>> Furthermore, if one allows strides in the Matrix-class, some
>>>>> specialized
>>>>> types, such as AlignedVector3 would become just a typedef. Currently,
>>>>> if
>>>>> someone needs an aligned vector7, he'd have to to the same thing again
>>>>> --
>>>>> also it might be interesting to store an aligned 3x3 matrix as the top
>>>>> 3
>>>>> rows of a 4x3 matrix allowing a much more efficient matrix-vector
>>>>> product.
>>>>>
>>>>>
>>>>> Christoph
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> ----------------------------------------------
>>>>> Dipl.-Inf. Christoph Hertzberg
>>>>> Cartesium 0.051
>>>>> Universität Bremen
>>>>> Enrique-Schmidt-Straße 5
>>>>> 28359 Bremen
>>>>>
>>>>> Tel: (+49) 421-218-64252
>>>>> ----------------------------------------------
>>>>>
>>>>>
>>
>
>
> --
> ----------------------------------------------
> Dipl.-Inf. Christoph Hertzberg
> Cartesium 0.049
>
> Universität Bremen
> Enrique-Schmidt-Straße 5
> 28359 Bremen
>
> Tel: +49 (421) 218-64252
> ----------------------------------------------
>
>
>
>