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 // $Log: matrix.h,v $ 00010 // Revision 1.24 2008/06/18 13:46:20 martius 00011 // beside and toBeside added 00012 // addColumns and addRows is now based on toAbove and toBeside 00013 // bug fix in removeColumns 00014 // 00015 // Revision 1.23 2008/05/30 11:58:08 martius 00016 // equals method and cmath 00017 // 00018 // Revision 1.22 2008/05/07 16:45:52 martius 00019 // code cosmetics and documentation 00020 // 00021 // Revision 1.21 2008/05/02 17:20:04 martius 00022 // *** empty log message *** 00023 // 00024 // Revision 1.20 2008/04/30 14:54:14 guettler 00025 // -indextype of matrices is now unsigned int (bigger matrices than 00026 // 256x256 can be used now, if not AVR defined) 00027 // -code cleaned up 00028 // 00029 // Revision 1.19 2008/04/29 11:04:44 guettler 00030 // forgot to deactivate += operator 00031 // 00032 // Revision 1.18 2008/04/29 11:01:32 guettler 00033 // -added toMap2 and toMap2P 00034 // -removed operator + for scalar (use add or toSum instead) 00035 // 00036 // Revision 1.17 2008/04/28 15:24:14 guettler 00037 // -added deleteRows and deleteColumns 00038 // -fixed memory leak in addColumns 00039 // 00040 // Revision 1.16 2008/04/28 10:33:05 guettler 00041 // -added operator + and += for adding a scalar to each element of the matrix 00042 // -added add function and toSum for adding a scalar to each element 00043 // -added addRows and addColumns for adding new rows or colums to the matrix 00044 // 00045 // Revision 1.15 2008/03/01 01:33:30 martius 00046 // size added 00047 // 00048 // Revision 1.14 2007/08/22 08:28:07 martius 00049 // contrains for reshape relaxed 00050 // 00051 // Revision 1.13 2007/06/21 16:29:18 martius 00052 // added map2P 00053 // map2 into cpp 00054 // 00055 // Revision 1.12 2007/06/08 15:50:29 martius 00056 // added unsafeGetData 00057 // 00058 // Revision 1.11 2007/05/22 13:52:36 martius 00059 // inplace operators return *this which makes them more useable for temporary matrices 00060 // 00061 // Revision 1.10 2007/04/03 09:58:20 martius 00062 // memory management done with free and malloc 00063 // 00064 // Revision 1.9 2007/04/03 07:13:32 der 00065 // plus lambdaI 00066 // 00067 // Revision 1.8 2007/02/05 12:31:21 martius 00068 // reshape 00069 // 00070 // Revision 1.7 2006/11/29 16:22:43 martius 00071 // name is a variable of configurable and is used as such 00072 // 00073 // Revision 1.6 2006/08/04 15:16:13 martius 00074 // documentation 00075 // 00076 // Revision 1.5 2006/07/20 17:14:35 martius 00077 // removed std namespace from matrix.h 00078 // storable interface 00079 // abstract model and invertablemodel as superclasses for networks 00080 // 00081 // Revision 1.4 2006/07/19 09:26:37 martius 00082 // namespace std removed from header 00083 // store and restore 00084 // read and write 00085 // columns accessor 00086 // 00087 // Revision 1.3 2006/07/18 14:13:09 martius 00088 // crucial bug fixing in *= operator! 00089 // 00090 // Revision 1.2 2006/07/14 12:24:01 martius 00091 // selforg becomes HEAD 00092 // 00093 // Revision 1.1.2.2 2006/07/14 08:56:53 der 00094 // New function NullTimesNull 00095 // 00096 // Revision 1.1.2.1 2006/07/10 12:01:02 martius 00097 // Matrixlib moved to selforg 00098 // 00099 // Revision 1.20.6.4 2006/03/30 23:08:53 martius 00100 // comments 00101 // 00102 // Revision 1.20.6.3 2006/03/30 12:34:45 martius 00103 // documentation updated 00104 // 00105 // Revision 1.20.6.2 2006/03/29 15:12:46 martius 00106 // column accessor function added 00107 // 00108 // Revision 1.20.6.1 2005/12/06 17:38:10 martius 00109 // *** empty log message *** 00110 // 00111 // Revision 1.20 2005/10/21 11:58:25 martius 00112 // map2 (similar to map but for 2 matrices) 00113 // changed naming of functions to be more consistent. 00114 // Functions with "to" in front indicate the change of this. (Still not consistent with add, mult ...) 00115 // 00116 // Revision 1.19 2005/10/06 17:10:06 martius 00117 // convertToList 00118 // above and toAbove 00119 // 00120 // Revision 1.18 2005/09/21 08:43:01 martius 00121 // convertToBuffer is const 00122 // 00123 // Revision 1.17 2005/08/06 20:47:36 martius 00124 // Commented 00125 // 00126 // Revision 1.16 2005/07/21 15:13:36 martius 00127 // mapP addid (mapping with additional parameter) 00128 // 00129 // Revision 1.15 2005/06/21 15:35:21 martius 00130 // hide invert3x3 and invert_nonzero for AVR to minimize binary size 00131 // 00132 // Revision 1.14 2005/06/17 15:19:03 martius 00133 // version workes with avr 00134 // 00135 // Revision 1.13 2005/06/10 08:23:15 martius 00136 // mult???wise are copy operations now! 00137 // toMult???wise are the inplace variant. 00138 // 00139 // Revision 1.11 2005/06/09 11:52:03 martius 00140 // multMT (M * M^T) and multTM (M^T * M) 00141 // 00142 // Revision 1.10 2005/06/02 22:48:54 martius 00143 // copy is inline and works correct now 00144 // 00145 // Revision 1.9 2005/06/02 08:48:31 martius 00146 // mult_row/column_wise 00147 // convertToBuffer 00148 // 00149 // Revision 1.8 2005/05/30 22:40:56 martius 00150 // map becomes toMap and the new map returns a new matrix 00151 // exp becomes toExp 00152 // 00153 // Revision 1.7 2005/05/30 21:46:54 martius 00154 // *** empty log message *** 00155 // 00156 // Revision 1.6 2005/05/30 17:21:26 martius 00157 // added zero 00158 // set() and constructor(m,n,0) initialise with zero 00159 // id returns void (more consistent) 00160 // 00161 // Revision 1.5 2005/05/30 16:42:56 martius 00162 // map function included (component-wise function application) 00163 // 00164 // Revision 1.4 2005/05/30 11:28:09 martius 00165 // marked "row" as untested 00166 // 00167 // Revision 1.3 2005/05/30 10:14:54 martius 00168 // 3x3 explicit matrix inversion 00169 // 00170 // Revision 1.2 2005/05/30 09:45:46 martius 00171 // Working. Interface not tested in pratice 00172 // 00173 // Revision 1.1 2005/05/29 22:43:08 martius 00174 // proper Makefile with dependencies and tag generator 00175 // 00176 /***************************************************************************/ 00177 00178 #ifndef MATRIX_H 00179 #define MATRIX_H 00180 00181 #include <string.h> 00182 #include <assert.h> 00183 #include <list> 00184 00185 #ifndef AVR 00186 #include <iostream> 00187 #endif 00188 00189 #include "storeable.h" 00190 00191 // TODO: add doxygen section 00192 00193 /** 00194 * namespace for matrix library 00195 *@author Georg Martius 00196 */ 00197 namespace matrix{ 00198 00199 /// integer constant for use with exp function and (^) operator to transpose the matrix 00200 extern const int T; 00201 00202 #ifndef AVR 00203 /// type for matrix indices 00204 typedef unsigned int I; 00205 /// type for matrix elements 00206 typedef double D; 00207 #else 00208 /// type for matrix indices, if AVR 00209 /// NOTE: You cannot use matrices bigger than m*n>255 if AVR! 00210 typedef unsigned short I; 00211 /// type for matrix elements 00212 typedef float D; 00213 #endif 00214 00215 00216 #define D_Zero 0 00217 #define D_One 1 00218 /** Matrix type. Type D is datatype of matrix elements, 00219 * which is fixed to double. 00220 * Type I is the indextype of matrix elements, 00221 * which is fixed to unsigned int, if AVR is not defined. 00222 * There are basicly two different types of operation: 00223 * Inplace operations and copy operations. 00224 * Please use the latter ones unless you know what you are doing. 00225 * Just in case of critical performance optimisation use the inplace 00226 * operations. 00227 * The most convinient way is to use the overloaded operators 00228 * (like + * ...). 00229 * All constructed matrices are initialised with zero elements 00230 * (unless data is given). 00231 * All functions perform range checks if in debug mode 00232 * (NDEBUG is not defined). 00233 * Please use debug the version (default) for testing 00234 * @see examples/matrix/matrixexample.cpp 00235 * 00236 * @author Georg Martius 00237 */ 00238 class Matrix : public Storeable { 00239 public: 00240 /// default constructor: zero matrix (0x0) 00241 Matrix() 00242 : m(0), n(0), buffersize(0), data(0) {}; 00243 /** constucts a matrix with the given size. 00244 If _data is null then the matrix is filled with zeros. 00245 otherwise matrix will be filled with _data in a row-wise manner. 00246 In this case _data must be at least _m*_n elements long 00247 */ 00248 Matrix(I _m, I _n, const D* _data=0); 00249 /** constucts a matrix with the given size and fills it with the default value 00250 */ 00251 Matrix(I _m, I _n, D def); 00252 /// constucts a instance on the base of a deep copy of the given matrix 00253 Matrix (const Matrix& c); 00254 ~Matrix() { if(data) free(data); }; 00255 00256 public: 00257 // /////////////////// Accessors /////////////////////////////// 00258 /** @return number of rows */ 00259 I getM() const { return m; }; 00260 /** @return number of columns */ 00261 I getN() const { return n; }; 00262 /// @return number number elements in the matrix (getM()*getN()) 00263 I size() const { return n*m; }; 00264 00265 00266 /** @return element at position i,j (row, column index) */ 00267 inline D val(I i, I j) const { 00268 assert( i<m && j<n); 00269 return data[i*n+j]; 00270 }; 00271 /** @return reference to element at position i,j 00272 (can be used as left side value) */ 00273 inline D& val(I i, I j) { 00274 assert( i<m && j<n); 00275 return data[i*n+j]; 00276 }; 00277 00278 /** @return element at position i,j (row, column index) and 0 if out of bounds */ 00279 inline D valDef0(I i, I j) const { 00280 if(0<=i && i<m && 0<=j && j<n) 00281 return data[i*n+j]; 00282 else return 0; 00283 }; 00284 00285 /** sets the size of the matrix and maybe the data if given (row-wise). 00286 If data=null then the matrix is set to zero 00287 @see toZero() 00288 @see constructor Matrix(m,n,data) 00289 */ 00290 void set(I _m, I _n, const D* _data=0); 00291 /** sets the data (row-wise). 00292 @param _data if null then matrix elements are set to zero 00293 otherwise the field MUST have the length should be getM()*getN()*/ 00294 void set(const D* _data); 00295 /** @return row-vector(as 1xN matrix) containing the index'th row */ 00296 Matrix row(I index) const; 00297 /** @returns submatrix (as KxN matrix) 00298 containing row from startindex to endindex inclusively (K=stopindex-endindex) 00299 indices can be out of bounds, they are clipped in any case 00300 */ 00301 Matrix rows(I startindex, I endindex) const; 00302 /** @returns column-vector(as Nx1 matrix) containing the index'th column */ 00303 Matrix column(I index) const; 00304 /** @returns submatrix (as NxK matrix) 00305 containing column from startindex to endindex inclusively (K=endindex-startindex) 00306 indices can be out of bounds, they are clipped in any case 00307 */ 00308 Matrix columns(I startindex, I endindex) const; 00309 00310 00311 /** stores the content of the matrix (row-wise) in the given buffer 00312 @param buffer Buffer for storing the elements (should have the length given by len) 00313 @param len Length of the provided buffer. 00314 In any case only min(len, getM()*getN()) elements are copied. 00315 @return number of actually written elements 00316 */ 00317 int convertToBuffer(D* buffer, I len) const; 00318 00319 /** @return a list of the content of the matrix (row-wise) 00320 */ 00321 std::list<D> convertToList() const; 00322 00323 /// returns a pointer to the data. UNSAFE!!! 00324 const double* unsafeGetData() const{return data;} 00325 00326 /* STOREABLE */ 00327 /** stores the Matrix into the given file stream (binary) 00328 */ 00329 bool store(FILE* f) const; 00330 00331 /** reads a Matrix from the given file stream (binary) 00332 */ 00333 bool restore(FILE* f); 00334 00335 /** writes the Matrix into the given file stream (ascii) 00336 */ 00337 bool write(FILE* f) const; 00338 00339 /** reads a Matrix from the given file stream (ascii) 00340 */ 00341 bool read(FILE* f); 00342 00343 00344 public: 00345 // //////////////////////////////////////////////////////////////////// 00346 // ///////////// operations ///////////////////////////// 00347 // (the result of the operation is not stored in one of the operands) 00348 void add(const Matrix& a, const Matrix& b); ///< addition: this = a + b 00349 void add(const Matrix& a, const D& summand); /// add scalar to each element 00350 void sub(const Matrix& a, const Matrix& b); ///< subtraction: this = a - b 00351 void mult(const Matrix& a, const Matrix& b);///< multiplication: this = a * b 00352 void mult(const Matrix& a, const D& fac);///< scaling: this = a * fac 00353 00354 /// returns true if matrix is a 0x0 matrix 00355 bool isNulltimesNull() const; 00356 00357 /** bytewise comparison (compares data buffer bytewise, which implies that 00358 n1*m1 == n2*m2 but not necessarily n1==n2) */ 00359 bool equals(const Matrix& a) const; 00360 00361 00362 /** maps the matrix to a new matrix 00363 with all elements mapped with the given function 00364 */ 00365 Matrix map(D (*fun)(D)) const; 00366 /** like map but with additional parameter for the mapping function 00367 */ 00368 Matrix mapP(void* param, D (*fun)(void*, D)) const; 00369 00370 // Exotic operations /////////// 00371 /** binary map operator for matrices. 00372 The resulting matrix consists of the function values applied to the elements of a and b. 00373 In haskell this would something like: map (uncurry . fun) $ zip a b 00374 */ 00375 static Matrix map2( D (*fun)(D,D), const Matrix& a, const Matrix& b); 00376 00377 /** binary map operator for matrices with parameter. 00378 The resulting matrix consists of the function values applied to the elements of a and b. 00379 In haskell this would something like: map (uncurry . (fun p)) $ zip a b 00380 */ 00381 static Matrix map2P( void* param, D (*fun)(void*, D,D), const Matrix& a, const Matrix& b); 00382 00383 /** row-wise multiplication 00384 @param factors column vector (Mx1) of factors, one for each row 00385 */ 00386 Matrix multrowwise(const Matrix& factors) const; 00387 /** column-wise multiplication 00388 @param factors column vector (Mx1) of factors, one for each column 00389 */ 00390 Matrix multcolwise(const Matrix& factors) const; 00391 00392 /// optimised multiplication of Matrix with its transposed: M * M^T 00393 Matrix multMT() const; 00394 /// optimised multiplication of transpsoed of Matrix with itself: M^T * M 00395 Matrix multTM() const; 00396 00397 /// returns the product of all elements (\f$ \Pi_{ij} m_{ij} \f$) 00398 D elementProduct() const; 00399 /// returns the sum of all elements (\f$ \sum_{ij} m_{ij} \f$) 00400 D elementSum() const; 00401 00402 /// returns a matrix that consists of this matrix above A (number of rows is getM + a.getM()) 00403 Matrix above(const Matrix& a) const ; 00404 /// returns a matrix that consists of this left beside A (number of columns is getN + a.getN()) 00405 Matrix beside(const Matrix& a) const ; 00406 00407 public: /// normal binary Operators 00408 /// deep copy 00409 Matrix& operator = (const Matrix& c) { copy(c); return *this; } 00410 Matrix operator + (const Matrix& sum) const; 00411 // Matrix operator + (const D& sum) const; /// new operator (guettler) 00412 Matrix operator - (const Matrix& sum) const; 00413 /** matrix product*/ 00414 Matrix operator * (const Matrix& fac) const; 00415 /** product with scalar (D) */ 00416 Matrix operator * (const D& fac) const; 00417 /** special matrix potence: 00418 @param exponent -1 -> inverse; 00419 0 -> Identity Matrix; 00420 1 -> itself; 00421 T -> Transpose 00422 */ 00423 Matrix operator ^ (int exponent) const; 00424 /// performant combined assigment operators 00425 Matrix& operator += (const Matrix& c) {toSum(c); return *this; } 00426 Matrix& operator -= (const Matrix& c) {toDiff(c); return *this; } 00427 Matrix& operator *= (const Matrix& c) { 00428 Matrix result; 00429 result.mult(*this, c); 00430 this->copy(result); 00431 return *this; 00432 } 00433 Matrix& operator *= (const D& fac) {toMult(fac); return *this; } 00434 00435 #ifndef AVR 00436 /// comparison operator (compares elements with tolerance distance of COMPARE_EPS) 00437 bool operator == (const Matrix& c) const; 00438 /** printing operator: 00439 output format: mxn (\n row0\n..rown \n) where rowX is tab seperated list of values 00440 */ 00441 friend std::ostream& operator<<(std::ostream& , const Matrix&); 00442 #endif 00443 00444 public: 00445 // /////////////////// inplace Operators /////////////////////////////// 00446 /** performs a deep copy of the given matrix */ 00447 void copy(const Matrix& c){ // Deep copy 00448 m=c.m; n=c.n; 00449 allocate(); 00450 memcpy(data,c.data,m*n*sizeof(D)); 00451 } 00452 00453 Matrix& toTranspose(); ///< inplace transpose 00454 Matrix& toZero(); ///< inplace converts matrix to zero matrix 00455 Matrix& toId(); ///< inplace converts matrix to identity (use ^0 to get a copy version of it) 00456 /// inplace addition: this = this + a 00457 Matrix& toSum(const Matrix& a) { 00458 assert(a.m==m && a.n==n); 00459 for(I i=0; i<m*n; i++){ 00460 data[i]+=a.data[i]; 00461 } 00462 return *this; 00463 } 00464 00465 /// inplace addition: this = this + a, where a is a scalar 00466 Matrix& toSum(const D& sum) { 00467 for(I i=0; i<m*n; i++){ 00468 data[i]+=sum; 00469 } 00470 return *this; 00471 } 00472 00473 /// inplace subtraction: this = this - a 00474 Matrix& toDiff(const Matrix& a){ 00475 assert(a.m==m && a.n==n); 00476 for(I i=0; i<m*n; i++){ 00477 data[i]-=a.data[i]; 00478 } 00479 return *this; 00480 } 00481 00482 /// inplace multiplication with scalar: this = this*fac 00483 Matrix& toMult(const D& fac); 00484 00485 /** special inplace matrix potence: 00486 @param exponent -1 -> inverse; (matrix MUST be SQUARE and NONZERO) 00487 0 -> Identity Matrix; 00488 1 -> itself; 00489 T -> Transpose 00490 */ 00491 Matrix& toExp(int exponent); 00492 /** inplace mapping of matrix elements (element-wise application) */ 00493 Matrix& toMap(D (*fun)(D)); 00494 /** like toMap, but with an extra parameter for the mapping function. */ 00495 Matrix& toMapP(void* param, D (*fun)(void*, D)); 00496 00497 /** like toMap, but with 2 arguments for the mapping function. */ 00498 Matrix& toMap2(D (*fun)(D,D), const Matrix& b); 00499 00500 Matrix& toMap2P( void* param, D (*fun)(void*, D,D), const Matrix& b); 00501 00502 // Exotic operations 00503 /** Inplace row-wise multiplication 00504 @param factors column vector of factors, one for each row 00505 */ 00506 Matrix& toMultrowwise(const Matrix& factors); 00507 /** Inplace column-wise multiplication 00508 @param factors column vector of factors, one for each column 00509 */ 00510 Matrix& toMultcolwise(const Matrix& factors); 00511 00512 /// sets the matrix a below this matrix 00513 Matrix& toAbove(const Matrix& a); 00514 /// sets the matrix a right beside this matrix 00515 Matrix& toBeside(const Matrix& a); 00516 00517 /// sorts the matrix (rowwise) 00518 Matrix& toSort(); 00519 00520 /** reshapes the matrix without destroying the data. 00521 Remember: The data is stored rowwise. 00522 00523 Only shrinking is allowed i.e. m*n must be lower or equal to getM()*getN() 00524 */ 00525 Matrix& reshape(I m, I n); 00526 00527 /// adds the given value to the diagonal 00528 Matrix& pluslambdaI(double lambda); 00529 00530 /** adds one or more rows to the existing matrix and fills it with the given data 00531 * 00532 * same as toAbove(Matrix(numberRows,getN(),data)) 00533 * @param numberRows number of rows to add (this extends m) 00534 * @param _data data to add 00535 * @return the address of the matrix itself 00536 */ 00537 Matrix& addRows(I numberRows, const D* _data=0); 00538 00539 /** 00540 * same as toAbove(dataMatrix) 00541 * @param numberRows number of rows to add (unused) 00542 * @param dataMatrix matrix which contains the data of the new rows 00543 * @return the address of the matrix itself 00544 */ 00545 Matrix& addRows(I numberRows, const Matrix& dataMatrix); 00546 00547 /** adds one or more columns to the existing matrix 00548 * same as toBeside(Matrix(getM, numberColumns, _data)) 00549 * @see toBeside() 00550 * @param numberColumns number of columns to add (this extends n) 00551 * @param _data data to add 00552 * @return the address of the matrix itself 00553 */ 00554 Matrix& addColumns(I numberColumns, const D* _data=0); 00555 00556 /** 00557 * same as toBeside(dataMatrix) 00558 * @see toBeside() 00559 * @param numberColumns number of columns to add (unused) 00560 * @param dataMatrix matrix which contains the data of the new rows 00561 * @return the address of the matrix itself 00562 */ 00563 Matrix& addColumns(I numberColumns, const Matrix& dataMatrix); 00564 00565 00566 /** removes one or more rows of the existing matrix, 00567 same as reshape(getM()-numberRows, getN()); 00568 * @param numberRows number of rows to remove (this reduces m) 00569 * @return the address of the matrix itself 00570 */ 00571 Matrix& removeRows(I numberRows); 00572 00573 /** removes one or more columns of the existing matrix 00574 * resets the size of the matrix and deletes the appropiate data. 00575 * @param numberColumns number of columns to remove (this reduces n) 00576 * @return the address of the matrix itself 00577 */ 00578 Matrix& removeColumns(I numberColumns); 00579 00580 private: 00581 // NOTE: buffersize determines available memory storage. 00582 // m and n define the actual size 00583 I m, n; 00584 I buffersize; // max number if elements 00585 D* data; // where the data contents of the matrix are stored 00586 00587 00588 private: // internals 00589 void allocate(); //internal allocation 00590 /*inplace matrix invertation: 00591 Matrix must be SQARE, in addition, all DIAGONAL ELEMENTS MUST BE NONZERO 00592 (positive definite) 00593 */ 00594 00595 #ifndef AVR 00596 void invertnonzero(); 00597 void invert3x3(); 00598 #endif 00599 void invert2x2(); 00600 }; 00601 00602 } // namespace matrix 00603 #endif