matrix.h

Go to the documentation of this file.
00001 /***************************************************************************
00002                           matrix.h  -  description
00003                              -------------------
00004     email                : georg.martius@web.de
00005 ***************************************************************************/
00006 // provides Matrix class with convinient operators
00007 //  and fast inversion for nonzero square matrixes
00008 //
00009 /***************************************************************************/
00010 
00011 #ifndef MATRIX_H
00012 #define MATRIX_H
00013 
00014 #include <string.h>
00015 #include <assert.h>
00016 #include <list>
00017 #include <vector>
00018 #include <cstdlib>
00019 
00020 #ifndef AVR
00021 #include <iostream>
00022 #endif
00023 
00024 #include "storeable.h"
00025 
00026 // TODO: add doxygen section
00027 
00028 /**
00029  * namespace for the matrix library
00030  *@author Georg Martius
00031  */
00032 namespace matrix{
00033 
00034   /// integer constant for use with exp function and (^) operator to transpose the matrix
00035   extern const int T;
00036 
00037 /// type for matrix indices
00038   typedef unsigned int I;
00039   /// type for matrix elements
00040   typedef double D;
00041 
00042   class Matrix;
00043   typedef std::vector<Matrix> Matrices;
00044 
00045 #define D_Zero 0
00046 #define D_One 1
00047   /** Matrix type. Type D is datatype of matrix elements,
00048    * which is fixed to double.
00049    * Type I is the indextype of matrix elements,
00050    * which is fixed to unsigned int, if AVR is not defined.
00051    * There are basicly two different types of operation:
00052    * Inplace operations and copy operations.
00053    * Please use the latter ones unless you know what you are doing.
00054    * Just in case of critical performance optimisation use the inplace
00055    * operations.
00056    * The most convinient way is to use the overloaded operators
00057    * (like + * ...).
00058    * All constructed matrices are initialised with zero elements
00059    * (unless data is given).
00060    * All functions perform range checks if in debug mode
00061    * (NDEBUG is not defined).
00062    * Please use debug the version (default) for testing
00063    * @see examples/matrix/matrixexample.cpp
00064    *
00065    * @author Georg Martius
00066    */
00067   class Matrix : public Storeable {
00068   public:
00069     /// default constructor: zero matrix (0x0)
00070     Matrix()
00071       : m(0), n(0), buffersize(0), data(0) {};
00072     /** constucts a matrix with the given size.
00073         If _data is null then the matrix is filled with zeros.
00074         otherwise matrix will be filled with _data in a row-wise manner.
00075         In this case _data must be at least _m*_n elements long
00076     */
00077     Matrix(I _m, I _n, const D* _data=0);
00078     /** constucts a matrix with the given size and fills it with the default value
00079     */
00080     Matrix(I _m, I _n, D def);
00081     /// constucts a instance on the base of a deep copy of the given matrix
00082     Matrix (const Matrix& c);
00083     ~Matrix() { if(data) free(data); };
00084 
00085   public:
00086     //  /////////////////// Accessors ///////////////////////////////
00087     /** @return number of rows */
00088     I getM() const { return m; };
00089     /** @return number of columns */
00090     I getN() const { return n; };
00091     /// @return number number elements in the matrix (getM()*getN())
00092     I size() const { return n*m; };
00093 
00094 
00095     /** @return element at position i,j (row, column index) */
00096     inline D val(I i, I j) const {
00097       assert( i<m && j<n);
00098       return data[i*n+j];
00099     };
00100     /** @return reference to element at position i,j
00101         (can be used as left side value) */
00102     inline D& val(I i, I j) {
00103       assert( i<m && j<n);
00104       return data[i*n+j];
00105     };
00106 
00107     /** @return element at position i,j (row, column index) and 0 if out of bounds */
00108     inline D valDef0(I i, I j) const {
00109       if(i<m && j<n)
00110         return data[i*n+j];
00111       else return 0;
00112     };
00113 
00114     /** sets the size of the matrix and maybe the data if given (row-wise).
00115         If data=null then the matrix is set to zero
00116         @see toZero()
00117         @see constructor Matrix(m,n,data)
00118     */
00119     void set(I _m, I _n, const D* _data=0);
00120     /** sets the data (row-wise).
00121         @param _data if null then matrix elements are set to zero
00122         otherwise the field MUST have the length should be getM()*getN()*/
00123     void set(const D* _data);
00124     /** @return row-vector(as 1xN matrix) containing the index'th row */
00125     Matrix row(I index) const;
00126     /** @returns submatrix (as KxN matrix)
00127         containing row from startindex to endindex inclusively (K=stopindex-endindex)
00128         indices can be out of bounds, they are clipped in any case
00129     */
00130     Matrix rows(I startindex, I endindex) const;
00131     /** @returns column-vector(as Mx1 matrix) containing the index'th column */
00132     Matrix column(I index) const;
00133     /** @returns submatrix (as MxK matrix)
00134         containing column from startindex to endindex inclusively (K=endindex-startindex)
00135         indices can be out of bounds, they are clipped in any case
00136     */
00137     Matrix columns(I startindex, I endindex) const;
00138 
00139 
00140     /** stores the content of the matrix (row-wise) in the given buffer
00141         @param buffer Buffer for storing the elements (should have the length given by len)
00142         @param len Length of the provided buffer.
00143                In any case only min(len, getM()*getN()) elements are copied.
00144         @return number of actually written elements
00145      */
00146     int convertToBuffer(D* buffer, I len) const;
00147 
00148     /** @return a list of the content of the matrix (row-wise)
00149      */
00150     std::list<D> convertToList() const;
00151 
00152     /// returns a pointer to the data. UNSAFE!!!
00153     const double* unsafeGetData() const{return data;}
00154 
00155     /*       STOREABLE       */
00156     /** stores the Matrix into the given file stream (binary)
00157      */
00158     bool store(FILE* f) const;
00159 
00160     /** reads a Matrix from the given file stream (binary)
00161      */
00162     bool restore(FILE* f);
00163 
00164     /** writes the Matrix into the given file stream (ascii)
00165      */
00166     bool write(FILE* f) const;
00167 
00168     /** reads a Matrix from the given file stream (ascii)
00169      */
00170     bool read(FILE* f);
00171 
00172 
00173   public:
00174     // ////////////////////////////////////////////////////////////////////
00175     // /////////////  operations  /////////////////////////////
00176     //  (the result of the operation is not stored in one of the operands)
00177     void add(const Matrix& a, const Matrix& b); ///< addition:    this = a + b
00178     void add(const Matrix& a, const D& summand); /// add scalar to each element
00179     void sub(const Matrix& a, const Matrix& b); ///< subtraction: this = a - b
00180     void mult(const Matrix& a, const Matrix& b);///< multiplication: this = a * b
00181     void mult(const Matrix& a, const D& fac);///< scaling: this = a * fac
00182 
00183     void exp(const Matrix& a, int exponent);///< exponent, this = a^i, @see toExp
00184 
00185     /// returns true if matrix is a 0x0 matrix
00186     bool isNulltimesNull() const;
00187 
00188     /// returns true if matrix is a vector
00189     bool isVector() const;
00190 
00191     /** bytewise comparison (compares data buffer bytewise, which implies that
00192         n1*m1 == n2*m2 but not necessarily n1==n2) */
00193     bool equals(const Matrix& a) const;
00194 
00195     /** calculates the pseudoinverse, depending on the shape of the matrix
00196         the left or right pseudoinverse is used.
00197         If the matrix has more columns than rows then we use
00198         \f[A^{+} = (A^T A + \lambda \mathbb I)^{-1}A^T\f]
00199         otherwise
00200         \f[A^{+} = A^T(A A^T + \lambda \mathbb I)^{-1}\f]
00201      */
00202     Matrix pseudoInverse(const D& lambda = 1e-8) const ;
00203 
00204     /** calculates the secure inverse of a square matrix.
00205         If singular then the pseudoinverse is used.
00206      */
00207     Matrix secureInverse() const;
00208 
00209     /** returns true if all entries are normal floating point numbers,
00210         otherwise false (e.g. for nan and inf)*/
00211     bool hasNormalEntries() const;
00212 
00213 
00214     /**  maps the matrix to a new matrix
00215          with all elements mapped with the given function
00216     */
00217     Matrix map(D (*fun)(D)) const;
00218     /**  like map but with additional double parameter for the mapping function
00219          (first argument of fun is parameter, the second is the value)*/
00220     Matrix mapP(D param, D (*fun)(D, D)) const;
00221     /**  like map but with additional arbitrary parameter for the mapping function */
00222     Matrix mapP(void* param, D (*fun)(void*, D)) const;
00223 
00224     // Exotic operations ///////////
00225     /** binary map operator for matrices.
00226        The resulting matrix consists of the function values applied to the elements of a and b.
00227        In haskell this would something like: map (uncurry . fun) $ zip a b
00228     */
00229     static Matrix map2( D (*fun)(D,D), const Matrix& a, const Matrix& b);
00230 
00231     /** like map2 but with additional parameter.
00232         The first argument of fun is the parameter and the second and third
00233         comes from the matrix elements.
00234         In haskell this would something like: map (uncurry . (fun p)) $ zip a b
00235      */
00236     static Matrix map2P( D param, D (*fun)(D, D,D), const Matrix& a, const Matrix& b);
00237     /** like map2P but with arbitrary paramters (void*) instead of double
00238      */
00239     static Matrix map2P( void* param, D (*fun)(void*, D,D), const Matrix& a, const Matrix& b);
00240 
00241 
00242 
00243     /** row-wise multiplication
00244         @param factors column vector (Mx1) of factors, one for each row
00245     */
00246     Matrix multrowwise(const Matrix& factors) const;
00247     /** column-wise multiplication
00248         @param factors column vector (Mx1) of factors, one for each column
00249     */
00250     Matrix multcolwise(const Matrix& factors) const;
00251 
00252     /// optimised multiplication of Matrix with its transposed: M * M^T
00253     Matrix multMT() const;
00254     /// optimised multiplication of transpsoed of Matrix with itself: M^T * M
00255     Matrix multTM() const;
00256 
00257     /// returns the product of all elements (\f$ \Pi_{ij} m_{ij} \f$)
00258     D elementProduct() const;
00259     /// returns the sum of all elements (\f$ \sum_{ij} m_{ij} \f$)
00260     D elementSum() const;
00261 
00262     /** returns the sum of all squares of all elements (\f$ \sum_{ij} m_{ij}^2 \f$)
00263         this is also known as the square of the Frobenius norm.
00264      */
00265     D norm_sqr() const;
00266 
00267     /// returns a matrix that consists of this matrix above A (number of rows is getM + a.getM())
00268     Matrix above(const Matrix& a) const ;
00269     /// returns a matrix that consists of this left beside A  (number of columns is getN + a.getN())
00270     Matrix beside(const Matrix& a) const ;
00271 
00272   public:   // normal binary Operators
00273     /// deep copy
00274     Matrix& operator = (const Matrix& c) { copy(c); return *this; }
00275     /// sum of two matrices
00276     Matrix operator +  (const Matrix& sum) const;
00277     //    Matrix operator +  (const D& sum) const; /// new operator (guettler)
00278     /// difference of two matrices
00279     Matrix operator -  (const Matrix& sum) const;
00280     /** matrix product*/
00281     Matrix operator *  (const Matrix& fac) const;
00282     /** product with scalar (D) (only right side) */
00283     Matrix operator *  (const D& fac) const;
00284     /** special matrix potence:
00285         @param exponent -1 -> inverse;
00286                        0 -> Identity Matrix;
00287                     1 -> itself;
00288                     T -> Transpose
00289     */
00290     Matrix operator ^ (int exponent) const;
00291     /// row-wise multiplication
00292     Matrix operator & (const Matrix& b) const;
00293     /// combined assigment operator (higher performance)
00294     Matrix& operator += (const Matrix& c) {toSum(c);   return *this; }
00295     /// combined assigment operator (higher performance)
00296     Matrix& operator -= (const Matrix& c) {toDiff(c);  return *this; }
00297     /// combined assigment operator (higher performance)
00298     Matrix& operator *= (const Matrix& c) {
00299       Matrix result;
00300       result.mult(*this, c);
00301       this->copy(result);
00302       return *this;
00303     }
00304     /// combined assigment operator (higher performance)
00305     Matrix& operator *= (const D& fac) {toMult(fac); return *this; }
00306     /// combined assigment operator (higher performance)
00307     Matrix& operator &= (const Matrix& c) {toMultrowwise(c); return *this; }
00308 
00309 #ifndef AVR
00310     /// comparison operator (compares elements with tolerance distance of COMPARE_EPS)
00311     bool operator == (const Matrix& c) const;
00312     /** printing operator:
00313         output format: mxn (\n row0\n..rown \n) where rowX is tab seperated list of values
00314     */
00315     friend std::ostream& operator<<(std::ostream& , const Matrix&);
00316 #endif
00317 
00318   public:
00319     // /////////////////// inplace Operators ///////////////////////////////
00320     /** performs a deep copy of the given matrix */
00321     void copy(const Matrix& c){ // Deep copy
00322       m=c.m; n=c.n;
00323       allocate();
00324       memcpy(data,c.data,m*n*sizeof(D));
00325     }
00326 
00327     Matrix& toTranspose();  ///< inplace transpose
00328     Matrix& toZero();       ///< inplace converts matrix to zero matrix
00329     Matrix& toId();         ///< inplace converts matrix to identity (use ^0 to get a copy version of it)
00330     /// inplace addition: this = this + a
00331     Matrix& toSum(const Matrix& a);
00332     /// inplace addition: this = this + a, where a is a scalar
00333     Matrix& toSum(const D& sum);
00334 
00335     /// inplace subtraction: this = this - a
00336     Matrix& toDiff(const Matrix& a);
00337 
00338     /// inplace multiplication: this = this * a
00339     Matrix& toMult(const Matrix& a);
00340     /// inplace multiplication with scalar: this = this*fac
00341     Matrix& toMult(const D& fac);
00342 
00343     /** special inplace matrix power:
00344         @param exponent -1 -> inverse; (matrix MUST be SQUARE and NONZERO)
00345                     0 -> Identity Matrix;
00346                     1 -> itself;
00347                     n -> n-th power;
00348                     T -> Transpose
00349     */
00350     Matrix& toExp(int exponent);
00351     /**  inplace mapping of matrix elements (element-wise application) */
00352     Matrix& toMap(D (*fun)(D));
00353     /**  like toMap, but with an extra double parameter for the mapping function. */
00354     Matrix& toMapP(D param, D (*fun)(D, D));
00355     /**  like toMap, but with an extra arbitrary parameter for the mapping function. */
00356     Matrix& toMapP(void* param, D (*fun)(void*, D));
00357 
00358     /**  like toMap, but with using 2 matrices */
00359     Matrix& toMap2(D (*fun)(D,D), const Matrix& b);
00360 
00361     /**  like toMap2, but with additional parameter */
00362     Matrix& toMap2P( D param, D (*fun)(D, D,D), const Matrix& b);
00363     /**  like toMap2P, but with arbitrary parameter */
00364     Matrix& toMap2P( void* param, D (*fun)(void*, D,D), const Matrix& b);
00365 
00366     // Exotic operations
00367     /** Inplace row-wise multiplication
00368         @param factors column vector of factors, one for each row
00369     */
00370     Matrix& toMultrowwise(const Matrix& factors);
00371     /** Inplace column-wise multiplication
00372         @param factors column vector of factors, one for each column
00373     */
00374     Matrix& toMultcolwise(const Matrix& factors);
00375 
00376     /// sets the matrix a below this matrix
00377     Matrix& toAbove(const Matrix& a);
00378     /// sets the matrix a right beside this matrix
00379     Matrix& toBeside(const Matrix& a);
00380 
00381     /// sorts the matrix (rowwise)
00382     Matrix& toSort();
00383 
00384     /** reshapes the matrix without destroying the data.
00385         Remember: The data is stored rowwise.
00386 
00387         Only shrinking is allowed i.e. m*n must be lower or equal to getM()*getN()
00388     */
00389     Matrix& reshape(I m, I n);
00390 
00391     /// adds the given value to the diagonal
00392     Matrix& pluslambdaI(double lambda = 1e-8);
00393 
00394     /** adds one or more rows to the existing matrix and fills it with the given data
00395      *
00396      * same as toAbove(Matrix(numberRows,getN(),data))
00397      * @param numberRows number of rows to add (this extends m)
00398      * @param _data data to add
00399      * @return the address of the matrix itself
00400      */
00401     Matrix& addRows(I numberRows, const D* _data=0);
00402 
00403     /**
00404      * same as toAbove(dataMatrix)
00405      * @param numberRows number of rows to add (unused)
00406      * @param dataMatrix matrix which contains the data of the new rows
00407      * @return the address of the matrix itself
00408      */
00409     Matrix& addRows(I numberRows, const Matrix& dataMatrix);
00410 
00411     /** adds one or more columns to the existing matrix
00412      * same as toBeside(Matrix(getM, numberColumns, _data))
00413      * @see toBeside()
00414      * @param numberColumns number of columns to add (this extends n)
00415      * @param _data data to add
00416      * @return the address of the matrix itself
00417      */
00418      Matrix& addColumns(I numberColumns, const D* _data=0);
00419 
00420     /**
00421      * same as toBeside(dataMatrix)
00422      * @see toBeside()
00423      * @param numberColumns number of columns to add (unused)
00424      * @param dataMatrix matrix which contains the data of the new rows
00425      * @return the address of the matrix itself
00426      */
00427     Matrix& addColumns(I numberColumns, const Matrix& dataMatrix);
00428 
00429 
00430     /** removes one or more rows of the existing matrix,
00431         same as reshape(getM()-numberRows, getN());
00432      * @param numberRows number of rows to remove (this reduces m)
00433      * @return the address of the matrix itself
00434      */
00435     Matrix& removeRows(I numberRows);
00436 
00437     /** removes one or more columns of the existing matrix
00438      * resets the size of the matrix and deletes the appropiate data.
00439      * @param numberColumns number of columns to remove (this reduces n)
00440      * @return the address of the matrix itself
00441      */
00442     Matrix& removeColumns(I numberColumns);
00443 
00444   private:
00445     // NOTE: buffersize determines available memory storage.
00446     // m and n define the actual size
00447     I m, n;
00448     I buffersize;  // max number if elements
00449     D* data;      // where the data contents of the matrix are stored
00450 
00451 
00452   private: // internals
00453     void allocate();  //internal allocation
00454     /*inplace matrix invertation:
00455         Matrix must be SQARE, in addition, all DIAGONAL ELEMENTS MUST BE NONZERO
00456         (positive definite)
00457     */
00458 
00459 #ifndef AVR
00460     void invertnonzero();
00461     void invert3x3();
00462 #endif
00463     void invert2x2();
00464   };
00465 
00466 } // namespace matrix
00467 #endif
Generated on Thu Jun 28 14:45:36 2012 for Robot Simulator of the Robotics Group for Self-Organization of Control by  doxygen 1.6.3