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.6 2006/08/04 15:16:13 martius 00011 // documentation 00012 // 00013 // Revision 1.5 2006/07/20 17:14:35 martius 00014 // removed std namespace from matrix.h 00015 // storable interface 00016 // abstract model and invertablemodel as superclasses for networks 00017 // 00018 // Revision 1.4 2006/07/19 09:26:37 martius 00019 // namespace std removed from header 00020 // store and restore 00021 // read and write 00022 // columns accessor 00023 // 00024 // Revision 1.3 2006/07/18 14:13:09 martius 00025 // crucial bug fixing in *= operator! 00026 // 00027 // Revision 1.2 2006/07/14 12:24:01 martius 00028 // selforg becomes HEAD 00029 // 00030 // Revision 1.1.2.2 2006/07/14 08:56:53 der 00031 // New function NullTimesNull 00032 // 00033 // Revision 1.1.2.1 2006/07/10 12:01:02 martius 00034 // Matrixlib moved to selforg 00035 // 00036 // Revision 1.20.6.4 2006/03/30 23:08:53 martius 00037 // comments 00038 // 00039 // Revision 1.20.6.3 2006/03/30 12:34:45 martius 00040 // documentation updated 00041 // 00042 // Revision 1.20.6.2 2006/03/29 15:12:46 martius 00043 // column accessor function added 00044 // 00045 // Revision 1.20.6.1 2005/12/06 17:38:10 martius 00046 // *** empty log message *** 00047 // 00048 // Revision 1.20 2005/10/21 11:58:25 martius 00049 // map2 (similar to map but for 2 matrices) 00050 // changed naming of functions to be more consistent. 00051 // Functions with "to" in front indicate the change of this. (Still not consistent with add, mult ...) 00052 // 00053 // Revision 1.19 2005/10/06 17:10:06 martius 00054 // convertToList 00055 // above and toAbove 00056 // 00057 // Revision 1.18 2005/09/21 08:43:01 martius 00058 // convertToBuffer is const 00059 // 00060 // Revision 1.17 2005/08/06 20:47:36 martius 00061 // Commented 00062 // 00063 // Revision 1.16 2005/07/21 15:13:36 martius 00064 // mapP addid (mapping with additional parameter) 00065 // 00066 // Revision 1.15 2005/06/21 15:35:21 martius 00067 // hide invert3x3 and invert_nonzero for AVR to minimize binary size 00068 // 00069 // Revision 1.14 2005/06/17 15:19:03 martius 00070 // version workes with avr 00071 // 00072 // Revision 1.13 2005/06/10 08:23:15 martius 00073 // mult???wise are copy operations now! 00074 // toMult???wise are the inplace variant. 00075 // 00076 // Revision 1.11 2005/06/09 11:52:03 martius 00077 // multMT (M * M^T) and multTM (M^T * M) 00078 // 00079 // Revision 1.10 2005/06/02 22:48:54 martius 00080 // copy is inline and works correct now 00081 // 00082 // Revision 1.9 2005/06/02 08:48:31 martius 00083 // mult_row/column_wise 00084 // convertToBuffer 00085 // 00086 // Revision 1.8 2005/05/30 22:40:56 martius 00087 // map becomes toMap and the new map returns a new matrix 00088 // exp becomes toExp 00089 // 00090 // Revision 1.7 2005/05/30 21:46:54 martius 00091 // *** empty log message *** 00092 // 00093 // Revision 1.6 2005/05/30 17:21:26 martius 00094 // added zero 00095 // set() and constructor(m,n,0) initialise with zero 00096 // id returns void (more consistent) 00097 // 00098 // Revision 1.5 2005/05/30 16:42:56 martius 00099 // map function included (component-wise function application) 00100 // 00101 // Revision 1.4 2005/05/30 11:28:09 martius 00102 // marked "row" as untested 00103 // 00104 // Revision 1.3 2005/05/30 10:14:54 martius 00105 // 3x3 explicit matrix inversion 00106 // 00107 // Revision 1.2 2005/05/30 09:45:46 martius 00108 // Working. Interface not tested in pratice 00109 // 00110 // Revision 1.1 2005/05/29 22:43:08 martius 00111 // proper Makefile with dependencies and tag generator 00112 // 00113 /***************************************************************************/ 00114 00115 #ifndef MATRIX_H 00116 #define MATRIX_H 00117 00118 #include <string.h> 00119 #include <assert.h> 00120 #include <list> 00121 00122 #ifndef AVR 00123 #include <iostream> 00124 #endif 00125 00126 #include "storeable.h" 00127 00128 // TODO: add doxygen section 00129 00130 /** 00131 * namespace for matrix library 00132 *@author Georg Martius 00133 */ 00134 namespace matrix{ 00135 00136 /// integer constant for use with exp function and (^) operator to transpose the matrix 00137 extern const int T; 00138 00139 /// type for matrix elements 00140 typedef double D; 00141 #define D_Zero 0 00142 #define D_One 1 00143 /** Matrix type. Type D is datatype of matrix elements, which is fixed to double. 00144 There are basicly two different types of operation: 00145 Inplace operations and copy operations. 00146 Please use the latter ones unless you know what you are doing. 00147 Just in case of critical performance optimisation use the inplace operations. 00148 The most convinient way is to use the overloaded operators (like + * ...). 00149 All constructed matrices are initialised with zero elements (unless data is given). 00150 All functions perform range checks if in debug mode (NDEBUG is not defined). 00151 Please use -lmatrix_debug for testing. 00152 @author Georg Martius 00153 */ 00154 class Matrix : public Storeable { 00155 public: 00156 /// default constructor: zero matrix (0x0) 00157 Matrix() 00158 : m(0), n(0), buffersize(0), data(0) {}; 00159 /** constucts a matrix with the given size. 00160 If _data is null then the matrix is filled with zeros. 00161 otherwise matrix will be filled with _data in a row-wise manner. 00162 In this case _data must be at least _m*_n elements long 00163 */ 00164 Matrix(unsigned short _m, unsigned short _n, const D* _data=0); 00165 /// constucts a instance on the base of a deep copy of the given matrix 00166 Matrix (const Matrix& c); 00167 ~Matrix() { if(data) delete[] data; }; 00168 00169 public: 00170 // /////////////////// Accessors /////////////////////////////// 00171 /** @return number of rows */ 00172 unsigned short getM() const { return m; }; 00173 /** @return number of columns */ 00174 unsigned short getN() const { return n; }; 00175 /** @return element at position i,j (row, column index) */ 00176 D val(unsigned short i, unsigned short j) const { 00177 assert( i<m && j<n); 00178 return data[i*n+j]; 00179 }; 00180 /** @return reference to element at position i,j 00181 (can be used as left side value) */ 00182 D& val(unsigned short i, unsigned short j) { 00183 assert( i<m && j<n); 00184 return data[i*n+j]; 00185 }; 00186 00187 /** @return element at position i,j (row, column index) and 0 if out of bounds */ 00188 D valDef0(short i, short j) const { 00189 if(0<=i && i<m && 0<=j && j<n) 00190 return data[i*n+j]; 00191 else return 0; 00192 }; 00193 00194 /** sets the size of the matrix and maybe the data if given (row-wise). 00195 If data=null then the matrix is set to zero 00196 @see toZero() 00197 @see constructor Matrix(m,n,data) 00198 */ 00199 void set(unsigned short _m, unsigned short _n, const D* _data=0); 00200 /** sets the data (row-wise). 00201 @param _data if null then matrix elements are set to zero 00202 otherwise the field MUST have the length should be getM()*getN()*/ 00203 void set(const D* _data); 00204 /** @return row-vector(as 1xN matrix) containing the index'th row */ 00205 Matrix row(unsigned short index) const; 00206 /** @returns column-vector(as Nx1 matrix) containing the index'th column */ 00207 Matrix column(unsigned short index) const; 00208 /** @returns submatrix (as NxK matrix) 00209 containing column from startindex to endindex inclusively (K=stopindex-endindex) 00210 indices can be out of bounds, they are clipped in any case 00211 */ 00212 Matrix columns(unsigned short startindex, unsigned short endindex) const; 00213 00214 00215 00216 /** stores the content of the matrix (row-wise) in the given buffer 00217 @param buffer Buffer for storing the elements (should have the length given by len) 00218 @param len Length of the provided buffer. 00219 In any case only min(len, getM()*getN()) elements are copied. 00220 @return number of actually written elements 00221 */ 00222 int convertToBuffer(D* buffer, unsigned int len) const; 00223 00224 /** @return a list of the content of the matrix (row-wise) 00225 */ 00226 std::list<D> convertToList() const; 00227 00228 /* STOREABLE */ 00229 /** stores the Matrix into the given file stream (binary) 00230 */ 00231 bool store(FILE* f) const; 00232 00233 /** reads a Matrix from the given file stream (binary) 00234 */ 00235 bool restore(FILE* f); 00236 00237 /** writes the Matrix into the given file stream (ascii) 00238 */ 00239 bool write(FILE* f) const; 00240 00241 /** reads a Matrix from the given file stream (ascii) 00242 */ 00243 bool read(FILE* f); 00244 00245 00246 public: 00247 // //////////////////////////////////////////////////////////////////// 00248 // ///////////// operations ///////////////////////////// 00249 // (the result of the operation is not stored in one of the operands) 00250 void add(const Matrix& a, const Matrix& b); ///< addition: this = a + b 00251 void sub(const Matrix& a, const Matrix& b); ///< subtraction: this = a - b 00252 void mult(const Matrix& a, const Matrix& b);///< multiplication: this = a * b 00253 void mult(const Matrix& a, const D& fac);///< scaling: this = a * fac 00254 00255 /// returns true if matrix is a 0x0 matrix 00256 bool isNulltimesNull(); 00257 00258 /** maps the matrix to a new matrix 00259 with all elements mapped with the given function 00260 */ 00261 Matrix map(D (*fun)(D)) const; 00262 /** like map but with additional parameter for the mapping function 00263 */ 00264 Matrix mapP(void* param, D (*fun)(void*, D)) const; 00265 00266 // Exotic operations /////////// 00267 /** binary map operator for matrices. 00268 The resulting matrix consists of the function values applied to the elements of a and b. 00269 In haskell this would something like: map (uncurry . fun) $ zip a b 00270 */ 00271 static Matrix map2( D (*fun)(D,D), const Matrix& a, const Matrix& b) { 00272 assert(a.m == b.m && a.n == b.n); 00273 Matrix result(a); 00274 unsigned int len = a.m*a.n; 00275 for(unsigned short i=0; i < len; i++){ 00276 result.data[i] = fun(a.data[i], b.data[i]); 00277 } 00278 return result; 00279 } 00280 00281 /** row-wise multiplication 00282 @param factors column vector (Mx1) of factors, one for each row 00283 */ 00284 Matrix multrowwise(const Matrix& factors) const; 00285 /** column-wise multiplication 00286 @param factors column vector (Mx1) of factors, one for each column 00287 */ 00288 Matrix multcolwise(const Matrix& factors) const; 00289 00290 /// optimised multiplication of Matrix with its transposed: M * M^T 00291 Matrix multMT() const; 00292 /// optimised multiplication of transpsoed of Matrix with itself: M^T * M 00293 Matrix multTM() const; 00294 00295 /// returns the product of all elements (\Pi_{ij} m_{ij}) 00296 D elementProduct() const; 00297 /// returns the sum of all elements (\Sum_{ij} m_{ij}) 00298 D elementSum() const; 00299 00300 /// returns a matrix that consists of this above A 00301 Matrix above(const Matrix& a) const ; 00302 00303 public: /// normal binary Operators 00304 /// deep copy 00305 Matrix& operator = (const Matrix& c) { copy(c); return *this; } 00306 Matrix operator + (const Matrix& sum) const; 00307 Matrix operator - (const Matrix& sum) const; 00308 /** matrix product*/ 00309 Matrix operator * (const Matrix& fac) const; 00310 /** product with scalar (D) */ 00311 Matrix operator * (const D& fac) const; 00312 /** special matrix potence: 00313 @param exponent -1 -> inverse; 00314 0 -> Identity Matrix; 00315 1 -> itself; 00316 T -> Transpose 00317 */ 00318 Matrix operator ^ (int exponent) const; 00319 /// performant combined assigment operators 00320 Matrix& operator += (const Matrix& c) {toSum(c); return *this; } 00321 Matrix& operator -= (const Matrix& c) {toDiff(c); return *this; } 00322 Matrix& operator *= (const Matrix& c) { 00323 Matrix result; 00324 result.mult(*this, c); 00325 this->copy(result); 00326 return *this; 00327 } 00328 Matrix& operator *= (const D& fac) {toMult(fac); return *this; } 00329 00330 #ifndef AVR 00331 /// comparison operator (compares elements with tolerance distance of COMPARE_EPS) 00332 bool operator == (const Matrix& c) const; 00333 /** printing operator: 00334 output format: mxn (\n row0\n..rown \n) where rowX is tab seperated list of values 00335 */ 00336 friend std::ostream& operator<<(std::ostream& , const Matrix&); 00337 #endif 00338 00339 public: 00340 // /////////////////// inplace Operators /////////////////////////////// 00341 /** performs a deep copy of the given matrix */ 00342 void copy(const Matrix& c){ // Deep copy 00343 m=c.m; n=c.n; 00344 allocate(); 00345 memcpy(data,c.data,m*n*sizeof(D)); 00346 } 00347 00348 void toTranspose(); ///< inplace transpose 00349 void toZero(); ///< inplace converts matrix to zero matrix 00350 void toId(); ///< inplace converts matrix to identity (use ^0 to get a copy version of it) 00351 /// inplace addition: this = this + a 00352 void toSum(const Matrix& a) { 00353 assert(a.m==m && a.n==n); 00354 for(unsigned short i=0; i<m*n; i++){ 00355 data[i]+=a.data[i]; 00356 } 00357 } 00358 /// inplace subtraction: this = this - a 00359 void toDiff(const Matrix& a){ 00360 assert(a.m==m && a.n==n); 00361 for(unsigned short i=0; i<m*n; i++){ 00362 data[i]-=a.data[i]; 00363 } 00364 } 00365 00366 /// inplace multiplication with scalar: this = this*fac 00367 void toMult(const D& fac); 00368 00369 /** special inplace matrix potence: 00370 @param exponent -1 -> inverse; (matrix MUST be SQUARE and NONZERO) 00371 0 -> Identity Matrix; 00372 1 -> itself; 00373 T -> Transpose 00374 */ 00375 void toExp(int exponent); 00376 /** inplace mapping of matrix elements (element-wise application) */ 00377 void toMap(D (*fun)(D)); 00378 /** like toMap, but with an extra parameter for the mapping function. */ 00379 void toMapP(void* param, D (*fun)(void*, D)); 00380 // Exotic operations 00381 /** Inplace row-wise multiplication 00382 @param factors column vector of factors, one for each row 00383 */ 00384 void toMultrowwise(const Matrix& factors); 00385 /** Inplace column-wise multiplication 00386 @param factors column vector of factors, one for each column 00387 */ 00388 void toMultcolwise(const Matrix& factors); 00389 00390 /// sets the matrix a below (this) matrix 00391 void toAbove(const Matrix& a); 00392 00393 00394 private: 00395 // NOTE: buffersize determines available memory storage. 00396 // m and n define the actual size 00397 unsigned short m, n; 00398 unsigned int buffersize; // max number if elements 00399 D* data; // where the data contents of the matrix are stored 00400 00401 00402 private: // internals 00403 void allocate(); //internal allocation 00404 /*inplace matrix invertation: 00405 Matrix must be SQARE, in addition, all DIAGONAL ELEMENTS MUST BE NONZERO 00406 (positive definite) 00407 */ 00408 00409 #ifndef AVR 00410 void invertnonzero(); 00411 void invert3x3(); 00412 #endif 00413 void invert2x2(); 00414 }; 00415 00416 } // namespace matrix 00417 #endif
1.4.7