Página principal | Lista de namespace | Lista de componentes | Lista de archivos | Miembros del Namespace  | Miembros de las clases | Archivos de los miembros

Matrix.h

Ir a la documentación de este archivo.
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

Generado el Wed Aug 28 09:27:07 2013 para Uso de Mx::Matrix: por  doxygen 1.3.9.1