00001 // Matrix.h Copyright (C) 2004 adolfo@di-mare.com 00002 00003 /** \file Matrix.h 00004 \brief Declaraciones y definiciones para la clase \c Matrix. 00005 00006 \author Adolfo Di Mare <adolfo@di-mare.com> 00007 \date 2004 00008 00009 - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04 00010 */ 00011 00012 #ifndef Matrix_h 00013 #define Matrix_h 00014 00015 #include <cassert> // assert() 00016 00017 /// Definido por la biblioteca C++ estándar 00018 namespace std {} // Está acá para que Doxygen lo documente 00019 00020 /// Matriz chirrisquitica de adolfo@di-mare.com 00021 namespace Mx { 00022 00023 /** Esta es una clase matriz muy chirrisquitica que puede cambiar dinámicamente de tamaño. 00024 - La matriz tiene tamaño \c rows() x \c cols() 00025 - Se le puede cambiar el tamaño dinámicamente con el método \c reSize(). 00026 - La clase \c E debe incluir un neutro para la adición, cuyo valor debe poderse 00027 obtener invocando el convertidor \c Sparse_Matrix<E>::value_type(0). 00028 - Las operaciones aritméticas "+" "-" "*" deben estar definidas para 00029 \c Matrix<E>::value_type y debe existir el valor \c Matrix<E>::value_type(0) y también 00030 \c Matrix<E>::value_type(1) (para matrices unitarias) 00031 - Los valores de la matriz pueden estar almacenados por filas o por columnas, 00032 según quede implementado el método \c Matrix<E>::operator(unsigned, unsigned) 00033 00034 \see http://www.oonumerics.org/oon/ 00035 */ 00036 template <class E> 00037 class Matrix { 00038 public: 00039 /// Tipo del objeto almacenado, similar al nombre usado en STL 00040 typedef E value_type; 00041 /// Tipo del objeto almacenado, similar al nombre usado en STL 00042 typedef value_type& reference; 00043 /// Tipo del objeto almacenado, similar al nombre usado en STL 00044 typedef const value_type& const_reference; 00045 /// Tipo del tamaño de un objeto, similar al nombre usado en STL 00046 typedef unsigned size_type; 00047 public: 00048 Matrix(unsigned m = 1, unsigned n = 1); 00049 Matrix(const Matrix& o); ///< Constructor de copia 00050 /// Matriz escalar de valor \c V. 00051 Matrix(const value_type V) : m_rows(0), m_cols(0), m_val(0) { reSize(1,1); (*this)(0,0) = V; } 00052 ~Matrix(); 00053 public: 00054 unsigned count() const { return size(); } ///< Cantidad de valores almacenados en la matriz 00055 unsigned size() const { return m_rows * m_cols; } ///< Cantidad de valores almacenados en la matriz 00056 unsigned rows() const { return m_rows; } ///< Cantidad de filas de la matriz 00057 unsigned cols() const { return m_cols; } ///< Cantidad de columnas de la Matriz 00058 /// Cantidad máxima posible de valores diferentes que pueden ser almacenados en la matriz 00059 size_type capacity() const { return size(); } 00060 public: 00061 Matrix& operator= (const Matrix &o) { return copy(o); } ///< Sinónimo de \c this->copy(o) 00062 Matrix& copy( const Matrix &o ); 00063 Matrix& move( Matrix &o ); 00064 Matrix& swap( Matrix &o ); 00065 public: 00066 /// ¿¿¿ (p == q) ??? 00067 friend bool operator == (const Matrix &p, const Matrix &q) { return p.equals(q); } 00068 /// ¿¿¿ (p != q) ??? 00069 friend bool operator != (const Matrix &p, const Matrix &q) { return !(p==q); } 00070 bool equals( const Matrix & o ) const; ///< ¿¿¿ (*this==o) ??? 00071 /// Retorna \c true si \c "o" comparte sus valores con \c "*this" 00072 bool same( const Matrix & o ) const { return this == &o; } 00073 protected: // disponibles para clases derivadas 00074 void add( const Matrix & ); 00075 void substract( const Matrix & ); 00076 void multiply( const Matrix &, const Matrix & ); 00077 public: 00078 friend Matrix operator + (const Matrix& A, const Matrix& B) 00079 { Matrix Res = A; Res.add(B); return Res; } ///< Retorna \c A+B 00080 friend Matrix operator - (const Matrix& A, const Matrix& B) 00081 { Matrix Res = A; Res.substract(B); return Res; } ///< Retorna \c A-B 00082 friend Matrix operator * (const Matrix& A, const Matrix& B) 00083 { Matrix Res; Res.multiply(A, B); return Res; } ///< Retorna \c A*B 00084 public: 00085 reference operator () (unsigned, unsigned); 00086 const_reference operator () (unsigned, unsigned) const; 00087 reference at (unsigned m, unsigned n) 00088 { return operator() (m,n); } ///< Retorna \c operator()(m,n). 00089 const_reference at (unsigned m, unsigned n) const 00090 { return operator() (m,n); } ///< Retorna \c operator()(m,n) \c "const". 00091 public: 00092 void reSize( unsigned, unsigned); 00093 void reShape(unsigned, unsigned); 00094 void transpose() { 00095 unsigned tmp = m_rows; 00096 m_rows = m_cols; 00097 m_cols = tmp; 00098 } ///< Transpone la matriz. 00099 00100 template<class T> friend bool check_ok( const Matrix<T>& M ); 00101 template<class T> friend class test_Matrix; ///< Datos de prueba para la clase 00102 private: 00103 value_type * m_val; ///< Vector de valores de la matriz 00104 unsigned m_rows; ///< Cantidad de filas de la matriz 00105 unsigned m_cols; ///< Cantidad de columnas de la matris 00106 }; // Matrix 00107 00108 00109 /** Verifica la invariante de la clase. 00110 - Es posible que la matriz tenga dimensiones nulas, lo que implica que todos los 00111 punteros a los vectors paralelos deben ser nulos. Este hecho se marca dándolo 00112 el valor \c 0 (cero) al campo \c m_val. 00113 - Las matrices quedan almacenadas en un vector de tamaño [M x N]. 00114 - En todos los algoritmos, "m" o "m_rows" es la cantidad de filas == \c rows() 00115 - En todos los algoritmos, "n" o "m_cols" es la cantidad de columnas == \c cols() 00116 00117 \par <em>Rep</em> Modelo de la clase 00118 \code 00119 +---+ / \ 00120 | 2 | M(i,j) ==> m_val[ (i * m_cols) + j ] | 0 1 2 3 | m_rows == 2 00121 +---+ (almacenamiento por filas) | 4 5 6 7 | m_cols == 4 00122 | 4 | \ / 00123 +---+ +---+---+---+---+---+---+---+---+ 00124 | *-|-->| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 00125 +---+ +---+---+---+---+---+---+---+---+ 00126 \endcode 00127 00128 \par <em>Rep</em> Modelo de la clase 00129 \code 00130 +---+ 00131 | 4 | M(i,j) ==> m_val[ i + (j * m_rows) ] / a e \ 00132 +---+ (almacenamiento por columnas) | b f | m_rows == 4 00133 | 2 | | c g | m_cols == 2 00134 +---+ +---+---+---+---+---+---+---+---+ \ d h / 00135 | *-|-->| a | b | c | d | e | f | g | h | 00136 +---+ +---+---+---+---+---+---+---+---+ 00137 \endcode 00138 - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep 00139 \remark 00140 Libera al programador de implementar el método \c Ok() 00141 - http://www.di-mare.com/adolfo/binder/c04.htm#sc11 00142 */ 00143 template<class T> 00144 bool check_ok( const Matrix<T>& M ) { 00145 if ( M.m_rows == 0 || M.m_cols == 0 ) { // si alguno es cero... 00146 if ( M.m_rows != 0 || M.m_cols != 0 ) { // ... los 2 deben serlo 00147 return false; /// - Invariante: <code>(M.m_rows == 0) <==> (M.m_cols == 0)</code> 00148 } 00149 else { 00150 if (M.m_val != 0) { 00151 return false; /// - Invariante: <code>(M.m_rows == 0) <==> (M.m_val == 0)</code> 00152 } 00153 return true; // La implementación sí permite (m_val == 0) 00154 } 00155 } 00156 00157 unsigned MxN = M.m_rows * M.m_cols; 00158 for (unsigned k=0; k<MxN; ++k) { 00159 if ( ! check_ok( M.m_val[k] ) ) { 00160 return false; /// - Invariante: <code>check_ok( m_val[k] )</code> 00161 } 00162 } 00163 return true; 00164 } 00165 00166 00167 /** \fn template <class E>inline Matrix<E>::Matrix(const value_type V); 00168 \brief Constructor a partir de \c Matrix<E>::value_type(V). 00169 00170 - La matriz resultante es una matriz escalar, de dimensiones 1x1, 00171 y su valor es \c "V". 00172 */ 00173 00174 /** Constructor de vector. 00175 - Obtiene suficiente memoria dinámica para almacenas los 00176 <code> n * m </code> valores de la matriz 00177 - Si \c "value_type" tiene un constructor de vector, lo 00178 usar para inicializar cada uno de los valores de la matriz; 00179 de lo contrario, los deja tal cual están en la memoria 00180 - Si \c "value_type" es uno de los tipos escalares básicos, 00181 como lo son \c int o \c float, los valores almacenados 00182 en la matriz quedan tal cual están y no son inicializados. 00183 00184 \pre 00185 - <code> m * n > 0 </code> 00186 - <code> (m > 0) && (n > 0) </code> 00187 00188 */ 00189 template <class E> 00190 inline Matrix<E>::Matrix(unsigned m, unsigned n) { 00191 if (m == 0 || n == 0) { 00192 m_rows = m_cols = 0; 00193 m_val = 0; 00194 } else { 00195 m_rows = m; 00196 m_cols = n; 00197 m_val = new value_type [n*m]; 00198 } 00199 } 00200 00201 template <class E> 00202 Matrix<E>::Matrix(const Matrix<E>& o) { 00203 if (o.m_val == 0) { // OJO: una matriz "vacía" produce errores en 00204 m_rows = m_cols = 0; // Matrix<E>::operator(unsigned, unsigned) 00205 m_val = 0; 00206 return; 00207 } 00208 m_rows = o.m_rows; 00209 m_cols = o.m_cols; 00210 const unsigned MxN = o.m_rows * o.m_cols; 00211 m_val = new value_type [MxN]; 00212 00213 // como las matrices son del mismo tamaño, 00214 // basta copiarlas entrada por entrada. 00215 00216 value_type *pSelf = this->m_val; 00217 value_type *pO = o.m_val; 00218 value_type *pEND = &m_val[MxN]; 00219 for (; pSelf != pEND; ++pSelf, ++pO) { 00220 *pSelf = *pO; 00221 } 00222 } 00223 00224 /// Destructor 00225 template <class E> 00226 inline Matrix<E>::~Matrix() { 00227 if ( m_val != 0 ) { 00228 delete [] m_val; 00229 } 00230 } 00231 00232 template <class E> 00233 bool Matrix<E>::equals( const Matrix & o ) const { 00234 if (m_rows != o.m_rows || m_cols != o.m_cols) { 00235 return false; 00236 } else if ( m_val == 0 ) { 00237 return true; // las 2 matrices están vacías ==> son iguales 00238 } 00239 const unsigned MxN = o.m_rows * o.m_cols; 00240 value_type *pSelf = this->m_val; 00241 value_type *pO = o.m_val; 00242 value_type *pEND = &m_val[MxN]; 00243 for (; pSelf != pEND; ++pSelf, ++pO) { 00244 if (*pSelf != *pO) { 00245 return false; 00246 } 00247 } 00248 return true; 00249 } 00250 00251 /** Copia desde \c "o". 00252 - Copia todo el valor de \c "o" sobre \c "*this", de forma que el nuevo valor de 00253 \c "*this" sea un duplicado exacto del valor de \c "o" 00254 - El valor anterior de \c "*this" se pierde 00255 - El objeto \c "o" mantiene su valor anterior 00256 - Luego de la copia, cuando el valor de \c "o" cambia, el de \c "*this" no cambiará, 00257 y viceversa, pues la copia es una copia profunda; no es superficial 00258 - Si \c "*this" es \c "o" entonces su valor no cambia 00259 - Después de esta operación siempre ocurre que <code> *this == o </code> 00260 00261 \par Complejidad: 00262 O( <code> rows() * cols() </code> ) 00263 00264 \returns *this 00265 00266 \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05 00267 */ 00268 template <class E> 00269 Matrix<E>& Matrix<E>::copy( const Matrix<E> &o ) { 00270 if (this == &o) { // evita auto-borrado 00271 return *this; 00272 } else if (o.m_val == 0) { 00273 if (m_val != 0) { 00274 delete [] m_val; 00275 m_rows = m_cols = 0; 00276 m_val = 0; 00277 } 00278 return *this; 00279 } 00280 // se asegura de que las dos matrices son del mismo tamaño 00281 const unsigned MxN = o.m_rows * o.m_cols; 00282 if (MxN != m_rows * m_cols) { // truco para evitar borrar la memoria dinámica 00283 delete [] m_val; 00284 m_val = new value_type [MxN]; 00285 } 00286 m_rows = o.m_rows; 00287 m_cols = o.m_cols; 00288 00289 00290 // como las matrices son del mismo tamaño, 00291 // basta copiarlas entrada por entrada. 00292 00293 value_type *pSelf = this->m_val; 00294 value_type *pO = o.m_val; 00295 value_type *pEND = &m_val[MxN]; 00296 for (; pSelf != pEND; ++pSelf, ++pO) { 00297 *pSelf = *pO; 00298 } 00299 return *this; 00300 } 00301 00302 /** Traslada el valor de \c "o" a \c "*this". 00303 - El valor anterior de \c "*this" se pierde 00304 - El nuevo valor de \c "*this" es el que \c "o" tuvo 00305 - \c "o" queda en el estado en que lo dejaría \c Erase() 00306 - Si \c "*this" es \c "o" entonces su valor no cambia 00307 - En general, después de esta operación casi 00308 nunca ocurre que <code> (*this == o) </code> 00309 00310 \par Complejidad: 00311 O( <code> rows() * cols() </code> ) 00312 00313 \returns \c *this 00314 00315 \see http://www.di-mare.com/adolfo/binder/c04.htm#sc07 00316 */ 00317 template <class E> 00318 Matrix<E>& Matrix<E>::move( Matrix<E> &o ) { 00319 if (this == &o) { // evita auto-borrado 00320 return *this; 00321 } else if (o.m_val == 0) { 00322 if (m_val != 0) { 00323 delete [] m_val; 00324 m_rows = m_cols = 0; 00325 m_val = 0; 00326 } 00327 return *this; 00328 } else if ( m_val != 0 ) { 00329 delete [] m_val; 00330 } 00331 m_val = o.m_val; // me robo los valores de "o" 00332 m_rows = o.m_rows; 00333 m_cols = o.m_cols; 00334 00335 o.m_rows = o.m_cols = 0; 00336 o.m_val = 0; 00337 return *this; 00338 } 00339 00340 /** Intercambia los valores de \c "*this" y \c "o". 00341 - Debido a que algunos métodos retornan copias del valor de \c "*this" en 00342 lugar de una referencia, como ocurre con \c Matrix::Child(), a veces 00343 \c swap() no tiene el resultado esperado por el programador. 00344 - Por ejemplo, si se invoca <code> T.Child(i). swap( T.Child(j) ) </code> 00345 el resultado no es intercambiar los hijos, sino más bien intercambiar 00346 los valores de los sub-árboles temporales \c T.Child(i) y \c T.Child(j). 00347 La forma correcta de intercambiar hijos es usar \c Graft(). 00348 00349 \par Complejidad: 00350 O( \c 1 ) 00351 00352 \returns *this 00353 00354 \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08 00355 */ 00356 template <class E> 00357 inline Matrix<E>& Matrix<E>::swap( Matrix<E> &o ) { 00358 std::swap( this->m_val , o.m_val ); 00359 std::swap( this->m_rows , o.m_rows ); 00360 std::swap( this->m_cols , o.m_cols ); 00361 return *this; 00362 } 00363 00364 /** Le cambia las dimensiones a la matriz. 00365 - En algunos casos los valores almacenados en la matriz no quedan 00366 todos iguales a \c Matrix<E>::value_type(0). 00367 - Si <code> (m * n == 0) </code> deja la matriz vacía. 00368 */ 00369 template <class E> 00370 void Matrix<E>::reSize(unsigned m, unsigned n) { 00371 const unsigned MxN = m * n; 00372 if (MxN == 0) { 00373 if (m_val != 0) { // sólo borra si hay algo que borrar 00374 delete [] m_val; 00375 m_rows = m_cols = 0; 00376 m_val = 0; 00377 } 00378 } else if ( MxN == m_rows * m_cols ) { // truco para evitar borrar la memoria dinámica 00379 m_rows = m; 00380 m_cols = n; 00381 } else { 00382 if (m_val != 0) { 00383 delete [] m_val; 00384 } 00385 m_val = new value_type [MxN] ; 00386 m_rows = m; 00387 m_cols = n; 00388 } 00389 return; 00390 00391 /* NOTA 00392 Esta es la antigua especificación de reSize(). Es incorrecta 00393 porque presume que el Rep de la matriz es un vector denso en 00394 donde están almacenados todos los valores de la matriz: 00395 00396 +----------------------------------------------------------+ 00397 | reSize(): Le cambia las dimensiones a la matriz. | 00398 | ======== | 00399 | - Si ocurre que (m*n) == rows() * cols() los valores de | 00400 | la matriz se mantienen, aunque cambian sus dimensiones.| 00401 | - Si (m*n) != rows() * cols() los valores de la matriz | 00402 | quedarán inicializados de la misma forma en que los | 00403 | inicializaría CERO == Sparse_Matrix<E>::value_type(0). | 00404 | | 00405 | \pre (m > 0) && (n > 0) | 00406 +----------------------------------------------------------+ 00407 00408 En la actual especificación, que ya está corregida, no queda 00409 implícita la presunción sobre cómo está organizada internamente 00410 la matriz. Por eso, esta nueva especificación sí sirve para una 00411 matriz implementada con un vector denso de valores, o para la 00412 matriz implementada como una matriz rala. 00413 00414 Estos pequeños detalles en algunas ocasiones surgen cuando el 00415 programador de una clase introduce mejoras o modificaciones, pues 00416 muchas veces es muy difícil o prácticamente imposible predecir 00417 todos los pormenores y detalles de una especificación o de una 00418 implementación. 00419 */ 00420 00421 } 00422 00423 /** Le ajusta las dimensiones a la matriz. 00424 - Si ocurre que <code> (m*n) == rows()*cols() </code> hace 00425 lo mismo que haría \c reSize(m,n). 00426 - En caso contrario, no hace nada. 00427 */ 00428 template <class E> 00429 inline void Matrix<E>::reShape(unsigned m, unsigned n) { 00430 const unsigned MxN = m * n; 00431 if (MxN == m_rows * m_cols) { 00432 m_rows = m; 00433 m_cols = n; 00434 } 00435 } 00436 00437 /// Retorna una referencia al elemento [i,j] de la matriz ( \c const ). 00438 /// - \c M(i,j) significa lo que en arreglos se denota con \c M[i][j]. 00439 /// - <code>val = M(i,j); // M(i,j) es un "rvalue" (const)</code> 00440 template <class E> 00441 inline const E& Matrix<E>::operator() (unsigned i, unsigned j) const { 00442 assert( "Matrix<E>::operator()()" && (i < rows()) ); 00443 assert( "Matrix<E>::operator()()" && (j < cols()) ); 00444 00445 return m_val[ (i * m_cols) + j ] ; // almacena los valores por filas 00446 // return m_val[ i + (j * m_rows) ] ; // almacena los valores por columnas 00447 } 00448 00449 /// Retorna una referencia al elemento [i,j] de la matriz. 00450 /// - \c M(i,j) significa lo que en arreglos se denota con \c M[i][j]. 00451 /// - <code>M(i,j) = val; // M(i,j) es un "lvalue" (modificable)</code> 00452 template <class E> 00453 inline E& Matrix<E>::operator() (unsigned i, unsigned j) { 00454 assert( "Matrix<E>::operator()()" && (i < rows()) ); 00455 assert( "Matrix<E>::operator()()" && (j < cols()) ); 00456 00457 return m_val[ (i * m_cols) + j ] ; // almacena los valores por filas 00458 // return m_val[ i + (j * m_rows) ] ; // almacena los valores por columnas 00459 } 00460 00461 /** Le suma a \c "*this" la matriz \c "O". 00462 \pre 00463 - \c "*this" y \c "O" deben tener las mismas dimensiones 00464 - <code> rows() == O.rows() && cols() == O.cols() </code> 00465 00466 \par Complejidad: 00467 O( <code> rows() * cols() </code> ) 00468 00469 \remarks 00470 - Esta es la implementación de Matrix<E> operator+( Matrix<E>&, Matrix<E> ) 00471 - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>) 00472 definida con plantillas si esa función amiga no está definida (implementada) 00473 dentro de la declaración de la clase. Para solventar esta deficiencia existe 00474 este método que realiza el trabajo, aunque es poco cómodo de usar. 00475 */ 00476 template <class E> 00477 void Matrix<E>::add( const Matrix<E> & O ) { 00478 // verifica que las dos matrices sean del mismo tamaño 00479 assert( (rows() == O.rows()) && (cols() == O.cols()) ); 00480 00481 // Como las matrices son del mismo tamaño basta sumarlas entrada por entrada. 00482 00483 value_type *pThis = m_val; 00484 value_type *pO = & O.m_val[0]; 00485 value_type *pEND = &m_val[m_cols * m_rows]; 00486 for ( ; pThis != pEND; ++pThis, ++pO) { 00487 *pThis += *pO; 00488 } 00489 return; 00490 } 00491 00492 /** Le resta a \c "*this" la matriz \c "O". 00493 \pre 00494 - \c "*this" y \c "O" deben tener las mismas dimensiones 00495 - <code> rows() == O.rows() && cols() == O.cols() </code> 00496 00497 \par Complejidad: 00498 O( <code> rows() * cols() </code> ) 00499 00500 \remarks 00501 - Esta es la implementación de Matrix<E> operator-( Matrix<E>&, Matrix<E> ) 00502 - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>) 00503 definida con plantillas si esa función amiga no está definida (implementada) 00504 dentro de la declaración de la clase. Para solventar esta deficiencia existe 00505 este método que realiza el trabajo, aunque es poco cómodo de usar. 00506 */ 00507 template <class E> 00508 void Matrix<E>::substract( const Matrix<E> & O ) { 00509 // verifica que las dos matrices sean del mismo tamaño 00510 assert( (rows() == O.rows()) && (cols() == O.cols()) ); 00511 00512 // Como las matrices son del mismo tamaño basta sumarlas entrada por entrada. 00513 00514 value_type *pThis = m_val; 00515 value_type *pO = & O.m_val[0]; 00516 value_type *pEND = &m_val[m_cols * m_rows]; 00517 for ( ; pThis != pEND; ++pThis, ++pO) { 00518 *pThis -= *pO; 00519 } 00520 return; 00521 } 00522 00523 /** Calcula la multiplicación <code> A * B </code> y la almacena en \c "*this". 00524 - Las dimensiones de \c "*this" se ajustan de manera que: 00525 - <code> rows() == A.rows() && cols() == B.cols()</code> 00526 00527 \pre 00528 - \c "A" y \c "B" deben tener dimensiones compatibles 00529 - <code> A.cols() == B.rows() </code> 00530 - La multiplicación se hace [Fila x Columna], lo que implica que la cantidad 00531 de valores en la filas de \c "A" debe ser igual a la cantidad de columnas de \c "B" 00532 00533 \par Complejidad: 00534 O( <code> A.cols() * B.cols() * A.cols() </code> ) 00535 00536 \remarks 00537 - Esta es la implementación de Matrix<E> operator*( Matrix<E>&, Matrix<E> ) 00538 - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>) 00539 definida con plantillas si esa función amiga no está definida (implementada) 00540 dentro de la declaración de la clase. Para solventar esta deficiencia existe 00541 este método que realiza el trabajo, aunque es poco cómodo de usar. 00542 */ 00543 template <class E> 00544 void Matrix<E>::multiply( const Matrix<E> & A, const Matrix<E> & B ) { 00545 // Verifica que las matrices se puedan multiplicar 00546 assert( (A.cols() == B.rows()) && " => Matrix<E>::multiply()" ); 00547 00548 reSize( A.rows(), B.cols() ); 00549 value_type sum; 00550 for (unsigned i=0; i<rows(); i++) { 00551 for (unsigned j=0; j<cols(); j++) { 00552 sum = 0; // sum = E(0); 00553 for (unsigned k=0; k<A.cols(); k++) { 00554 sum = sum + A(i,k) * B(k,j); 00555 } 00556 // this->(i,j) = sum; // produce un error de compilación 00557 // this->operator()(i,j) = sum; // también funciona 00558 (*this)(i,j) = sum; // también funciona 00559 } 00560 } 00561 return; 00562 } 00563 00564 /// Graba en el flujo \c COUT el valor de \c M[][]. 00565 template <class E> 00566 std::ostream& operator<<(std::ostream& COUT, const Matrix<E>& M) { 00567 COUT << '[' << M.rows() << 'x' << M.cols() << ']' << std::endl; 00568 for (unsigned i=0; i < M.rows(); ++i) { 00569 for (unsigned j=0; j < M.cols(); ++j) { 00570 COUT << " " << M(i,j); 00571 } 00572 COUT << std::endl; 00573 } 00574 return COUT; 00575 } 00576 00577 /// Obtiene del flujo \c CIN el valor para \c M[][]. 00578 template <class E> 00579 std::istream& operator>>(std::istream& CIN, Matrix<E>& M) { 00580 assert( "This code has not been tested" ); 00581 unsigned rows,cols; 00582 CIN >> rows >> cols; 00583 M.reSize(rows,cols); 00584 for (unsigned i=0; i<rows; i++) { 00585 for (unsigned j=0; j<cols; j++) { 00586 CIN >> M(i,j); 00587 } 00588 } 00589 return CIN; 00590 } 00591 00592 } // namespace Mx 00593 00594 #include "Matrix_Lib.h" 00595 00596 #endif // Matrix_h 00597 // EOF: Matrix.h
1.3.9.1