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 #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

Generado el Wed Nov 14 13:47:09 2007 para Uso de Mx::Matrix: por  doxygen 1.3.9.1