Re: [eigen] What is the 'correct' way to pass matrix results? |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
On 18.05.2011 13:42, Hauke Heibel wrote:
Hi Christoph,
There is no single correct solution. It depends on your requirements
and your working environment.
On Wed, May 18, 2011 at 12:43 PM, Christoph Hertzberg
<chtz@xxxxxxxxxxxxxxxxxxxxxxxx> wrote:
1) Implement an expression template -- this might be ok if your code is
in pre-final stage ... or if you return using C++0x auto return type;
otherwise, I think it is a bit too complicated.
I agree, that writing an expression is quite complicated but I
disagree that using an expression is complicated. Its usage gets only
complicated, when you try to store the expression into a temporary
which is not a PlainObject, i.e. when you exactly need to know the
type of an expression. In most cases you probably do not need this
knowledge.
Well, I need to know the type if I want to return it -- unless I use
C++0x in which case I can return auto (and can also use auto for
temporary expressions).
2) Pass output parameters by values, inline everything and rely on your
compiler to optimize away unnecessary overhead. I think this works
reasonably well for small types, I experienced some overhead when
assigning vectorized expressions to unaligned destinations, though.
In case we are talking about expressions, they are always returned by
value. The difficulty is that such expressions may be complex
constructs consisting of several other nested expressions. Thus their
return types are complicated or at least cumbersome to define.
This case I meant by 1).
In case we are returning an Eigen PlainObject (Matrix or Array), it
can only be optimized away, as long as it is not dynamic. For dynamic
matrices there will always be at least one copy (ignoring std::move
features from C++0x, see bug #266 for details).
This solution is partly efficient (for fixed size types), portable,
const-correct and simple while being not generic. In fact, even with
C++0x features, this solution would always be only partially
efficient, since it will always introduce temporaries when assigning
to other expressions.
Yes, my use case is small fixed sized matrices most of the time (still
wanted to keep this thread generic). If the result fits completely into
some registers there is usually no overhead, indeed. One pitfall is
assigning vectorized expressions to unaligned locations:
http://eigen.tuxfamily.org/bz/show_bug.cgi?id=0x100
3) Pass a Matrix<...> by reference. This does not work when assigning
to a block or similar.
As you observed, this approach is not generic but it is efficient,
portable, safe and easy to implement.
4) Pass a const MatrixBase<...>& as proposed here [1] and const_cast
it. Obvious drawback of this is that it easily bypasses const-
correctness (actually only for plain matrices, not for blocks/maps).
This is quite a hack and we always said so but ... it is an efficient,
generic, portable and easy solution though not safe.
Now, let's assume you develop in an environment, where you have access
to C++0x and let's furthermore assume that your code is never intended
to be compiled on a non C++0x system.
A) Pass the output by r-value reference:
template<typename Derived>
void foo(MatrixBase<Derived>&& output) {}
This solution is efficient, generic, safe, easy to implement but not portable.
Yes, true. This as well as 1) should work well and efficient on C++0x.
I'm not sure, if I already want to lose C++03 compatibility already,
though ...
Maybe solution A) should be included into the documentation somehow
(marked as C++0x-only).
To truly answer your question, one would need to know the exact use
case and usage constraints.
Yeah, I have several different use cases. I usually just need to return
comparatively small vectors (of varying sizes) and (usually) store them
into parts of a big vector.
The result is generated by some user-defined function which is stored
into a wrapper-object.
What I currently do is passing a double-pointer to the wrapper, which
passes a slightly customized Map object to the function (it basically
just inherits from Map and has additional constructors).
Unfortunately passing these Maps to further functions seems not to get
always inlined and completely loses vectorization possibilities.
I am currently implementing pass-by-value, at least within the inner
functions (not in the wrapper) ...
Christoph
--
----------------------------------------------
Dipl.-Inf. Christoph Hertzberg
Cartesium 0.051
Universität Bremen
Enrique-Schmidt-Straße 5
28359 Bremen
Tel: (+49) 421-218-64252
----------------------------------------------