mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
release of tvmet (inactive for 2 years and developer unreachable) as the basis for eigen2, because it provides seemingly good expression template mechanisms, we want that, and it would take years to reinvent that wheel. We'll see. So this commit imports the last tvmet release.
326 lines
9.0 KiB
Plaintext
326 lines
9.0 KiB
Plaintext
/*
|
|
* $Id: notes.dox,v 1.20 2004/04/11 01:29:41 opetzold Exp $
|
|
*/
|
|
|
|
/**
|
|
\page notes Some Notes ...
|
|
|
|
<p>Contents:</p>
|
|
-# \ref optimizing
|
|
-# \ref temporaries
|
|
-# \ref operators
|
|
-# \ref threads
|
|
-# \ref expressions
|
|
-# \ref adl
|
|
-# \ref alias
|
|
-# \ref spec_meta_func
|
|
-# \ref mmv
|
|
|
|
|
|
|
|
|
|
\section optimizing ... on optimizing
|
|
|
|
This depends heavily on compiler and the flags used. The code produced with
|
|
-O could be better than with -O2 even on gcc-2.9x suite. To get the best
|
|
results, you should examine the assembler code generated by your compiler.
|
|
Maybe I will write a benchmark suite for different compiler options one day.
|
|
(Maybe you could contribute?)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
\section temporaries ... on temporaries
|
|
|
|
The use of expression templates (ET) and meta templates (MT) allows the
|
|
generated code to avoid the creation of many temporaries -- especially with
|
|
standard mathematical and assignment operations. There are times that you
|
|
have to use actual temporaries e.g. when swapping variables of type
|
|
double -- with integer values you can use the XOR operator.
|
|
|
|
Some implementations are using a loop with temporaries even if there is a
|
|
solution with ET. Than the loops are faster than MT.
|
|
|
|
\sa \ref mmv
|
|
|
|
|
|
|
|
|
|
|
|
\section operators ... on operators and namespace element_wise
|
|
|
|
Some operations on matrices and vectors are not available at first glance.
|
|
These are defined in the namespace <code>element_wise</code> because they
|
|
are element wise (and not strictly mathematical) operations.
|
|
|
|
But there is more: some functions do element wise operations per se (e.g.
|
|
vector addition) and are NOT inside namespace element_wise. Furthermore,
|
|
all comparison operators perform element wise operations.
|
|
|
|
\sa \ref compare
|
|
|
|
|
|
|
|
|
|
|
|
\section threads ... about Threads
|
|
|
|
This library is not thread safe. It's designed for small math operations where
|
|
the overhead for locking policies is too great. If you require locking for
|
|
a multi-threaded application, you will need to write a wrapper.
|
|
|
|
|
|
|
|
|
|
|
|
\section expressions ... on expressions
|
|
|
|
The first versions of %tvmet had only one expression (Xpr) which was shared
|
|
for both vectors and matrices. This was working fine, but limited tvmet's
|
|
use for arithmetic expressions expressions on complex values. For this
|
|
reason, I had to separate expression types for vectors and matrices. The
|
|
same problem appeared when using the eval() function for evaluating these
|
|
expressions. (Which index operator should handle it?) Unfortunately, the
|
|
use of separate expression types vastly increases the number of operators
|
|
and functions needed to make the library viable. Fortunately, most boundary
|
|
checks are not necessary since they are done at compile time (such as those
|
|
needed by the assignment operator, etc).
|
|
|
|
|
|
|
|
|
|
|
|
\section adl ... on namespaces and Koenig Lookup
|
|
|
|
IMO, the cleanest way would be to put all functions into their own
|
|
namespace <code>Functional</code> instead of naming them with the
|
|
<code>fncl_</code> prefix they currently have. (I did beforehand, and
|
|
have thought better since). Unfortunately, this technique doesn't work well.
|
|
I got compiler errors like:
|
|
|
|
\code
|
|
template <class T> Functional::xyt<T>' is not a function
|
|
conflict with `template <class E> xyz(Xpr<E>)' in call to `xyz'
|
|
\endcode
|
|
|
|
when trying:
|
|
|
|
\code
|
|
typedef Vector<double, 3> vector3d;
|
|
vector3d t1(1,2,3);
|
|
vector3d t2(t1);
|
|
vector3d r;
|
|
r = sqrt( t1 * t2 );
|
|
\endcode
|
|
|
|
ADL (argument dependent lookup), aka Koenig Lookup, is causing the
|
|
compiler to check for a match in namespace Functional, since the
|
|
template instantiation is part of Functional (the Xpr stuff), it matches
|
|
before the global namespace (the Vector stuff) is checked. Writing:
|
|
|
|
\code
|
|
r = ::sqrt( t1 * t2 );
|
|
\endcode
|
|
|
|
seems to solve the problem at first glance. However, to force the user of
|
|
the library into this syntax is painful and could probably run cause other
|
|
problems with other namespaces (I haven't checked this). Therefore, all
|
|
"Functionals" have the prefix fncl_.
|
|
|
|
|
|
|
|
|
|
|
|
\section alias ... about aliasing
|
|
|
|
tvmet assumes that all matrices and vectors are alias free. These means that
|
|
source and destination memory layout of matrices and vectors never overlaps
|
|
(during an operation).
|
|
|
|
This is very easy to understood if you see a matrix-vector product. Both
|
|
contain different data in different (unique, non-overlapping) memory
|
|
regions -- hence, they are alias free. Contrast this with a matrix-matrix
|
|
multiply which maybe can have an aliasing, e.g. \f$A = A * B\f$.
|
|
When source and destination memory regions are the same, the computed results
|
|
may be wrong. (Probably they will be.) But, \f$C = A * B\f$ is alias free.
|
|
|
|
Let's see an example in detail:
|
|
|
|
\par Example:
|
|
\code
|
|
Matrix<double,3,3> M1;
|
|
M1 = 1,2,3,4,5,6,7,8,9;
|
|
|
|
cout << "M1 = " << M1 << endl;
|
|
M1 = trans(M1);
|
|
cout << "M1 = " << M1 << endl;
|
|
\endcode
|
|
|
|
\par Output:
|
|
\code
|
|
M1 = Matrix<d, 3, 3> = [
|
|
[1, 2, 3],
|
|
[4, 5, 6],
|
|
[7, 8, 9]
|
|
]
|
|
M1 = Matrix<d, 3, 3> = [
|
|
[1, 4, 7],
|
|
[4, 5, 8],
|
|
[7, 8, 9]
|
|
]
|
|
\endcode
|
|
|
|
As you can see, the lower triangular matrix isn't what you expected due to
|
|
the aliasing. These results depends on the compiler optimizations, too.
|
|
|
|
Unfortunately, to avoid the aliasing problem, you must use temporaries
|
|
as shown here:
|
|
|
|
\par Example:
|
|
\code
|
|
matrix_type temp_A(A);
|
|
A = temp_A * B;
|
|
cout << "matrix_type temp_A(A);\n"
|
|
<< "A = temp_A * B = " << A << endl;
|
|
\endcode
|
|
|
|
Anyway, it seems there is a small exception (no guarantee, since it's
|
|
compiler dependent I assume) for element wise operations with matrices
|
|
or vectors on right hand side.
|
|
|
|
Starting with tvmet release 1.4.1 there is a new function alias. These
|
|
function use a proxy to call special member functions of the %Matrix/Vector
|
|
class. These member functions introduce the temporary for you.
|
|
|
|
\par Example:
|
|
\code
|
|
typedef tvmet::Matrix<double, 3, 3> matrix_type;
|
|
matrix_type M;
|
|
std::generate(M.begin(), M.end(),
|
|
tvmet::util::Incrementor<matrix_type::value_type>());
|
|
std::cout << "M = " << M << std::endl;
|
|
|
|
alias(M) = trans(M);
|
|
std::cout << "M = " << M << std::endl;
|
|
\endcode
|
|
|
|
with the expected
|
|
|
|
\par Output:
|
|
\code
|
|
M = [
|
|
[1, 4, 7],
|
|
[2, 5, 8],
|
|
[3, 6, 9]
|
|
]
|
|
\endcode
|
|
|
|
These function/proxy will work for the element wise operators +=, -=, *= and /=
|
|
with expressions, e.g. as trans() returns.
|
|
|
|
\sa \ref assign_op
|
|
|
|
|
|
|
|
|
|
|
|
\section spec_meta_func ... special Meta-Template Functions
|
|
|
|
From a principle point of view, there is no need for some special functions
|
|
for %Matrix and %Vector functions, namely \f$M^T\, x\f$, \f$M^T\,M\f$,
|
|
\f$M\,M^T\f$, and \f$(M\,M)^T\f$.
|
|
|
|
Unfortunately, the g++ compiler throws in the towel sometimes even on
|
|
transposing matrices. Because of this, %tvmet offers specialized functions
|
|
which speed up at runtime (about factor 2 ... 3) using meta templates.
|
|
|
|
\par Example:
|
|
\code
|
|
using namespace tvmet;
|
|
|
|
Matrix<double, 6, 3> M1(0); // will be transposed to be conform to vector size
|
|
Vector<double, 6> v1(0);
|
|
Vector<double, 3> v2(0);
|
|
|
|
M1 = ...
|
|
v1 = ...
|
|
|
|
v2 = Mtx_prod(M1, v1); // equal to: v2 = trans(M1)*v1;
|
|
\endcode
|
|
|
|
BTW, the %Matrix-%Matrix \f$M\,M\f$ and %Matrix-%Vector \f$M\,x\f$
|
|
products use Meta-Templates, too.
|
|
|
|
\sa \ref Mtx_prod
|
|
\sa \ref MMt_prod
|
|
\sa \ref MtM_prod
|
|
\sa \ref trans_prod
|
|
|
|
|
|
|
|
|
|
|
|
\section mmv ... about Matrix-Matrix-Vector and Matrix-Matrix-Matrix-operations
|
|
|
|
The problem is related to the optimizer - due to the expression and meta
|
|
templates used.
|
|
|
|
Internally, an expression template may contain other expression templates
|
|
(meta templates inside as well as) too - the compiler will unroll all of
|
|
these expression into a single resultant expression (which is a hard job).
|
|
Sometimes the code generated from this is worse (from a performance point
|
|
of view) than just using simple temporaries.
|
|
|
|
You can chain matrix-matrix and matrix-vector operations without writing
|
|
temporaries by yourself (if this is what you want).
|
|
|
|
\par from examples/hspiess.cc:
|
|
\code
|
|
tvmet::Matrix<double,3,2> B;
|
|
tvmet::Matrix<double,3,3> D;
|
|
tvmet::Matrix<double,2,2> K;
|
|
|
|
B =
|
|
-0.05, 0,
|
|
0, 0.05,
|
|
0.05, -0.05;
|
|
D =
|
|
2000, 1000, 0,
|
|
1000, 2000, 0,
|
|
0, 0, 500;
|
|
|
|
K = trans(B) * D * B;
|
|
\endcode
|
|
|
|
The performance can be sub optimal due to the increasing complexity
|
|
of operations. This can be reduced by a user specified temporary:
|
|
|
|
\par from examples/hspiess.cc:
|
|
\code
|
|
// as before
|
|
|
|
K = tvmet::Matrix<double,2,3>(trans(B) * D) * B;
|
|
\endcode
|
|
|
|
or
|
|
\code
|
|
K = prod(tvmet::Matrix<double,2,3>(prod(trans(B), D)), B);
|
|
\endcode
|
|
|
|
At this moment an intelligent cache and pre-evaluating strategy is
|
|
missing by %tvmet.
|
|
|
|
\sa \ref spec_meta_func
|
|
\sa some notes \ref temporaries
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
// Local Variables:
|
|
// mode:c++
|
|
// End:
|