lkptr - simple reference LinKed PoinTeR:
Matrix.h
Go to the documentation of this file.
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) { \
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         }
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 */
00215 template <class E>
00216 inline Matrix<E>::Matrix(unsigned m, unsigned n) {
00217     if (m == 0 || n == 0) {
00218         m_rows = m_cols = 0;
00219         m_val = 0;
00220     } else {
00221         m_rows = m;
00222         m_cols = n;
00223         m_val = new value_type [n*m];
00224     }
00225 }
00226 
00227 template <class E>
00228 Matrix<E>::Matrix(const Matrix<E>& o) {
00229     if (o.m_val == 0) {        // OJO: una matriz "vacía" produce errores en
00230         m_rows = m_cols = 0;   // Matrix<E>::operator(unsigned, unsigned)
00231         m_val = 0;
00232         return;
00233     }
00234     m_rows = o.m_rows;
00235     m_cols = o.m_cols;
00236     const unsigned MxN = o.m_rows * o.m_cols;
00237     m_val = new value_type [MxN];
00238 
00239     // como las matrices son del mismo tamaño,
00240     // basta copiarlas entrada por entrada.
00241 
00242     value_type *pSelf = this->m_val;
00243     value_type *pO    = o.m_val;
00244     value_type *pEND  = &m_val[MxN];
00245     for (; pSelf != pEND; ++pSelf, ++pO) {
00246         *pSelf = *pO;
00247     }
00248 }
00249 
00250 /// Destructor
00251 template <class E>
00252 inline Matrix<E>::~Matrix() {
00253     if ( m_val != 0 ) {
00254         delete [] m_val;
00255     }
00256 }
00257 
00258 template <class E>
00259 bool Matrix<E>::equals( const Matrix & o ) const {
00260     if (m_rows != o.m_rows || m_cols != o.m_cols) {
00261         return false;
00262     } else if ( m_val == 0 ) {
00263         return true; // las 2 matrices están vacías ==> son iguales
00264     }
00265     const unsigned MxN = o.m_rows * o.m_cols;
00266     value_type *pSelf = this->m_val;
00267     value_type *pO    = o.m_val;
00268     value_type *pEND  = &m_val[MxN];
00269     for (; pSelf != pEND; ++pSelf, ++pO) {
00270         if (*pSelf != *pO) {
00271             return false;
00272         }
00273     }
00274     return true;
00275 }
00276 
00277 /** Copia desde \c "o".
00278     - Copia todo el valor de \c "o" sobre \c "*this", de forma que el nuevo valor de
00279       \c "*this" sea un duplicado exacto del valor de \c "o"
00280     - El valor anterior de \c "*this" se pierde
00281     - El objeto \c "o" mantiene su valor anterior
00282     - Luego de la copia, cuando el valor de \c "o" cambia, el de \c "*this" no cambiará,
00283       y viceversa, pues la copia es una copia profunda; no es superficial
00284     - Si \c "*this" es \c "o" entonces su valor no cambia
00285     - Después de esta operación siempre ocurre que <code> *this == o </code>
00286 
00287     \par Complejidad:
00288          O( <code>  rows() * cols() </code> )
00289 
00290     \returns *this
00291 
00292     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05
00293 */
00294 template <class E>
00295 Matrix<E>& Matrix<E>::copy( const Matrix<E> &o ) {
00296     if (this == &o) { // evita auto-borrado
00297         return *this;
00298     } else if (o.m_val == 0) {
00299         if (m_val != 0) {
00300             delete [] m_val;
00301             m_rows = m_cols = 0;
00302             m_val = 0;
00303         }
00304         return *this;
00305     }
00306     // se asegura de que las dos matrices son del mismo tamaño
00307      const unsigned MxN = o.m_rows * o.m_cols;
00308      if (MxN != m_rows * m_cols) { // truco para evitar borrar la memoria dinámica
00309         delete [] m_val;
00310         m_val = new value_type [MxN];
00311     }
00312     m_rows = o.m_rows;
00313     m_cols = o.m_cols;
00314 
00315 
00316     // como las matrices son del mismo tamaño,
00317     // basta copiarlas entrada por entrada.
00318 
00319     value_type *pSelf = this->m_val;
00320     value_type *pO    = o.m_val;
00321     value_type *pEND  = &m_val[MxN];
00322     for (; pSelf != pEND; ++pSelf, ++pO) {
00323         *pSelf = *pO;
00324     }
00325     return *this;
00326 }
00327 
00328 /** Traslada el valor de \c "o" a \c "*this".
00329   - El valor anterior de \c "*this" se pierde
00330   - El nuevo valor de \c "*this" es el que \c "o" tuvo
00331   - \c "o" queda en el estado en que lo dejaría \c Erase()
00332   - Si \c "*this" es \c "o" entonces su valor no cambia
00333   - En general, después de esta operación casi
00334     nunca ocurre que <code> (*this == o) </code>
00335 
00336     \par Complejidad:
00337          O( <code>  rows() * cols() </code> )
00338 
00339     \returns \c *this
00340 
00341     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc07
00342 */
00343 template <class E>
00344 Matrix<E>& Matrix<E>::move( Matrix<E> &o ) {
00345     if (this == &o) { // evita auto-borrado
00346         return *this;
00347     } else if (o.m_val == 0) {
00348         if (m_val != 0) {
00349             delete [] m_val;
00350             m_rows = m_cols = 0;
00351             m_val = 0;
00352         }
00353         return *this;
00354     } else if ( m_val != 0 ) {
00355         delete [] m_val;
00356     }
00357     m_val = o.m_val;   // me robo los valores de "o"
00358     m_rows = o.m_rows;
00359     m_cols = o.m_cols;
00360 
00361     o.m_rows = o.m_cols = 0;
00362     o.m_val = 0;
00363     return *this;
00364 }
00365 
00366 /** Intercambia los valores de \c "*this" y \c "o".
00367     - Debido a que algunos métodos retornan copias del valor de \c "*this" en
00368       lugar de una referencia, como ocurre con \c Matrix::Child(), a veces
00369       \c swap() no tiene el resultado esperado por el programador.
00370     - Por ejemplo, si se invoca <code> T.Child(i). swap( T.Child(j) ) </code>
00371       el resultado no es intercambiar los hijos, sino más bien intercambiar
00372       los valores de los sub-árboles temporales \c T.Child(i) y \c T.Child(j).
00373       La forma correcta de intercambiar hijos es usar \c Graft().
00374 
00375       \par Complejidad:
00376          O( \c 1 )
00377 
00378     \returns *this
00379 
00380     \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08
00381 */
00382 template <class E>
00383 inline Matrix<E>& Matrix<E>::swap( Matrix<E> &o ) {
00384     std::swap( this->m_val  , o.m_val  );
00385     std::swap( this->m_rows , o.m_rows );
00386     std::swap( this->m_cols , o.m_cols );
00387     return *this;
00388 }
00389 
00390 /** Le cambia las dimensiones a la matriz.
00391     - En algunos casos los valores almacenados en la matriz no quedan
00392       todos iguales a \c Matrix<E>::value_type().
00393     - Si <code> (m * n == 0) </code> deja la matriz vacía.
00394 */
00395 template <class E>
00396 void Matrix<E>::reSize(unsigned m, unsigned n) {
00397      const unsigned MxN = m * n;
00398     if (MxN == 0) {
00399         if (m_val != 0) { // sólo borra si hay algo que borrar
00400             delete [] m_val;
00401             m_rows = m_cols = 0;
00402             m_val = 0;
00403         }
00404     } else if ( MxN == m_rows * m_cols ) { // truco para evitar borrar la memoria dinámica
00405         m_rows = m;
00406         m_cols = n;
00407      } else {
00408         if (m_val != 0) {
00409             delete [] m_val;
00410         }
00411         m_val = new value_type [MxN] ;
00412         m_rows = m;
00413         m_cols = n;
00414     }
00415     return;
00416 
00417 /*  NOTA
00418     Esta es la antigua especificación de reSize(). Es incorrecta
00419     porque presume que el Rep de la matriz es un vector denso en
00420     donde están almacenados todos los valores de la matriz:
00421 
00422     +----------------------------------------------------------+
00423     | reSize(): Le cambia las dimensiones a la matriz.         |
00424     | ========                                                 |
00425     | - Si ocurre que (m*n) == rows() * cols() los valores de  |
00426     |   la matriz se mantienen, aunque cambian sus dimensiones.|
00427     | - Si (m*n) != rows() * cols() los valores de la matriz   |
00428     |   quedarán inicializados de la misma forma en que los    |
00429     |   inicializaría CERO == Sparse_Matrix<E>::value_type().  |
00430     |                                                          |
00431     | \pre (m > 0) && (n > 0)                                  |
00432     +----------------------------------------------------------+
00433 
00434     En la actual especificación, que ya está corregida, no queda
00435     implícita la presunción sobre cómo está organizada internamente
00436     la matriz. Por eso, esta nueva especificación sí sirve para una
00437     matriz implementada con un vector denso de valores, o para la
00438     matriz implementada como una matriz rala.
00439 
00440     Estos pequeños detalles en algunas ocasiones surgen cuando el
00441     programador de una clase introduce mejoras o modificaciones, pues
00442     muchas veces es muy difícil o prácticamente imposible predecir
00443     todos los pormenores y detalles de una especificación o de una
00444     implementación.
00445 */
00446 
00447 }
00448 
00449 /** Le ajusta las dimensiones a la matriz.
00450     - Si ocurre que <code> (m*n) == rows()*cols() </code> hace
00451       lo mismo que haría \c reSize(m,n).
00452     - En caso contrario, no hace nada.
00453 */
00454 template <class E>
00455 inline void Matrix<E>::reShape(unsigned m, unsigned n) {
00456      const unsigned MxN = m * n;
00457      if (MxN == m_rows * m_cols) {
00458         m_rows = m;
00459         m_cols = n;
00460     }
00461 }
00462 
00463 /// Retorna una referencia al elemento [i,j] de la matriz ( \c const ).
00464 /// - \c M(i,j) significa lo que en arreglos se denota con \c M[i][j].
00465 /// - <code>val = M(i,j); // M(i,j) es un "rvalue" (const)</code>
00466 template <class E>
00467 inline const E& Matrix<E>::operator() (unsigned i, unsigned j) const {
00468     assert( "Matrix<E>::operator()()" && (i < rows()) );
00469     assert( "Matrix<E>::operator()()" && (j < cols()) );
00470 
00471     return m_val[ (i * m_cols) + j ] ; // almacena los valores por filas
00472 //  return m_val[ i + (j * m_rows) ] ; // almacena los valores por columnas
00473 }
00474 
00475 /// Retorna una referencia al elemento [i,j] de la matriz.
00476 /// - \c M(i,j) significa lo que en arreglos se denota con \c M[i][j].
00477 /// - <code>M(i,j) = val; // M(i,j) es un "lvalue" (modificable)</code>
00478 template <class E>
00479 inline E& Matrix<E>::operator() (unsigned i, unsigned j) {
00480     assert( "Matrix<E>::operator()()" && (i < rows()) );
00481     assert( "Matrix<E>::operator()()" && (j < cols()) );
00482 
00483     return m_val[ (i * m_cols) + j ] ; // almacena los valores por filas
00484 //  return m_val[ i + (j * m_rows) ] ; // almacena los valores por columnas
00485 }
00486 
00487 /** Le suma a \c "*this" la matriz \c "O".
00488     \pre
00489     - \c "*this" y \c "O" deben tener las mismas dimensiones
00490     - <code> rows() == O.rows() && cols() == O.cols() </code>
00491 
00492     \par Complejidad:
00493          O( <code> rows() * cols() </code> )
00494 
00495     \remarks
00496     - Esta es la implementación de Matrix<E> operator+( Matrix<E>&, Matrix<E> )
00497     - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>)
00498       definida con plantillas si esa función amiga no está definida (implementada)
00499       dentro de la declaración de la clase. Para solventar esta deficiencia existe
00500       este método que realiza el trabajo, aunque es poco cómodo de usar.
00501 */
00502 template <class E>
00503 void Matrix<E>::add( const Matrix<E> & O ) {
00504     // verifica que las dos matrices sean del mismo tamaño
00505     assert( (rows() == O.rows()) && (cols() == O.cols()) );
00506 
00507     // Como las matrices son del mismo tamaño basta sumarlas entrada por entrada.
00508 
00509     value_type *pThis = m_val;
00510     value_type *pO    = & O.m_val[0];
00511     value_type *pEND  = &m_val[m_cols * m_rows];
00512     for ( ; pThis != pEND; ++pThis, ++pO) {
00513         *pThis += *pO;
00514     }
00515     return;
00516 }
00517 
00518 /** Le resta a \c "*this" la matriz \c "O".
00519     \pre
00520     - \c "*this" y \c "O" deben tener las mismas dimensiones
00521     - <code> rows() == O.rows() && cols() == O.cols() </code>
00522 
00523     \par Complejidad:
00524          O( <code> rows() * cols() </code> )
00525 
00526     \remarks
00527     - Esta es la implementación de Matrix<E> operator-( Matrix<E>&, Matrix<E> )
00528     - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>)
00529       definida con plantillas si esa función amiga no está definida (implementada)
00530       dentro de la declaración de la clase. Para solventar esta deficiencia existe
00531       este método que realiza el trabajo, aunque es poco cómodo de usar.
00532 */
00533 template <class E>
00534 void Matrix<E>::substract( const Matrix<E> & O ) {
00535     // verifica que las dos matrices sean del mismo tamaño
00536     assert( (rows() == O.rows()) && (cols() == O.cols()) );
00537 
00538     // Como las matrices son del mismo tamaño basta sumarlas entrada por entrada.
00539 
00540     value_type *pThis = m_val;
00541     value_type *pO    = & O.m_val[0];
00542     value_type *pEND  = &m_val[m_cols * m_rows];
00543     for ( ; pThis != pEND; ++pThis, ++pO) {
00544         *pThis -= *pO;
00545     }
00546     return;
00547 }
00548 
00549 /** Calcula la multiplicación <code> A * B </code> y la almacena en \c "*this".
00550     - Las dimensiones de \c "*this" se ajustan de manera que:
00551       - <code> rows() == A.rows() && cols() == B.cols()</code>
00552 
00553     \pre
00554     - \c "A" y \c "B" deben tener dimensiones compatibles
00555     - <code> A.cols() == B.rows() </code>
00556     - La multiplicación se hace [Fila x Columna], lo que implica que la cantidad
00557       de valores en la filas de \c "A" debe ser igual a la cantidad de columnas de \c "B"
00558 
00559     \par Complejidad:
00560          O( <code> A.cols() * B.cols() * A.cols() </code> )
00561 
00562     \remarks
00563     - Esta es la implementación de Matrix<E> operator*( Matrix<E>&, Matrix<E> )
00564     - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>)
00565       definida con plantillas si esa función amiga no está definida (implementada)
00566       dentro de la declaración de la clase. Para solventar esta deficiencia existe
00567       este método que realiza el trabajo, aunque es poco cómodo de usar.
00568 */
00569 template <class E>
00570 void Matrix<E>::multiply( const Matrix<E> & A, const Matrix<E> & B ) {
00571     // Verifica que las matrices se puedan multiplicar
00572     assert( (A.cols() == B.rows()) && " => Matrix<E>::multiply()" );
00573 
00574     reSize( A.rows(), B.cols() );
00575     value_type sum;
00576     for (unsigned i=0; i<rows(); i++) {
00577         for (unsigned j=0; j<cols(); j++) {
00578             sum = value_type(); // sum = E(0);
00579             for (unsigned k=0; k<A.cols(); k++) {
00580                 sum = sum + A(i,k) * B(k,j);
00581             }
00582             // this->(i,j) = sum; // produce un error de compilación
00583             // this->operator()(i,j) = sum; // también funciona
00584             (*this)(i,j) = sum; // también funciona
00585         }
00586     }
00587     return;
00588 }
00589 
00590 /// Graba en el flujo \c COUT el valor de \c M[][].
00591 template <class E>
00592 std::ostream& operator<<(std::ostream& COUT, const Matrix<E>& M) {
00593     COUT << '[' << M.rows() << 'x' << M.cols() << ']' << std::endl;
00594     for (unsigned i=0; i < M.rows(); ++i) {
00595         for (unsigned j=0; j < M.cols(); ++j) {
00596             COUT << "  " << M(i,j);
00597         }
00598         COUT << std::endl;
00599     }
00600     return COUT;
00601 }
00602 
00603 /// Obtiene del flujo \c CIN el valor para \c M[][].
00604 template <class E>
00605 std::istream& operator>>(std::istream& CIN, Matrix<E>& M) {
00606     assert( "This code has not been tested" );
00607     unsigned rows,cols;
00608     CIN >> rows >> cols;
00609     M.reSize(rows,cols);
00610     for (unsigned i=0; i<rows; i++) {
00611         for (unsigned j=0; j<cols; j++) {
00612             CIN >> M(i,j);
00613         }
00614     }
00615     return CIN;
00616 }
00617 
00618 } // namespace Mx
00619 
00620 #include "Matrix_Lib.h"
00621 
00622 #endif // Matrix_h
00623 // EOF: Matrix.h
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines