It provides classes for statically- (known at compile time) and dynamically- (unknown at compile time) sized vectors and matrices and it delegates advanced functions (like SVD or multiplication of large matrices) to LAPACK and BLAS (this means you will need libblas and liblapack).
The library makes substantial internal use of templates to achieve run-time speed efficiency whilst retaining a (reasonably) clear programming syntax. Because of this use of templates, you will need a recent compiler (for example it does not work with g++ before version 3.0). Programs that use it can also take a long time to compile with -O3 under g++. Currently the library only supports double precision vectors and matrices.
Why use this library?
(*) This is not always true (see Implementation, below)
cvs -z3 -d:pserver:anonymous@cvs.savannah.nongnu.org:/sources/toon co TooN
include <TooN/TooN.h>, and any other header files you might need e.g. TooN/helpers.h (for some more matrix and vector functions) or TooN/SVD.h (for the singular value decomposition) to your source code.using namespace TooN to your code (or prefix class declarations with TooN::).-llapack -lblas (and -lg2c for g++. I'm not sure about other compilers). This means you will also need liblapack.{a,so} and libblas.{a,so}// Initialise the vectors Vector<3> a; a = 3,5,0; Vector<3> b; b = 4,1,3; // Now work out the products double dot = a*b; // Dot product Matrix<3,3> outer = a.as_col() * b.as_row(); // Outer product Vector<3> cross = a ^ b; // Cross product cout << "a:" << endl << a << endl; cout << "b:" << endl << b << endl; cout << "Outer:" << endl << outer << endl; cout << "Cross:" << endl << cross << endl;
Create a vector and a matrix and multiply the two together
// Initialise a vector Vector<3> v; v = 1,2,3; // Initialise a matrix double d[2][3] = {{2,4,5},{6,8,9}}; Matrix<2,3> M(d); // Now perform calculations Vector<2> v2 = M*v; // OK - answer is a static 2D vector Vector<> v3 = M*v; // OK - vector is determined to be 2D at runtime Vector<> v4 = v*M; // Compile error - dimensions of matrix and vector incompatible
See the detailed documentation for Vector, Matrix and the various matrix decompositions for more examples.
sizeof(Vector<3>) is 24. This means that when you write Vector<3> v; the data for v is allocated on the stack and hence new/delete (malloc/free) overhead is avoided. However, for large vectors and matrices, this would be a Bad Thing since Vector<1000000> v; would result in an object of 8 megabytes being allocated on the stack. I don't know about you, but my whole stack is only that big. TooN gets around that problem by having a cutoff at which statically sized vectors are allocated on the heap. This is completely transparent to the programmer, the objects' behaviour is unchanged and you still get the type safety offered by statically sized vectors and matrices. The cutoff size at which the library changes the representation is defined in toon.h as the const int MaxStackSize in the class NUMERICS.
When you apply the subscript operator to a Matrix<3,3> and the function simply returns the apropriate hunk of memory as a vector reference (i.e. it basically does no work). This avoids copying and also allows the resulting vector to be used as an l-value. Similarly the transpose operation applied to a matrix returns the memory corresponding to the matrix as a reference to a matrix with the opposite layout which also means the transpose can be used as an l-value so M1 = M2.T(); and M1.T() = M2; do exactly the same thing.
v1 = M * v2; a naive implementation will compute M * v2 and store the result in a temporary object. It will then copy this temporary object into v1. A method often advanced to avoid this is to have M * v2 simply return an special object O which contains references to M and v2. When the compiler then resolves v1 = O, the special object computes M*v2 directly into v1. This approach is often called lazy evaluation and the special objects lazy vectors or lazy matrices. Stroustrup (The C++ programming language Chapter 22) refers to them as composition closure objects or compositors.
The killer is this: What if v1 is just another name for v2? i.e. you write something like v = M * v;. In this case the semantics have been broken because the values of v are being overwritten as the computation progresses and then the remainder of the computation is using the new values. In this library v1 in the expression could equally well alias part of M, thus you can't even solve the problem by having a clever check for aliasing between v1 and v2. This aliasing problem means that the only time the compiler can assume it's safe to omit the temporary is when v1 is being constructed (and thus cannot alias anything else) i.e. Vector<3> v1 = M * v2;.
TooN provides this optimisation by providing the compiler with the opportunity to use a return value optimisation. It does this by making M * v2 call a special constructor for Vector<3> with M and v2 as arguments. Since nothing is happening between the construction of the temporary and the copy construction of v1 from the temporary (which is then destroyed), the compiler is permitted to optimise the construction of the return value directly into v1.
Because a naive implemenation of this strategy would result in the vector and matrix classes having a very large number of constructors, these classes are provided with template constructors that take a standard form. The code that does this, declared in the header of class Vector is:
// constructor from 2-ary operator template <class LHS, class RHS, class Op> inline Vector(const LHS& lhs, const RHS& rhs, const Operator<Op>&){Op::eval(*this,lhs,rhs);}
template <int Size, class AllocZone> class FixedVAccessor : public AllocZone { ... };
template <int Size> class Vector : public FixedVector<Size, FixedVAccessor<Size,typename SizeTraits<Size>::get_zone> > { ... };
1.4.7