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: Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
- Date: Thu, 26 Jan 2012 08:33:24 -0500
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :content-type:content-transfer-encoding; bh=KRvrlrr1n+3npGeXrS+2z/sMiZAUa8H9E/7LX3yffMg=; b=mFLCy9J8ru/WgXeMZmraXicI50FlKM/79F1FlU7WmyGSjTpYGIXrU8U2QHTTFjAHuF j/CdW0nFaC9pq6uqVa0+8sKQ2RTl2C2HiVoKxo7BOxfF5CG3+c34ej9VFNrI795lvwx8 fKBoD1IzjtrD7SniD7cIULdhsveZkENhOfTUQ=
2012/1/26 Christian Seiler <christian@xxxxxxxx>:
> Hi,
>
> I'm a user and a fan of Eigen. However, there is one issue I frequently
> run into: I very often want to write functions that take Eigen types as
> parameters. Now, I've read
> <http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html>,
> and that has certain issues: First of all, these functions have to be
> defined as template functions, which means that they have to be defined
> in a header file in order to work. This is fine if the function does not
> do that much, but I'd really prefer to put the function into a separate
> compilation unit if the code is a little more complex. (But for this to
> work with template functions, I'd have to explicitly instantiate all
> possible template variants in the compilation units, and there I'm
> definitely going to miss quite a few.) Also, having to play around with
> const_cast<> and template logic seems a bit excessive to me just to
> pass a simple matrix / vector as an argument, while at the same time
> being able to accept Block-type objects or direct expressions etc.
> Especially if the code is supposed to be shared with other people that
> are not as well-versed in the intricacies of C++ as I am, who may also
> need to modify the code later on.
>
> Therefore, I'd like to propose a solution that would make the life for
> me (and probably a lot of other people) easier.
>
> Rationale: In the end, the only real information about a matrix stored
> in memory that one needs are:
> - pointer to the first element
> - dimension
> - row/col major
> - strides (inner/outer)
> - alignment
>
> I propose adding a new class (name could be decided on later, for the
> purpose of this class, I'll use MatrixParameter, although I don't like
> the name particularily) that has the following properties:
>
> - 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.
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.
Cheers,
Benoit
>
> This would allow one to create functions and/or methods that accept
> Eigen objects as parameters much more easily - and would even provide
> a stable binary ABI for libraries one wants to write, as long as the
> numerical type is specified.
>
> Examples of possible usage pattern:
>
> void veryComplicatedAlgorithm(
> Eigen::MatrixParameterXd result,
> Eigen::MatrixParameterXd orig
> ) {
> // do some very complicated calculation with orig
> // and store it in result
> }
>
> Matrix4d orig;
> orig << 1, 2, 3, 4,
> 5, 6, 7, 8,
> 9, 10, 11, 12,
> 13, 14, 15, 16;
> MatrixXd result(2,2);
> veryComplicatedAlgorithm(result, orig.block(1,1,2,2));
>
> double worksOnlyWithTwoByTwo(Eigen::MatrixParameter2d inp)
> {
> // or something...
> return inp(0,0) * inp(1,1) / (inp(0,1) + inp(1,0));
> }
>
> Matrix4d foo = Matrix4d::Identity();
> MatrixXd foo2 = MatrixXd::Identity(4, 4);
> double p = worksOnlyWithTwoByTwo(foo); // compile-time error
> double p2 = worksOnlyWithTwoByTwo(foo2); // run-time error
> // unless range-checking
> // disabled
> double p3 = worksOnlyWithTwoByTwo(foo.block(0, 0, 2, 2)); // works
> double p4 = worksOnlyWithTwoByTwo(foo2.block(0, 0, 2, 2)); // works
>
> void someWrapperAroundLegacyFortranCode(
> Eigen::MatrixParameterXd mat,
> Eigen::VectorParameterXd vec
> ) {
> // or something
> xxyyzz_(mat.size(), mat.data(), vec.data());
> }
>
> Considerations:
>
> - The layout of the fields in the class should be fixed once and for
> all, this allows binary compatibility even when using a different
> version of Eigen for compiling both compilation units.
> ("once and for all" should mean something like "only change this
> if the major version of Eigen changes")
>
> - If the functions are not templated themselves, this fixes the scalar
> data type. I don't see this as a problem though, because that may
> be what people want. Also, this scheme still allows for declaring
> something along the lines of template<typename Scalar> void
> foo(Eigen::MatrixParameter<Scalar, ...> ...); if this is really
> wanted
>
> - Resizing of output matrices is not easily possible here. However,
> I don't think this is necessarily a problem, since most of the
> time the calling code will already know what the dimension of
> matrices used for output have to be. And if somebody really
> requires the ability to resize matrices, it should always be
> possible to use the current way of passing Eigen matrices.
>
> - Expressions such as foo(A * B) can be tricky. I propse that we
> define two classes: The second class could be prefixed with "Const"
> (e.g. MatrixConstParameter). There, any expression would be
> evaluated into a temporary before being passed to the function,
> while plain matrices and .block(...) would remain untouched. The
> non-"Const"-variant, on the other hand, would only accept plain
> matrices and .block(...) expressions, since only those can
> guarantee write acccess. (Ok, .transpose() would also work because
> one can just flip the RowMajor/ColMajor bit, but .adjoint() would
> already be problematic.)
>
> - The documentation should warn about memory management caveats here.
> Basically, since the classes proposed here are just wrappers for
> pointers, if the matrix pointed to falls out of scope or is
> deleted, and somebody stored a reference somewhere, this will
> lead to bugs. Unfortunately, disabling the copy constructor is
> not possible, since it is needed to be able to pass through
> arguments to other functions.
>
> I'd like to here your thoughts on this, and I'm offering to implement
> my proposal if you agree with the basic idea.
>
> Thanks,
> Christian
>
>
>