Abstract non Polymorphyc Matrix:
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines
Matrix_List.h
Go to the documentation of this file.
00001 // Matrix_List.h Copyright (C) 2009  adolfo@di-mare.com
00002 
00003 #ifdef Spanish_dox
00004 /** \file  Matrix_List.h
00005     \brief Declaraciones y definiciones para la clase \c Matrix_List<>.
00006     \author Adolfo Di Mare <adolfo@di-mare.com>
00007     \date   2004
00008     - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
00009 */
00010 #endif
00011 #ifdef English_dox
00012 /** \file  Matrix_List.h
00013     \brief Declarations and definitiones for class \c Matrix_List<>.
00014     \author Adolfo Di Mare <adolfo@di-mare.com>
00015     \date   2004
00016     - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
00017 */
00018 #endif
00019 
00020 #include "Matrix_BASE.h"
00021 
00022 #include <list>
00023 #include <vector>
00024 
00025 namespace Mx {
00026 
00027 template <class E>
00028 class Matrix_List_ColVal {
00029     template <class T> friend class Matrix_List;
00030 private:
00031     unsigned m_col;
00032     E        m_val;
00033 private:
00034     /// Constructor.
00035     Matrix_List_ColVal( unsigned col , const E& val )
00036         : m_col( col ) , m_val( val ) { }
00037 public:
00038     ~Matrix_List_ColVal() { } //< Destructor.
00039 };
00040 
00041 #ifdef Spanish_dox
00042 /** \class Matrix_List_ColVal
00043     \brief Clase privada para implementar la lista de valores de cada fila.
00044     \var   Matrix_List_ColVal::m_col;
00045     \brief Columna del valor almacenado en la matriz.
00046     \var   Matrix_List_ColVal::m_val;
00047     \brief Valor almacenado en la matriz.
00048 */
00049 #endif
00050 #ifdef English_dox
00051 /** \class Matrix_List_ColVal
00052     \brief Private class used to implement the list of values for each row.
00053     \var   Matrix_List_ColVal::m_col
00054     \brief Column o the value stored in the matrix.
00055     \var   Matrix_List_ColVal::m_val
00056     \brief Value stored in the matrix.
00057 */
00058 #endif
00059 
00060 
00061 #ifdef Spanish_dox
00062 /// Matriz muy chirrisquitica almacenada como matriz rala implementada con listas.
00063 #endif
00064 #ifdef English_dox
00065 /// Chirrisquitica matrix stored as a sparse matrix implemented with lists.
00066 #endif
00067 /// \copydetails Matrix_BASE
00068 template <class E>
00069 class Matrix_List : public Matrix_BASE<E> {
00070 public:
00071     Matrix_List(unsigned m = 1, unsigned n = 1);
00072     Matrix_List(const Matrix_List& o);
00073     /// \copydoc Matrix_BASE::Matrix_BASE(const E&)
00074     Matrix_List(const E& V)
00075         : Matrix_BASE<E>() , m_same()
00076         { reSize(1,1); (*this)(0,0) = V; }
00077     ~Matrix_List(); ///< Destructor.
00078 public:
00079     unsigned rows()  const { return static_cast<unsigned>(m_VL.size()); }
00080     unsigned cols()  const { return m_cols; }
00081     unsigned size()  const { return rows() * m_cols; }
00082     unsigned count() const { return size(); }
00083     unsigned capacity() const { return size(); }
00084 public:
00085     Matrix_List& operator= (const Matrix_List &o) { return copy(o); }
00086     Matrix_List& copy( const Matrix_List &o );
00087     Matrix_List& move( Matrix_List &o );
00088     Matrix_List& swap( Matrix_List &o );
00089     void clear();
00090 public:
00091     bool equals( const Matrix_List & o ) const;
00092 public:
00093     E& operator()(unsigned, unsigned);
00094     const E& operator()(unsigned, unsigned) const;
00095     E& at(unsigned i, unsigned j) { return at_Matrix(*this,i,j); }
00096     const E& at(unsigned i, unsigned j) const { return at_Matrix(*this,i,j); }
00097 
00098     void reShape(unsigned m, unsigned n);
00099     void reSize( unsigned m, unsigned n);
00100     void transpose();
00101 
00102     void setDefault(const E& same);
00103     const E& getDefault();
00104 public:
00105     template <class T> friend bool  check_ok( const Matrix_List<T>& M );
00106     template <class T> friend class test_Matrix; ///< BUnit test.
00107 private:
00108     std::vector< std::list < Matrix_List_ColVal< E > > > m_VL; // filas
00109     unsigned  m_cols; // # cols
00110     E         m_same; // valor por defecto
00111 private:
00112     void reserve(unsigned n);
00113     void reSize(unsigned newsize);
00114 }; // Matrix_List
00115 
00116 #ifdef Spanish_dox
00117 /**
00118     \var     Matrix_List::m_VL;
00119     \brief   Vector en donde están almacenados los valores de la lista de columnas.
00120 
00121     \var     Matrix_List::m_cols;
00122     \brief   Cantidad de columnas de la matriz.
00123 
00124     \var     Matrix_List::m_same;
00125     \brief   Valor almacenado en la mayor parte de la \c Matrix_List.
00126 */
00127 #endif
00128 #ifdef English_dox
00129 /**
00130     \var     Matrix_List::m_VL;
00131     \brief   Vector where the column list values are stored.
00132     \var     Matrix_List::m_cols;
00133     \brief   Number of columns in the matrix.
00134     \var     Matrix_List::m_same;
00135     \brief   Most common value stored in the \c Matrix_List.
00136 */
00137 #endif
00138 
00139 #ifdef Spanish_dox
00140 /** \copydoc check_ok_Matrix(const MAT&)
00141     \brief   Verifica la invariante de la clase.
00142 
00143     - El campo \c m_same indica cuál es el valor que se repite más en toda la matriz.
00144     - Usualmente \c m_same es el neutro aditivo \c value_type().
00145     - No existe un constructor explícito para darle a \c m_same su valor inicial, que
00146       es siempre inicializado en \c value_type(). Para cambiarlo es necesario invocar
00147       el método \c setgetDefault().
00148     - El vector \c m_VL[] contiene las listas de valores almacenados en la matriz.
00149       Cualquiera de estas listas puede estar vacía; aún todas pueden ser listas vacías.
00150     - La cantidad de columnas de la matriz es el valor fijo es \c m_cols.
00151     - El largo de las listas de valores cambia cuando se hace referencia a un valor M(i,j)
00152       mediante la versión que no es \c const del \c operator()(i,j). O sea, que es
00153       ese método el encargado de agregar valores en \c m_VL[], pues el operador
00154       homónimo \c const operator()(i,j) nunca agrega nada y, como es \c const, en
00155       general retorna una referencia constante a \c m_same.
00156     - Es posible que la matriz tenga dimensiones nulas, lo que implica que el vector
00157       \c m_VL[] está vacío.
00158     - No hace falta alacenar la cantidad de valores de la matriz porque se siempre es
00159       \c m_VL.size().
00160       el valor \c 0 (cero) al campo \c m_capacity.
00161 
00162     \par <em>Rep</em> Modelo de la clase
00163 \code
00164 m_VL<list<>>  _______
00165     +---+    /       \
00166   0 | *-|---| 1 , 'a' |
00167     +---+    \_______/                      0 1 2 3 4 5 6
00168   1 | ? |   M(0,1)=='a'                 0 / - a - - - - - \
00169     +---+                               1 | - - - - - - - |
00170   2 | ? |     _______       _______     2 | - - - - - - - |
00171     +---+    /       \     /       \    3 | - c - - - b - |
00172   3 | *-|---| 5 , 'b' |---| 1 , 'c' |   4 \ - - - - - - - /
00173     +---+    \_______/     \_______/
00174   4 | ? |   M(3,5)=='b'   M(3,1)=='c'
00175     +---+
00176         m_same == '-'    rows() == m_VL.size()  m_cols == 7
00177 \endcode
00178     - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep
00179     \remark
00180     Libera al programador de implementar el método \c Ok()
00181     - http://www.di-mare.com/adolfo/binder/c04.htm#sc11
00182 */
00183 #endif
00184 #ifdef English_dox
00185 #endif
00186 template<class T>
00187 bool check_ok( const Matrix_List<T>& M ) {
00188     if ( ! check_ok_Matrix( M )  ) {
00189         return false;
00190     }
00191     if ( M.m_cols == 0 ) { // m_cols es el "marcador" que determina el valor de los demás
00192         if ( ! M.m_VL.empty() ) {
00193             return false; /// - check_ok(): <code>(m_cols == 0) <==> (m_VL.empty())</code>
00194         }
00195     }
00196 
00197     if ( ! check_ok( M.m_same ) ) {
00198         return false; /// - check_ok(): <code>check_ok( M.m_same )</code>
00199     }
00200     return true;
00201 }
00202 
00203 
00204 #ifdef Spanish_dox
00205 /**
00206     \fn    Matrix_List::reserve(unsigned);
00207     \brief Ajusta la matriz para que pueda almacenar al menos
00208            \n valores diferentes a \c getDefault().
00209 */
00210 #endif
00211 #ifdef English_dox
00212 /**
00213     \fn    Matrix_List::reserve(unsigned);
00214     \brief Adjust the matrix so that it can store at least
00215            \n values different than \c getDefault().
00216 */
00217 #endif
00218 
00219 /// \copydoc Matrix_BASE::Matrix_BASE(unsigned,unsigned)
00220 template <class E>
00221 Matrix_List<E>::Matrix_List(unsigned m, unsigned n)
00222     : m_VL(), m_cols(n), m_same()
00223 {
00224     if (m == 0 || n == 0) {
00225         m_cols = 0;
00226     }
00227     else {
00228         reSize(m,n);
00229     }
00230 //  m_same = E(); // Usa el número "cero" como neutro tipo "E"
00231 }
00232 
00233 /// \copydoc Matrix_BASE::Matrix_BASE(const Matrix_BASE&)
00234 template <class E>
00235 inline Matrix_List<E>::Matrix_List(const Matrix_List<E>& o) {
00236     copy( o );
00237     return;
00238 }
00239 
00240 template <class E>
00241 inline Matrix_List<E>::~Matrix_List() { }
00242 
00243 /// \copydoc Matrix_BASE::equals()
00244 template <class E>
00245 inline bool Matrix_List<E>::equals( const Matrix_List & o ) const {
00246     return equals_Matrix( *this, o );
00247 }
00248 
00249 /// \copydoc Matrix_BASE::copy()
00250 template <class E>
00251 Matrix_List<E>& Matrix_List<E>::copy( const Matrix_List<E> &o ) {
00252     if (this == &o) { // evita auto-borrado
00253         return *this;
00254     }
00255     this->m_VL   = o.m_VL;
00256     this->m_cols = o.m_cols;
00257     this->m_same = o.m_same;
00258     return *this;
00259 }
00260 
00261 /// \copydoc Matrix_BASE::move()
00262 template <class E>
00263 Matrix_List<E>& Matrix_List<E>::move( Matrix_List<E> &o ) {
00264     if (this == &o) { // evita auto-borrado
00265         return *this;
00266     }
00267     if ( m_VL.size() != o.m_VL.size() ) {
00268         m_VL.clear();
00269         m_VL.resize( o.m_VL.size() );
00270     }
00271     assert( m_VL.size() == o.m_VL.size() );
00272     for ( int i=0; i<m_VL.size(); ++i ) {
00273         this->m_VL[i].clear();
00274         this->m_VL[i].splice( m_VL[i].begin(), o.m_VL[i] );
00275     }
00276     this->m_cols = o.m_cols;
00277     this->m_same = o.m_same;
00278     return *this;
00279 }
00280 
00281 /// \copydoc Matrix_BASE::swap()
00282 template <class E>
00283 Matrix_List<E>& Matrix_List<E>::swap( Matrix_List<E> &o ) {
00284     std::swap( this->m_VL   , o.m_VL   );
00285     std::swap( this->m_cols , o.m_cols );
00286     std::swap( this->m_same , o.m_same );
00287     return *this;
00288 }
00289 
00290 /// \copydoc Matrix_BASE::clear()
00291 template <class E>
00292 void Matrix_List<E>::clear() {
00293     m_VL.clear();
00294     m_VL.push_back( std::list < Matrix_List_ColVal< E > >() );
00295     m_cols = 1;
00296     m_same = E(); // typename Matrix_BASE::value_type();
00297 }
00298 
00299 /// \copydoc Matrix_BASE::reSize()
00300 template <class E>
00301 void Matrix_List<E>::reSize(unsigned m, unsigned n) {
00302     unsigned rows = m_VL.size();
00303     if ( m > rows ) {
00304         std::vector< std::list < Matrix_List_ColVal< E > > > TMP(m);
00305         // TMP.resize(m);
00306         for ( unsigned i=0 ; i<rows ; ++i ) { // recuerda filas
00307             TMP[i].splice( TMP[i].begin(), this->m_VL[i] );
00308         }
00309         this->m_VL.resize(m); // reinstala las filas anteriores
00310         for ( unsigned i=0 ; i<rows ; ++i ) {
00311             this->m_VL[i].splice( this->m_VL[i].begin() , TMP[i] );
00312         }
00313     }
00314     else if ( m < rows ) { // desecha las filas restantes
00315         this->m_VL.resize(m);
00316     }
00317         assert( m_VL.size() == m );
00318     if ( n < m_cols ) { // desecha valores en columnas mayores a "n"
00319         rows = m_VL.size();
00320         for ( unsigned i=0 ; i<rows ; ++i ) {
00321             typedef typename std::list < Matrix_List_ColVal< E > >::iterator ITR;
00322             ITR it = this->m_VL[i].begin();
00323             while ( it != this->m_VL[i].end() ) {
00324                 if ( it->m_col >= n ) {
00325                     it = this->m_VL[i].erase( it );
00326                 }
00327                 else {
00328                     ++it;
00329                 }
00330             }
00331         }
00332     }
00333     m_cols = n;
00334     return;
00335 }
00336 
00337 /// \copydoc Matrix_BASE::reShape()
00338 template <class E>
00339 void Matrix_List<E>::reShape(unsigned m, unsigned n) {
00340     if ( m * n == m_VL.size() * m_cols ) {
00341         reSize(n,m);
00342     }
00343 }
00344 
00345 /// \copydoc Matrix_BASE::operator()(unsigned,unsigned) const
00346 template <class E>
00347 inline const E& Matrix_List<E>::operator()(unsigned i, unsigned j) const {
00348     assert( "Matrix_List<E>::operator()()" && (i < rows()) );
00349     assert( "Matrix_List<E>::operator()()" && (j < cols()) );
00350 
00351     typedef typename std::list < Matrix_List_ColVal< E > >::const_iterator ITR;
00352     ITR it = this->m_VL[i].begin();
00353     while ( it != this->m_VL[i].end() ) {
00354         if ( it->m_col == j ) {
00355             break;
00356         }
00357         ++it;
00358     }
00359     if ( it == this->m_VL[i].end() ) {
00360         return m_same;
00361     }
00362     else {
00363         return it->m_val;
00364     }
00365 
00366 /*  NOTA
00367     Como este método es "const", de antemano se sabe que el programador no puede
00368     usarlo para modificar el valor de la matriz. Por eso, aunque el valor
00369     retornado sea una referencia a valor común por defecto m_same, de antemano
00370     el compilador asegura que ese valor no será modificado.
00371 
00372     Sin embargo, cuando el programador usa el método homónimo \c operator()(i,j)
00373     que no es \c "const", es posible que el valor retornado sí sea modificado.
00374     En ese caso, ya no es correcto retornar una referencia al valor común \c "m_same".
00375     - Por eso, cuando se usa el hace referencia en el otro \c operator()(i,j) es
00376       necesario agregar una entrada en los vectores paralelos en aquellos casos
00377       en que no existe un valor diferente a \c "m_same" para \c (i,j).
00378     - Esto quiere decir que sí es posible que al utilizar la versión modificable
00379       de \c operator()(i,j) quede en el vector "m_VL[]" un valor que es igual a
00380       "m_same". En el caso peor, podría ocurrir que todos los valores almacenados
00381       en el vector \c "m_VL[]" sean todos iguales a \c "m_same".
00382     - Una forma de corregir esta anomalía es "revisar después" si existe un valor
00383       en el vector \c "m_VL[]" que es igual a "m_same". Una forma eficiente de
00384       hacerlo es mantener el el Rep un puntero "m_last_change" que apunte al
00385       último valor \c "m_VL[]" que la versión modificable de \c operator()(i,j) retornó.
00386       En la siguiente invocación a \c operator()(i,j), se puede verificar si hubo un
00387       ese valor anterior fue cambiado de manera que tiene almacenado \c "m_same".
00388 */
00389 }
00390 
00391 /// \copydoc Matrix_BASE::operator()(unsigned,unsigned)
00392 template <class E>
00393 inline E& Matrix_List<E>::operator()(unsigned i, unsigned j) {
00394     assert( "Matrix_List<E>::operator()()" && (i < rows()) );
00395     assert( "Matrix_List<E>::operator()()" && (j < cols()) );
00396 
00397     // Busca al elemento M(i,j)
00398     typedef typename std::list < Matrix_List_ColVal< E > >::iterator ITR;
00399     ITR it = this->m_VL[i].begin();
00400     while ( it != this->m_VL[i].end() ) {
00401         if ( it->m_col == j ) {
00402             break;
00403         }
00404         ++it;
00405     }
00406     if ( it == this->m_VL[i].end() ) { // lo agrega porque no estaba
00407         this->m_VL[i].push_front( Matrix_List_ColVal< E >(j,m_same) );
00408         it = this->m_VL[i].begin();
00409     }
00410     return it->m_val;
00411 }
00412 
00413 /// \copydoc Matrix_BASE::getDefault()
00414 template<class E>
00415 inline const E& Matrix_List<E>::getDefault() {
00416     return m_same;
00417 }
00418 
00419 /// \copydoc Matrix_BASE::setDefault()
00420 template<class E>
00421 inline void Matrix_List<E>::setDefault(const E& same) {
00422     if ( m_same != same ) {
00423         clear();
00424         m_same = same;
00425     }
00426 }
00427 
00428 } // namespace Mx
00429 
00430 #ifndef   Matrix_List_h
00431 #define   Matrix_List_h   // Evita la inclusión múltiple
00432 
00433 #ifdef Spanish_dox
00434    /// \c "Doxygen: Documentación en español"
00435     #define Spanish_dox "Doxygen: Documentación en español"
00436    /// \def   Matrix_List_h
00437    /// \brief Evita la inclusión múltiple.
00438 #endif
00439 #ifdef English_dox
00440    /// "Doxygen: English documentation"
00441     #define   English_dox   "Doxygen: English documentation"
00442    /// \def   Matrix_List_h
00443    /// \brief Avoids multiple inclusion.
00444 #endif
00445 
00446 #endif // Matrix_List_h
00447 
00448 // EOF: Matrix_List.h