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