La Matriz Abstracta no Polimorfica:
|
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