Abstract non Polymorphyc Matrix:
|
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