Abstract non Polymorphyc Matrix:
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines
Matrix_Dense.h
Go to the documentation of this file.
00001 // Matrix_Dense.h Copyright (C) 2009  adolfo@di-mare.com
00002 
00003 #ifdef Spanish_dox
00004 /** \file  Matrix_Dense.h
00005     \brief Declaraciones y definiciones para la clase \c Matrix_Dense.<>
00006     \author Adolfo Di Mare <adolfo@di-mare.com>
00007     \date   2009
00008     - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
00009 */
00010 #endif
00011 #ifdef English_dox
00012 /** \file  Matrix_Dense.h
00013     \brief Declarations and definitiones for class \c Matrix_Dense<>.
00014     \author Adolfo Di Mare <adolfo@di-mare.com>
00015     \date   2009
00016     - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
00017 */
00018 #endif
00019 
00020 #ifndef   Matrix_Dense_h
00021 #define   Matrix_Dense_h   // Evita la inclusión múltiple#include "Matrix_BASE.h"
00022 
00023 #include "Matrix_BASE.h"
00024 
00025 namespace Mx {
00026 
00027 #ifdef Spanish_dox
00028 /// Esta es una clase matriz muy chirrisquitica que puede cambiar dinámicamente de tamaño.
00029 #endif
00030 #ifdef English_dox
00031 /// This is a very chirrisquitica matrix that can change size dinamically.
00032 #endif
00033 /// \copydetails Matrix_BASE
00034 template <class E>
00035 class Matrix_Dense : public Matrix_BASE<E> {
00036 public:
00037     Matrix_Dense(unsigned m = 1, unsigned n = 1);
00038     Matrix_Dense(const Matrix_Dense& o);
00039     /// \copydoc Matrix_BASE::Matrix_BASE(const E&)
00040     Matrix_Dense(const E& V)
00041         : Matrix_BASE<E>() , m_rows(0), m_cols(0), m_val(0)
00042         { reSize(1,1); (*this)(0,0) = V; }
00043     ~Matrix_Dense(); ///< Destructor.
00044 public:
00045     unsigned rows()  const { return m_rows; }
00046     unsigned cols()  const { return m_cols; }
00047     unsigned size()  const { return m_rows * m_cols; }
00048     unsigned count() const { return size(); }
00049     unsigned capacity() const { return size(); }
00050 public:
00051     Matrix_Dense& operator= (const Matrix_Dense &o) { return copy(o); }
00052     Matrix_Dense& copy( const Matrix_Dense &o );
00053     Matrix_Dense& move( Matrix_Dense &o );
00054     Matrix_Dense& swap( Matrix_Dense &o );
00055     void clear();
00056 public:
00057     bool equals( const Matrix_Dense & o ) const;
00058 public:
00059     E& operator()(unsigned, unsigned);
00060     const E& operator()(unsigned, unsigned) const;
00061     E& at(unsigned i, unsigned j) { return at_Matrix(*this,i,j); }
00062     const E& at(unsigned i, unsigned j) const { return at_Matrix(*this,i,j); }
00063 
00064     void reShape(unsigned m, unsigned n);
00065     void reSize( unsigned m, unsigned n);
00066     void transpose();
00067 
00068     void setDefault(const E& same) { }
00069     const E getDefault() { return E(0); }
00070 public:
00071     template <class T> friend bool  check_ok( const Matrix_Dense<T>& M );
00072     template <class T> friend class test_Matrix; ///< BUnit test.
00073 private: // Rep
00074     typename Matrix_BASE<E>::value_type * m_val;
00075     unsigned     m_rows;
00076     unsigned     m_cols;
00077 private:
00078     template <class T> friend
00079     void add_Matrix( Matrix_Dense<T>& Res, const Matrix_Dense<T>& M );
00080 }; // Matrix_Dense
00081 
00082 #ifdef Spanish_dox
00083 /// \fn    template <class E> Matrix_Dense<E>::m_val;
00084 /// \brief Vector de valores de la matriz.
00085 
00086 /// \fn    template <class E> Matrix_Dense<E>::m_rows;
00087 /// \brief Cantidad de filas de la matriz.
00088 
00089 /// \fn    template <class E> Matrix_Dense<E>::m_cols;
00090 /// \brief Cantidad de columnas de la matriz.
00091 #endif
00092 #ifdef English_dox
00093 /// \fn    template <class E> Matrix_Dense<E>::m_val;
00094 /// \brief Vector to hold the matrix's values.
00095 
00096 /// \fn    template <class E> Matrix_Dense<E>::m_rows;
00097 /// \brief Number of rows of the matrix.
00098 
00099 /// \fn    template <class E> Matrix_Dense<E>::m_cols;
00100 /// \brief Number of columns of the matrix.
00101 #endif
00102 
00103 #if 0
00104 {{  // Rep ==> Diagrama de la clase
00105     +---+                                         /         \
00106     | 2 |  M(i,j) ==> m_val[ (i * m_cols) + j ]   | 0 1 2 3 |   m_rows == 2
00107     +---+  (almacenamiento por filas)             | 4 5 6 7 |   m_cols == 4
00108     | 4 |                                         \         /
00109     +---+   +---+---+---+---+---+---+---+---+
00110     | *-|-->| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
00111     +---+   +---+---+---+---+---+---+---+---+
00112 
00113     +---+
00114     | 4 |  M(i,j) ==> m_val[ i + (j * m_rows) ]   / a e \
00115     +---+  (almacenamiento por columnas)          | b f |   m_rows == 4
00116     | 2 |                                         | c g |   m_cols == 2
00117     +---+   +---+---+---+---+---+---+---+---+     \ d h /
00118     | *-|-->| a | b | c | d | e | f | g | h |
00119     +---+   +---+---+---+---+---+---+---+---+
00120 }}
00121 #endif
00122 
00123 #ifdef Spanish_dox
00124 /** Verifica la invariante de la clase.
00125     \dontinclude Matrix_Dense.h
00126     \skipline    Rep ==> Diagrama de la clase
00127     \until       }}
00128     \copydetails check_ok_Matrix( const MAT& M )
00129 */
00130 #endif
00131 #ifdef English_dox
00132 /** Checks the class invariant.
00133     \dontinclude Matrix_Dense.h
00134     \skipline    Rep ==> Diagrama de la clase
00135     \until       }}
00136     \copydetails check_ok_Matrix(const MAT&)
00137 */
00138 #endif
00139 template <class T>
00140 bool check_ok( const Matrix_Dense<T>& M ) {
00141     if ( ! (&M != 0 ) ) {
00142         return false; /// - check_ok(): <code> &M != 0 </code>.
00143     }
00144     if ( M.m_rows == 0 || M.m_cols == 0 ) {    // si alguno es cero...
00145         if ( M.m_rows != 0 || M.m_cols != 0 ) { // ... los 2 deben serlo
00146             return false; /// - check_ok(): <code>(M.m_rows == 0) <==> (M.m_cols == 0)</code>
00147         }
00148         else {
00149             if (M.m_val != 0) {
00150                 return false; /// - check_ok(): <code>(M.m_rows == 0) <==> (M.m_val == 0)</code>
00151             }
00152             return true; // La implementación sí permite (m_val == 0)
00153         }
00154     }
00155 
00156     unsigned MxN = M.m_rows * M.m_cols;
00157     for (unsigned k=0; k<MxN; ++k) {
00158         if ( ! check_ok( M.m_val[k] ) ) {
00159             return false; /// - check_ok(): <code>check_ok( m_val[k] )</code>
00160         }
00161     }
00162     return true;
00163 }
00164 
00165 /// \copydoc Matrix_BASE::Matrix_BASE(unsigned,unsigned)
00166 template <class E>
00167 inline Matrix_Dense<E>::Matrix_Dense(unsigned m, unsigned n) {
00168     if (m == 0 || n == 0) {
00169         m_rows = m_cols = 0;
00170         m_val = 0;
00171     } else {
00172         m_rows = m;
00173         m_cols = n;
00174         m_val = new typename Matrix_BASE<E>::value_type [n*m];
00175     }
00176 }
00177 
00178 /// \copydoc Matrix_BASE::Matrix_BASE(const Matrix_BASE&)
00179 template <class E>
00180 Matrix_Dense<E>::Matrix_Dense(const Matrix_Dense<E>& o) {
00181     if (o.m_val == 0) {        // OJO: una matriz "vacía" produce errores en
00182         m_rows = m_cols = 0;   // Matrix_Dense<E>::operator(unsigned, unsigned)
00183         m_val = 0;
00184         return;
00185     }
00186     m_rows = o.m_rows;
00187     m_cols = o.m_cols;
00188     const unsigned MxN = o.m_rows * o.m_cols;
00189     m_val = new typename Matrix_BASE<E>::value_type [MxN];
00190 
00191     // como las matrices son del mismo tamaño,
00192     // basta copiarlas entrada por entrada.
00193 
00194     typename Matrix_BASE<E>::value_type *pSelf = this->m_val;
00195     typename Matrix_BASE<E>::value_type *pO    = o.m_val;
00196     typename Matrix_BASE<E>::value_type *pEND  = &m_val[MxN];
00197     for (; pSelf != pEND; ++pSelf, ++pO) {
00198         *pSelf = *pO;
00199     }
00200 }
00201 
00202 /// \copydoc Matrix_BASE::~Matrix_BASE()
00203 template <class E>
00204 inline Matrix_Dense<E>::~Matrix_Dense() {
00205     if ( m_val != 0 ) {
00206         delete [] m_val;
00207     }
00208 }
00209 
00210 /// \copydoc Matrix_BASE::equals()
00211 //  \copybrief Matrix_BASE::equals() \copydetails Matrix_BASE::equals()
00212 template <class E>
00213 bool Matrix_Dense<E>::equals( const Matrix_Dense & o ) const {
00214     if (m_rows != o.m_rows || m_cols != o.m_cols) {
00215         return false;
00216     } else if ( m_val == 0 ) {
00217         return true; // las 2 matrices están vacías ==> son iguales
00218     }
00219     const unsigned MxN = o.m_rows * o.m_cols;
00220     typename Matrix_BASE<E>::value_type *pSelf = this->m_val;
00221     typename Matrix_BASE<E>::value_type *pO    = o.m_val;
00222     typename Matrix_BASE<E>::value_type *pEND  = &m_val[MxN];
00223     for (; pSelf != pEND; ++pSelf, ++pO) {
00224         if (*pSelf != *pO) {
00225             return false;
00226         }
00227     }
00228     return true;
00229 }
00230 
00231 /// \copydoc Matrix_BASE::copy()
00232 template <class E>
00233 Matrix_Dense<E>& Matrix_Dense<E>::copy( const Matrix_Dense<E> &o ) {
00234     if (this == &o) { // evita auto-borrado
00235         return *this;
00236     } else if (o.m_val == 0) {
00237         if (m_val != 0) {
00238             delete [] m_val;
00239             m_rows = m_cols = 0;
00240             m_val = 0;
00241         }
00242         return *this;
00243     }
00244     // se asegura de que las dos matrices son del mismo tamaño
00245      const unsigned MxN = o.m_rows * o.m_cols;
00246      if (MxN != m_rows * m_cols) { // truco para evitar borrar la memoria dinámica
00247         delete [] m_val;
00248         m_val = new typename Matrix_BASE<E>::value_type [MxN];
00249     }
00250     m_rows = o.m_rows;
00251     m_cols = o.m_cols;
00252 
00253     // como las matrices son del mismo tamaño,
00254     // basta copiarlas entrada por entrada.
00255 
00256     typename Matrix_BASE<E>::value_type *pSelf = this->m_val;
00257     typename Matrix_BASE<E>::value_type *pO    = o.m_val;
00258     typename Matrix_BASE<E>::value_type *pEND  = &m_val[MxN];
00259     for (; pSelf != pEND; ++pSelf, ++pO) {
00260         *pSelf = *pO;
00261     }
00262     return *this;
00263 }
00264 
00265 /// \copydoc Matrix_BASE::move()
00266 template <class E>
00267 Matrix_Dense<E>& Matrix_Dense<E>::move( Matrix_Dense<E> &o ) {
00268     if (this == &o) { // evita auto-borrado
00269         return *this;
00270     } else if (o.m_val == 0) {
00271         if (m_val != 0) {
00272             delete [] m_val;
00273             m_rows = m_cols = 0;
00274             m_val = 0;
00275         }
00276         return *this;
00277     } else if ( m_val != 0 ) {
00278         delete [] m_val;
00279     }
00280     m_val = o.m_val;   // me robo los valores de "o"
00281     m_rows = o.m_rows;
00282     m_cols = o.m_cols;
00283 
00284     o.m_rows = o.m_cols = 0;
00285     o.m_val = 0;
00286     return *this;
00287 }
00288 
00289 /// \copydoc Matrix_BASE::swap()
00290 template <class E>
00291 inline Matrix_Dense<E>& Matrix_Dense<E>::swap( Matrix_Dense<E> &o ) {
00292     std::swap( this->m_val  , o.m_val  );
00293     std::swap( this->m_rows , o.m_rows );
00294     std::swap( this->m_cols , o.m_cols );
00295     return *this;
00296 }
00297 
00298 /// \copydoc Matrix_BASE::clear()
00299 template <class E>
00300 inline void Matrix_Dense<E>::clear( ) {
00301     clear_Matrix( *this );
00302 }
00303 
00304 /// \copydoc Matrix_BASE::reSize()
00305 template <class E>
00306 void Matrix_Dense<E>::reSize(unsigned m, unsigned n) {
00307      const unsigned MxN = m * n;
00308     if (MxN == 0) {
00309         if (m_val != 0) { // sólo borra si hay algo que borrar
00310             delete [] m_val;
00311             m_rows = m_cols = 0;
00312             m_val = 0;
00313         }
00314     }
00315     else if ( MxN == m_rows * m_cols ) {
00316         // truco para evitar borrar la memoria dinámica
00317         m_rows = m;
00318         m_cols = n;
00319      }
00320      else {
00321         if (m_val != 0) {
00322             delete [] m_val;
00323         }
00324         m_val = new typename Matrix_BASE<E>::value_type [MxN] ;
00325         m_rows = m;
00326         m_cols = n;
00327     }
00328     return;
00329 
00330 /*  NOTA
00331     Esta es la antigua especificación de reSize(). Es incorrecta
00332     porque presume que el Rep de la matriz es un vector denso en
00333     donde están almacenados todos los valores de la matriz:
00334 
00335     +----------------------------------------------------------+
00336     | reSize(): Le cambia las dimensiones a la matriz.         |
00337     | ========                                                 |
00338     | - Si ocurre que (m*n) == rows() * cols() los valores de  |
00339     |   la matriz se mantienen, aunque cambian sus dimensiones.|
00340     | - Si (m*n) != rows() * cols() los valores de la matriz   |
00341     |   quedarán inicializados de la misma forma en que los    |
00342     |   inicializaría CERO == Sparse_Matrix<E>::value_type().  |
00343     |                                                          |
00344     | \pre (m > 0) && (n > 0)                                  |
00345     +----------------------------------------------------------+
00346 
00347     En la actual especificación, que ya está corregida, no queda
00348     implícita la presunción sobre cómo está organizada internamente
00349     la matriz. Por eso, esta nueva especificación sí sirve para una
00350     matriz implementada con un vector denso de valores, o para la
00351     matriz implementada como una matriz rala.
00352 
00353     Estos pequeños detalles en algunas ocasiones surgen cuando el
00354     programador de una clase introduce mejoras o modificaciones, pues
00355     muchas veces es muy difícil o prácticamente imposible predecir
00356     todos los pormenores y detalles de una especificación o de una
00357     implementación.
00358 */
00359 }
00360 
00361 /// \copydoc Matrix_BASE::reShape()
00362 template <class E>
00363 void Matrix_Dense<E>::reShape(unsigned m, unsigned n) {
00364      const unsigned MxN = m * n;
00365      if (MxN == m_rows * m_cols) {
00366         m_rows = m;
00367         m_cols = n;
00368     }
00369 }
00370 
00371 /// \copydoc Matrix_BASE::operator()(unsigned,unsigned) const
00372 template <class E>
00373 inline const E& Matrix_Dense<E>::operator()(unsigned i, unsigned j) const {
00374     assert( "Matrix_Dense<E>::operator()()" && (i < rows()) );
00375     assert( "Matrix_Dense<E>::operator()()" && (j < cols()) );
00376 
00377     return m_val[ (i * m_cols) + j ] ; // almacena los valores por filas
00378 //  return m_val[ i + (j * m_rows) ] ; // almacena los valores por columnas
00379 }
00380 
00381 /// \copydoc const_reference Matrix_BASE<E>::operator()(unsigned,unsigned)
00382 template <class E>
00383 inline E& Matrix_Dense<E>::operator()(unsigned i, unsigned j) {
00384     assert( "Matrix_Dense<E>::operator()()" && (i < rows()) );
00385     assert( "Matrix_Dense<E>::operator()()" && (j < cols()) );
00386 
00387     return m_val[ (i * m_cols) + j ] ; // almacena los valores por filas
00388 //  return m_val[ i + (j * m_rows) ] ; // almacena los valores por columnas
00389 }
00390 
00391 /// \copybrief   Matrix_BASE<E>::add_Matrix()
00392 /// \copydetails Matrix_BASE<E>::add_Matrix()
00393 template <class T>
00394 void add_Matrix( Matrix_Dense<T>& Res, const Matrix_Dense<T> & M ) {
00395     // verifica que las dos matrices sean del mismo tamaño
00396     assert( "Matrix_Dense<E>::add()" && ( Res.rows() == M.rows() ) );
00397     assert( "Matrix_Dense<E>::add()" && ( Res.cols() == M.cols() ) );
00398 
00399     // Como las matrices son del mismo tamaño basta sumarlas entrada por entrada.
00400     
00401     T *pRes =   Res.m_val;
00402     T *pM   = & M.m_val[0];
00403     T *pEND = & Res.m_val[M.m_cols * M.m_rows];
00404     for ( ; pRes != pEND; ++pRes, ++pM ) {
00405         *pRes += *pM;
00406     }
00407     return;
00408 }
00409 
00410 #if 0 // evita que esta implementación sea compilada
00411 /*  NOTA
00412     Como esta rutina no está declarada, en la implementación
00413     de la resta se usa la función substract_Matrix() definida
00414     en Matrix_BASE.h, que es la versión genérica.
00415 
00416     Las funciones add_Matrix() y substract_Matrix() son ejemplo
00417     de que es posible redefinir selectivamente algunas de las
00418     implementaciones genéricas que aparecen en la clase base, que
00419     en este caso es Matrix_BASE<>.
00420 */
00421 /// \copydoc Matrix_BASE::substract()
00422 template <class T>
00423 void substract_Matrix( Matrix_Dense<T>& Res, const Matrix_Dense<T> & M ) {
00424     // verifica que las dos matrices sean del mismo tamaño
00425     assert( "Matrix_Dense<E>::substract()" && ( Res.rows() == M.rows() ) );
00426     assert( "Matrix_Dense<E>::substract()" && ( Res.cols() == M.cols() ) );
00427 
00428     // Como las matrices son del mismo tamaño basta restarlas entrada por entrada.
00429 
00430     typename Matrix_BASE<T>::value_type *pRes =   Res.m_val;
00431     typename Matrix_BASE<T>::value_type *pM   = & M.m_val[0];
00432     typename Matrix_BASE<T>::value_type *pEND = & Res.m_val[M.m_cols * M.m_rows];
00433     for ( ; pRes != pEND; ++pRes, ++pM ) {
00434         *pRes -= *pM;
00435     }
00436     return;
00437 }
00438 #endif
00439 
00440 } // namespace Mx
00441 
00442 #ifdef Spanish_dox
00443    /// \c "Doxygen: Documentación en español"
00444     #define Spanish_dox "Doxygen: Documentación en español"
00445    /// \def   Matrix_Dense_h
00446    /// \brief Evita la inclusión múltiple.
00447 #endif
00448 #ifdef English_dox
00449    /// "Doxygen: English documentation"
00450     #define   English_dox   "Doxygen: English documentation"
00451    /// \def   Matrix_Dense_h
00452    /// \brief Avoids multiple inclusion.
00453 #endif
00454 
00455 #endif // Matrix_Dense_h
00456 
00457 // EOF: Matrix_Dense.h