Uso de Mx::Matrix:
 Todo Clases Namespaces Archivos Funciones Variables 'typedefs' Amigas 'defines'
Matrix_List.h
Ir a la documentación de este archivo.
1 // Matrix_List.h Copyright (C) 2004 adolfo@di-mare.com
2 
3 /** \file Matrix_List.h
4  \brief Declaraciones y definiciones para la clase \c Matrix_List.
5 
6  \author Adolfo Di Mare <adolfo@di-mare.com>
7  \date 2004
8 
9  - Why English names??? ==> http://www.di-mare.com/adolfo/binder/c01.htm#sc04
10 */
11 
12 #ifndef Matrix_List_h
13 #define Matrix_List_h
14 
15 #include <cassert> // assert()
16 #include <list>
17 #include <vector>
18 
19 /// Definido por la biblioteca C++ estándar
20 namespace std {} // Está acá para que Doxygen lo documente
21 
22 /// Matriz chirrisquitica de adolfo@di-mare.com
23 namespace Mx {
24 
25 /// Clase privada para implementar la lista de valores de cada fila.
26 template <class E>
28  template <class T> friend class Matrix_List;
29 private:
30  unsigned m_col; ///< Columna del valor almacenado en la matriz.
31  E m_val; ///< Valor almacenado en la matriz.
32 private:
33  /// constructor
34  Matrix_List_ColVal( unsigned col , const E& val )
35  : m_col( col ) , m_val( val ) { }
36 public:
37  ~Matrix_List_ColVal() { } //< Destructor.
38 };
39 
40 /** Esta es una clase matriz muy chirrisquitica almacenada como una matriz rala implementada con listas.
41  - La matriz tiene tamaño \c rows() x \c cols().
42  - Se le puede cambiar el tamaño dinámicamente con el método \c reSize().
43  - La clase \c E debe incluir un neutro para la adición, cuyo valor debe poderse
44  obtener invocando el convertidor \c Matrix_List<E>::value_type().
45  - Las operaciones aritméticas "+" "-" "*" deben estar definidas para
46  \c Matrix_List<E>::value_type y debe existir el valor \c Matrix_List<E>::value_type().
47  \see http://www.oonumerics.org/oon/
48 */
49 template <class E>
50 class Matrix_List {
51 public:
52  /// Tipo del objeto almacenado, similar al nombre usado en STL
53  typedef E value_type;
54  /// Tipo del objeto almacenado, similar al nombre usado en STL
56  /// Tipo del objeto almacenado, similar al nombre usado en STL
57  typedef const value_type& const_reference;
58  /// Tipo del tamaño de un objeto, similar al nombre usado en STL
59  typedef unsigned size_type;
60 public:
61  Matrix_List(unsigned m = 1, unsigned n = 1);
62  Matrix_List(const Matrix_List& o); ///< Constructor de copia
63  /// Matriz escalar de valor \c V.
64  Matrix_List(const value_type V) : m_same() { reSize(1,1); (*this)(0,0) = V; }
65  ~Matrix_List();
66 public:
67  unsigned rows() const { return m_VL.size(); } ///< Cantidad de filas de la matriz
68  unsigned cols() const { return m_cols; } ///< Cantidad de columnas de la Matriz
69  unsigned size() const { return rows() * m_cols; } ///< Cantidad de valores almacenados en la matriz
70  unsigned count() const { return size(); } ///< Cantidad de valores almacenados en la matriz
71  /// Cantidad máxima posible de valores diferentes que pueden ser almacenados en la matriz
72  size_type capacity() const { return size(); }
73 public:
74  Matrix_List& operator= (const Matrix_List &o) { return copy(o); } ///< Sinónimo de \c this->copy(o)
75  Matrix_List& copy( const Matrix_List &o );
78 public:
79  /// ¿¿¿ (p == q) ???
80  friend bool operator == (const Matrix_List &p, const Matrix_List &q) { return p.equals(q); }
81  /// ¿¿¿ (p != q) ???
82  friend bool operator != (const Matrix_List &p, const Matrix_List &q) { return !(p==q); }
83  bool equals( const Matrix_List & o ) const; ///< ¿¿¿ (*this==o) ???
84  /// Retorna \c true si \c "o" comparte sus valores con \c "*this"
85  bool same( const Matrix_List & o ) const { return this == &o; }
86 private:
87  void add( const Matrix_List & );
88  void substract( const Matrix_List & );
89  void multiply( const Matrix_List &, const Matrix_List & );
90 public:
91  friend Matrix_List operator + (const Matrix_List& A, const Matrix_List& B)
92  { Matrix_List Res = A; Res.add(B); return Res; } ///< Retorna \c A+B
93  friend Matrix_List operator - (const Matrix_List& A, const Matrix_List& B)
94  { Matrix_List Res = A; Res.substract(B); return Res; } ///< Retorna \c A-B
95  friend Matrix_List operator * (const Matrix_List& A, const Matrix_List& B)
96  { Matrix_List Res; Res.multiply(A, B); return Res; } ///< Retorna \c A*B
97 public:
98  reference operator () (unsigned, unsigned);
99  const_reference operator () (unsigned, unsigned) const;
100 public:
101  void reSize( unsigned, unsigned);
102  void reShape(unsigned, unsigned);
103 public:
104  void setDefault(const E& same);
105  /// Valor almacenado en la mayor parte de la \c Matrix_List
106  const E& getDefault() { return m_same; }
107  /// Ajusta la matriz para que pueda almacenar \c n valores diferentes a \c getDefault().
108  void reserve(size_type _Count);
109  void reSize(unsigned newsize);
110  void clear();
111 
112  template<class T> friend bool check_ok( const Matrix_List<T>& M );
113  template<class T> friend class test_Matrix_List; ///< Datos de prueba para la clase
114 private:
115  std::vector< std::list < Matrix_List_ColVal< E > > > m_VL; ///< Vector que contiene la lista de valores de las columnas.
116  unsigned m_cols; ///< Cantidad de columnas de la matris
117  E m_same; ///< Valor almacenado en la mayor parte de la \c Matrix_List
118 }; // Matrix_List
119 
120 /** Verifica la invariante de la clase.
121  - El campo \c m_same indica cuál es el valor que se repite más en toda la matriz.
122  - Usualmente \c m_same es el neutro aditivo \c value_type().
123  - No existe un constructor explícito para darle a \c m_same su valor inicial, que
124  es siempre inicializado en \c value_type(). Para cambiarlo es necesario invocar
125  el método \c setgetDefault().
126  - El vector \c m_VL[] contiene las listas de valores almacenados en la matriz.
127  Cualquiera de estas listas puede estar vacía; aún todas pueden ser listas vacías.
128  - La cantidad de columnas de la matriz es el valor fijo es \c m_cols.
129  - El largo de las listas de valores cambia cuando se hace referencia a un valor M(i,j)
130  mediante la versión que no es \c const del \c operator()(i,j). O sea, que es
131  ese método el encargado de agregar valores en \c m_VL[], pues el operador
132  homónimo \c const operator()(i,j) nunca agrega nada y, como es \c const, en
133  general retorna una referencia constante a \c m_same.
134  - Es posible que la matriz tenga dimensiones nulas, lo que implica que el vector
135  \c m_VL[] está vacío.
136  - No hace falta alacenar la cantidad de valores de la matriz porque se siempre es
137  \c m_VL.size().
138  el valor \c 0 (cero) al campo \c m_capacity.
139 
140  \par <em>Rep</em> Modelo de la clase
141 \code
142 m_VL<list<>> _______
143  +---+ / \
144  0 | *-|---| 1 , 'a' |
145  +---+ \_______/ 0 1 2 3 4 5 6
146  1 | ? | M(0,1)=='a' 0 / - a - - - - - \
147  +---+ 1 | - - - - - - - |
148  2 | ? | _______ _______ 2 | - - - - - - - |
149  +---+ / \ / \ 3 | - c - - - b - |
150  3 | *-|---| 5 , 'b' |---| 1 , 'c' | 4 \ - - - - - - - /
151  +---+ \_______/ \_______/
152  4 | ? | M(3,5)=='b' M(3,1)=='c'
153  +---+
154  m_same == '-' rows() == m_VL.size() m_cols == 7
155 \endcode
156  - http://www.di-mare.com/adolfo/binder/c03.htm#k1-Rep
157  \remark
158  Libera al programador de implementar el método \c Ok()
159  - http://www.di-mare.com/adolfo/binder/c04.htm#sc11
160 */
161 template<class T>
162 bool check_ok( const Matrix_List<T>& M ) {
163  if ( ! (&M != 0 ) ) {
164  /// - Invariante: ningún objeto puede estar almacenado en la posición nula.
165  return false;
166  }
167  if ( M.m_cols == 0 ) { // m_cols es el "marcador" que determina el valor de los demás
168  if ( ! M.m_VL.empty() ) {
169  return false; /// - Invariante: <code>(m_cols == 0) <==> (m_VL.empty())</code>
170  }
171  }
172 
173  if ( ! check_ok( M.m_same ) ) {
174  return false; /// - Invariante: <code>check_ok( M.m_same )</code>
175  }
176  for (unsigned i=0; i<M.rows(); ++i) {
177  for (unsigned j=0; j<M.cols(); ++j) {
178  if ( ! check_ok( M(i,j) ) ) {
179  return false; /// - Invariante: <code>check_ok( M(i,j) )</code>
180  }
181  }
182  }
183  return true;
184 }
185 
186 /// Define el escalar que por defecto está en todas las entradas de la \c Matrix_List.
187 /// - Si <code>same != getDefault()</code> la matriz queda vacía.
188 /// - De lo contrario, nada ocurre.
189 template<class E>
190 inline void Matrix_List<E>::setDefault(const E& same) {
191  if ( m_same != same ) {
192  m_same = same;
193  }
194 }
195 /** \fn template <class E>inline Matrix_List<E>::Matrix_List(const value_type V);
196 
197  \brief Constructor a partir de \c Matrix_List<E>::value_type(V).
198 
199  - La matriz resultante es una matriz escalar, de dimensiones 1x1,
200  y su valor es \c "V"
201 */
202 
203 /** Constructor de vector.
204  - Obtiene suficiente memoria dinámica para almacenas los
205  <code> n * m </code> valores de la matriz.
206  - Si \c "value_type" tiene un constructor de vector, lo
207  usar para inicializar cada uno de los valores de la matriz;
208  de lo contrario, los deja tal cual están en la memoria.
209  - Si \c "value_type" es uno de los tipos escalares básicos,
210  como lo son \c int o \c float, los valores almacenados
211  en la matriz quedan tal cual están y no son inicializados.
212  \pre
213  - <code> m * n > 0 </code>
214  - <code> (m > 0) && (n > 0) </code>
215 */
216 template <class E>
217 inline Matrix_List<E>::Matrix_List(unsigned m, unsigned n)
218  : m_VL(), m_cols(n), m_same()
219 {
220  if (m == 0 || n == 0) {
221  m_cols = 0;
222  }
223  reSize(m,n);
224 // m_same = E(); // Usa el número "cero" como neutro tipo "E"
225 }
226 
227 template <class E>
229  copy( o );
230  return;
231 }
232 
233 /// Destructor
234 template <class E>
236 
237 template <class E>
238 bool Matrix_List<E>::equals( const Matrix_List & o ) const {
239  if ( this == & o ) {
240  return true;
241  }
242  if (rows() != o.rows() || cols() != o.cols()) {
243  return false;
244  }
245 
246  for (unsigned i=0; i<rows(); i++) {
247  for (unsigned j=0; j<cols(); j++) {
248  if ( (*this)(i,j) != o(i,j) ) {
249  return false;
250  }
251  }
252  }
253  return true;
254 }
255 
256 /** Copia desde \c "o".
257  - Copia todo el valor de \c "o" sobre \c "*this", de forma que el nuevo valor de
258  \c "*this" sea un duplicado exacto del valor de \c "o".
259  - El valor anterior de \c "*this" se pierde.
260  - El objeto \c "o" mantiene su valor anterior.
261  - Luego de la copia, cuando el valor de \c "o" cambia, el de \c "*this" no cambiará,
262  y viceversa, pues la copia es una copia profunda; no es superficial.
263  - Si \c "*this" es \c "o" entonces su valor no cambia.
264  - Después de esta operación siempre ocurre que <code> *this == o </code>.
265 
266  \par Complejidad:
267  O( <code> rows() * cols() </code> )
268 
269  \returns *this
270  \see http://www.di-mare.com/adolfo/binder/c04.htm#sc05
271 */
272 template <class E>
274  if (this == &o) { // evita auto-borrado
275  return *this;
276  }
277  this->m_VL = o.m_VL;
278  this->m_cols = o.m_cols;
279  this->m_same = o.m_same;
280  return *this;
281 }
282 
283 /** Traslada el valor de \c "o" a \c "*this".
284  - El valor anterior de \c "*this" se pierde.
285  - El nuevo valor de \c "*this" es el que \c "o" tuvo.
286  - \c "o" queda en el estado en que lo dejaría \c Erase().
287  - Si \c "*this" es \c "o" entonces su valor no cambia.
288  - En general, después de esta operación casi
289  nunca ocurre que <code> (*this == o) </code>
290 
291  \par Complejidad:
292  O( <code> rows() * cols() </code> )
293 
294  \returns \c *this
295 
296  \see http://www.di-mare.com/adolfo/binder/c04.htm#sc07
297 */
298 template <class E>
300  if (this == &o) { // evita auto-borrado
301  return *this;
302  }
303  if ( m_VL.size() != o.m_VL.size() ) {
304  m_VL.clear();
305  m_VL.resize( o.m_VL.size() );
306  }
307  assert( m_VL.size() == o.m_VL.size() );
308  for ( int i=0; i<m_VL.size(); ++i ) {
309  this->m_VL[i].clear();
310  this->m_VL[i].splice( m_VL[i].begin(), o.m_VL[i] );
311  }
312  this->m_cols = o.m_cols;
313  this->m_same = o.m_same;
314  return *this;
315 }
316 
317 /** Intercambia los valores de \c "*this" y \c "o".
318  - Debido a que algunos métodos retornan copias del valor de \c "*this" en
319  lugar de una referencia, como ocurre con \c Matrix_List::Child(), a veces
320  \c swap() no tiene el resultado esperado por el programador.
321  - Por ejemplo, si se invoca <code> T.Child(i). swap( T.Child(j) ) </code>
322  el resultado no es intercambiar los hijos, sino más bien intercambiar
323  los valores de los sub-árboles temporales \c T.Child(i) y \c T.Child(j).
324  La forma correcta de intercambiar hijos es usar \c Graft().
325 
326  \par Complejidad:
327  O( \c 1 )
328 
329  \returns *this
330 
331  \see http://www.di-mare.com/adolfo/binder/c04.htm#sc08
332 */
333 template <class E>
335  std::swap( this->m_VL , o.m_VL );
336  std::swap( this->m_cols , o.m_cols );
337  std::swap( this->m_same , o.m_same );
338  return *this;
339 }
340 
341 /** Le cambia las dimensiones a la matriz.
342  - En algunos casos los valores almacenados en la matriz no quedan
343  todos iguales a \c Matrix_List<E>::value_type().
344  \pre <code> (m > 0) && (n > 0) </code>
345 */
346 template <class E>
347 void Matrix_List<E>::reSize(unsigned m, unsigned n) {
348  unsigned rows = m_VL.size();
349  if ( m > rows ) {
350  std::vector< std::list < Matrix_List_ColVal< E > > > TMP(m);
351  for ( unsigned i=0 ; i<rows ; ++i ) {
352  TMP[i].splice( TMP[i].begin(), this->m_VL[i] );
353  }
354  this->m_VL.resize(m); // copia todas las filas anteriores
355  for ( unsigned i=0 ; i<rows ; ++i ) {
356  this->m_VL[i].splice( this->m_VL[i].begin() , TMP[i] );
357  }
358  }
359  else if ( m < rows ) { // desecha las filas restantes
360  this->m_VL.resize(m);
361  }
362 
363  if ( n < m_cols ) { // desecha valores en columnas mayores a "n"
364  rows = m_VL.size();
365  for ( unsigned i=0 ; i<rows ; ++i ) {
366  typedef typename std::list < Matrix_List_ColVal< E > >::iterator ITR;
367  ITR it = this->m_VL[i].begin();
368  while ( it != this->m_VL[i].end() ) {
369  if ( it->m_col >= n ) {
370  it = this->m_VL[i].erase( it );
371  }
372  else {
373  ++it;
374  }
375  }
376  }
377  }
378  m_cols = n;
379  return;
380 
381 /* NOTA
382  Esta es la antigua especificación de reSize(). Es incorrecta
383  porque presume que el Rep de la matriz es un vector denso en
384  donde están almacenados todos los valores de la matriz:
385 
386  +----------------------------------------------------------+
387  | reSize(): Le cambia las dimensiones a la matriz. |
388  | ======== |
389  | - Si ocurre que (m*n) == rows() * cols() los valores de |
390  | la matriz se mantienen, aunque cambian sus dimensiones.|
391  | - Si (m*n) != rows() * cols() los valores de la matriz |
392  | quedarán inicializados de la misma forma en que los |
393  | inicializaría CERO == Matrix_List<E>::value_type(). |
394  | |
395  | \pre (m > 0) && (n > 0) |
396  +----------------------------------------------------------+
397 
398  En la actual especificación, que ya está corregida, no queda
399  implícita la presunción sobre cómo está organizada internamente
400  la matriz. Por eso, esta nueva especificación sí sirve para una
401  matriz implementada con un vector denso de valores, o para la
402  matriz implementada como una matriz rala.
403 
404  Estos pequeños detalles en algunas ocasiones surgen cuando el
405  programador de una clase introduce mejoras o modificaciones, pues
406  muchas veces es muy difícil o prácticamente imposible predecir
407  todos los pormenores y detalles de una especificación o de una
408  implementación.
409 */
410 }
411 
412 /** Le ajusta las dimensiones a la matriz.
413  - Si ocurre que <code> (m*n) == rows()*cols() </code> hace
414  lo mismo que haría \c reSize(m,n).
415  - En caso contrario, no hace nada.
416 */
417 template <class E>
418 inline void Matrix_List<E>::reShape(unsigned m, unsigned n) {
419  if ( m * n == m_VL.size() * m_cols ) {
420  reSize(n,m);
421  }
422 }
423 
424 /// Deja el valor de \c *this en el valor en que lo
425 /// inicializa el constructor de vector.
426 template <class E>
428  m_VL.clear();
429  m_VL.push_back( std::list < Matrix_List_ColVal< E > >() );
430  m_cols = 1;
431  m_same = value_type();
432 }
433 
434 /// Retorna una referencia al elemento [i,j] de la matriz ( \c const ).
435 /// - \c M(i,j) significa lo que en arreglos se denota con \c M[i][j].
436 /// - <code>val = M(i,j); // M(i,j) es un "rvalue" (const)</code>
437 template <class E>
438 const E& Matrix_List<E>::operator () (unsigned i, unsigned j) const {
439  assert( "Matrix_List<E>::operator()()" && (i < rows()) );
440  assert( "Matrix_List<E>::operator()()" && (j < cols()) );
441 
442  typedef typename std::list < Matrix_List_ColVal< E > >::const_iterator ITR;
443  ITR it = this->m_VL[i].begin();
444  while ( it != this->m_VL[i].end() ) {
445  if ( it->m_col == j ) {
446  break;
447  }
448  ++it;
449  }
450  if ( it == this->m_VL[i].end() ) {
451  return m_same;
452  }
453  else {
454  return it->m_val;
455  }
456 
457 /* NOTA
458  Como este método es "const", de antemano se sabe que el programador no puede
459  usarlo para modificar el valor de la matriz. Por eso, aunque el valor
460  retornado sea una referencia a valor común por defecto m_same, de antemano
461  el compilador asegura que ese valor no será modificado.
462 
463  Sin embargo, cuando el programador usa el método homónimo operator()(i,j)
464  que no es "const", es posible que el valor retornado sí sea modificado.
465  En ese caso, ya no es correcto retornar una referencia al valor común "m_same".
466  - Por eso, cuando se usa el hace referencia en el otro operator()(i,j) es
467  necesario agregar una entrada en los vectores paralelos en aquellos casos
468  en que no existe un valor diferente a "m_same" para (i,j).
469  - Esto quiere decir que sí es posible que al utilizar la versión modificable
470  de operator()(i,j) quede en el vector "m_VL[]" un valor que es igual a
471  "m_same". En el caso peor, podría ocurrir que todos los valores almacenados
472  en el vector "m_VL[]" sean todos iguales a "m_same".
473  - Una forma de corregir esta anomalía es "revisar después" si existe un valor
474  en el vector "m_VL[]" que es igual a "m_same". Una forma eficiente de
475  hacerlo es mantener el el Rep un puntero "m_last_change" que apunte al
476  último valor "m_VL[]" que la versión modificable de operator()(i,j) retornó.
477  En la siguiente invocación a operator()(i,j), se puede verificar si hubo un
478  ese valor anterior fue cambiado de manera que tiene almacenado "m_same".
479 */
480 }
481 
482 /// Retorna una referencia al elemento [i,j] de la matriz.
483 /// - \c M(i,j) significa lo que en arreglos se denota con \c M[i][j].
484 /// - <code>M(i,j) = val; // M(i,j) es un "lvalue" (modificable)</code>
485 template <class E>
486 E& Matrix_List<E>::operator() (unsigned i, unsigned j) {
487  assert( "Matrix_List<E>::operator()()" && (i < rows()) );
488  assert( "Matrix_List<E>::operator()()" && (j < cols()) );
489 
490  // Busca al elemento M(i,j)
491  typedef typename std::list < Matrix_List_ColVal< E > >::iterator ITR;
492  ITR it = this->m_VL[i].begin();
493  while ( it != this->m_VL[i].end() ) {
494  if ( it->m_col == j ) {
495  break;
496  }
497  ++it;
498  }
499  if ( it == this->m_VL[i].end() ) { // lo agrega porque no estaba
500  this->m_VL[i].push_front( Matrix_List_ColVal< E >(j,m_same) );
501  it = this->m_VL[i].begin();
502  }
503  return it->m_val;
504 }
505 
506 /// Le cambia el tamaño máximo posible a la matriz.
507 /// - Le aumenta la cantidad de valores diferentes a \c getDefault().
508 /// - No hace nada cuando <code>size() < newsize</code>.
509 template <class E>
510 inline void Matrix_List<E>::reSize(unsigned newsize) {
511 }
512 
513 /** Le suma a \c "*this" la matriz \c "O".
514  \pre
515  - \c "*this" y \c "O" deben tener las mismas dimensiones
516  - <code> rows() == O.rows() && cols() == O.cols() </code>
517 
518  \par Complejidad:
519  O( <code> rows() * cols() </code> )
520 
521  \remarks
522  - Esta es la implementación de Matrix_List<E> operator+( Matrix_List<E>&, Matrix_List<E> )
523  - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>)
524  definida con plantillas si esa función amiga no está definida (implementada)
525  dentro de la declaración de la clase. Para solventar esta deficiencia existe
526  este método que realiza el trabajo, aunque es poco cómodo de usar.
527 */
528 template <class E>
530  // verifica que las dos matrices sean del mismo tamaño
531  assert( "Matrix_List<E>::add()" && (rows() == O.rows()) && (cols() == O.cols()) );
532 
533  // Como las matrices son del mismo tamaño basta sumarlas entrada por entrada.
534  for ( unsigned i=0 ; i<rows() ; ++i ) {
535  for ( unsigned j=0 ; j<cols() ; ++j ) {
536  this->operator()(i,j) += O(i,j);
537  }
538  }
539  return;
540 }
541 
542 /** Le resta a \c "*this" la matriz \c "O".
543  \pre
544  - \c "*this" y \c "O" deben tener las mismas dimensiones
545  - <code> rows() == O.rows() && cols() == O.cols() </code>
546 
547  \par Complejidad:
548  O( <code> rows() * cols() </code> )
549 
550  \remarks
551  - Esta es la implementación de Matrix_List<E> operator-( Matrix_List<E>&, Matrix_List<E> )
552  - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>)
553  definida con plantillas si esa función amiga no está definida (implementada)
554  dentro de la declaración de la clase. Para solventar esta deficiencia existe
555  este método que realiza el trabajo, aunque es poco cómodo de usar.
556 */
557 template <class E>
559  // verifica que las dos matrices sean del mismo tamaño
560  assert( "Matrix_List<E>::substract()" && (rows() == O.rows()) && (cols() == O.cols()) );
561 
562  for ( unsigned i=0 ; i<rows() ; ++i ) {
563  for ( unsigned j=0 ; j<cols() ; ++j ) {
564  this->operator()(i,j) -= O(i,j);
565  }
566  }
567  return;
568 }
569 
570 /** Calcula la multiplicación <code> A * B </code> y la almacena en \c "*this".
571  - Las dimensiones de \c "*this" se ajustan de manera que:
572  - <code> rows() == A.rows() && cols() == B.cols()</code>
573 
574  \pre
575  - \c "A" y \c "B" deben tener dimensiones compatibles
576  - <code> A.cols() == B.rows() </code>
577  - La multiplicación se hace [Fila x Columna], lo que implica que la cantidad
578  de valores en la filas de \c "A" debe ser igual a la cantidad de columnas de \c "B"
579 
580  \par Complejidad:
581  O( <code> A.cols() * B.cols() * A.cols() * A.capacity() * B.capacity() </code> )
582 
583  \remarks
584  - Esta es la implementación de Matrix_List<E> operator*( Matrix_List<E>&, Matrix_List<E> )
585  - El compilador tiene problemas en compilar un función amiga (<em>"friend"</em>)
586  definida con plantillas si esa función amiga no está definida (implementada)
587  dentro de la declaración de la clase. Para solventar esta deficiencia existe
588  este método que realiza el trabajo, aunque es poco cómodo de usar.
589 */
590 template <class E>
592  // Verifica que las matrices se puedan multiplicar
593  assert( (A.cols() == B.rows()) && " => Matrix_List<E>::multiply()" );
594 
595  reSize( A.rows(), B.cols() );
596  value_type sum;
597  for (unsigned i=0; i<rows(); i++) {
598  for (unsigned j=0; j<cols(); j++) {
599  sum = 0; // sum = E(0);
600  for (unsigned k=0; k<A.cols(); k++) {
601  sum = sum + A(i,k) * B(k,j);
602  }
603  // this->(i,j) = sum; // produce un error de compilación
604  // this->operator()(i,j) = sum; // también funciona
605  (*this)(i,j) = sum; // también funciona
606  }
607  }
608  return;
609 }
610 
611 /// Graba en el flujo \c COUT el valor de \c M[][].
612 template <class E>
613 std::ostream& operator<<(std::ostream& COUT, const Matrix_List<E>& M) {
614  COUT << '[' << M.rows() << 'x' << M.cols() << ']' << std::endl;
615  for (unsigned i=0; i < M.rows(); ++i) {
616  for (unsigned j=0; j < M.cols(); ++j) {
617  COUT << " " << M(i,j);
618  }
619  COUT << std::endl;
620  }
621  return COUT;
622 }
623 
624 /// Obtiene del flujo \c CIN el valor para \c M[][].
625 template <class E>
626 std::istream& operator>>(std::istream& CIN, Matrix_List<E>& M) {
627  assert( "This code has not been tested" );
628  unsigned rows,cols;
629  CIN >> rows >> cols;
630  M.reSize(rows,cols);
631  for (unsigned i=0; i<rows; i++) {
632  for (unsigned j=0; j<cols; j++) {
633  CIN >> M(i,j);
634  }
635  }
636  return CIN;
637 }
638 
639 } // namespace Mx
640 
641 // Este [horrible] truco permite "compartir" el mismo archivo Matrix_Lib.h
642 // entre Matrix.h y Matrix_List.h
643 // #define Matrix Matrix_List
644 // #include "Matrix_Lib.h"
645 // #undef Matrix
646 
647 #include "Matrix_Lib.h"
648 
649 #endif // Matrix_List_h
650 // EOF: Matrix_List.h
Matrix_List & operator=(const Matrix_List &o)
Sinónimo de this-&gt;copy(o)
Definition: Matrix_List.h:74
void reserve(size_type _Count)
Ajusta la matriz para que pueda almacenar n valores diferentes a getDefault().
friend Matrix_List operator+(const Matrix_List &A, const Matrix_List &B)
Retorna A+B.
Definition: Matrix_List.h:91
const E & getDefault()
Valor almacenado en la mayor parte de la Matrix_List.
Definition: Matrix_List.h:106
unsigned size() const
Cantidad de valores almacenados en la matriz.
Definition: Matrix_List.h:69
unsigned m_cols
Cantidad de columnas de la matris.
Definition: Matrix_List.h:116
unsigned rows() const
Cantidad de filas de la matriz.
Definition: Matrix_List.h:67
friend bool operator==(const Matrix_List &p, const Matrix_List &q)
¿¿¿ (p == q) ???
Definition: Matrix_List.h:80
E m_val
Valor almacenado en la matriz.
Definition: Matrix_List.h:31
void substract(const Matrix_List &)
Le resta a &quot;*this&quot; la matriz &quot;O&quot;.
Definition: Matrix_List.h:558
Matrix_List(unsigned m=1, unsigned n=1)
Constructor de vector.
Definition: Matrix_List.h:217
unsigned count() const
Cantidad de valores almacenados en la matriz.
Definition: Matrix_List.h:70
Funciones para manipular Matrix_BASE&lt;&gt;.
std::istream & operator>>(std::istream &CIN, Matrix< E > &M)
Obtiene del flujo CIN el valor para M[][].
Definition: Matrix.h:615
void clear()
Deja el valor de *this en el valor en que lo inicializa el constructor de vector. ...
Definition: Matrix_List.h:427
Matrix_List & swap(Matrix_List &o)
Intercambia los valores de &quot;*this&quot; y &quot;o&quot;.
Definition: Matrix_List.h:334
bool check_ok(const Matrix< T > &M)
Verifica la invariante de la clase.
Definition: Matrix.h:170
value_type & reference
Tipo del objeto almacenado, similar al nombre usado en STL.
Definition: Matrix_List.h:55
Esta es una clase matriz muy chirrisquitica almacenada como una matriz rala implementada con listas...
Definition: Matrix_List.h:50
~Matrix_List()
Destructor.
Definition: Matrix_List.h:235
Matrix_List(const value_type V)
Matriz escalar de valor V.
Definition: Matrix_List.h:64
unsigned size_type
Tipo del tamaño de un objeto, similar al nombre usado en STL.
Definition: Matrix_List.h:59
void add(const Matrix_List &)
Le suma a &quot;*this&quot; la matriz &quot;O&quot;.
Definition: Matrix_List.h:529
E m_same
Valor almacenado en la mayor parte de la Matrix_List.
Definition: Matrix_List.h:117
size_type capacity() const
Cantidad máxima posible de valores diferentes que pueden ser almacenados en la matriz.
Definition: Matrix_List.h:72
reference operator()(unsigned, unsigned)
Retorna una referencia al elemento [i,j] de la matriz.
Definition: Matrix_List.h:486
friend bool operator!=(const Matrix_List &p, const Matrix_List &q)
¿¿¿ (p != q) ???
Definition: Matrix_List.h:82
Clase privada para implementar la lista de valores de cada fila.
Definition: Matrix_List.h:27
Matrix_List & move(Matrix_List &o)
Traslada el valor de &quot;o&quot; a &quot;*this&quot;.
Definition: Matrix_List.h:299
std::vector< std::list< Matrix_List_ColVal< E > > > m_VL
Vector que contiene la lista de valores de las columnas.
Definition: Matrix_List.h:115
E value_type
Tipo del objeto almacenado, similar al nombre usado en STL.
Definition: Matrix_List.h:53
friend Matrix_List operator*(const Matrix_List &A, const Matrix_List &B)
Retorna A*B.
Definition: Matrix_List.h:95
unsigned cols() const
Cantidad de columnas de la Matriz.
Definition: Matrix_List.h:68
Matrix_List_ColVal(unsigned col, const E &val)
constructor
Definition: Matrix_List.h:34
const value_type & const_reference
Tipo del objeto almacenado, similar al nombre usado en STL.
Definition: Matrix_List.h:57
friend class test_Matrix_List
Datos de prueba para la clase.
Definition: Matrix_List.h:113
unsigned m_col
Columna del valor almacenado en la matriz.
Definition: Matrix_List.h:30
bool same(const Matrix_List &o) const
Retorna true si &quot;o&quot; comparte sus valores con &quot;*this&quot;.
Definition: Matrix_List.h:85
Matrix_List & copy(const Matrix_List &o)
Copia desde &quot;o&quot;.
Definition: Matrix_List.h:273
void reSize(unsigned, unsigned)
Le cambia las dimensiones a la matriz.
Definition: Matrix_List.h:347
void reShape(unsigned, unsigned)
Le ajusta las dimensiones a la matriz.
Definition: Matrix_List.h:418
void multiply(const Matrix_List &, const Matrix_List &)
Calcula la multiplicación A * B y la almacena en &quot;*this&quot;.
Definition: Matrix_List.h:591
void setDefault(const E &same)
Define el escalar que por defecto está en todas las entradas de la Matrix_List.
Definition: Matrix_List.h:190
friend bool check_ok(const Matrix_List< T > &M)
Verifica la invariante de la clase.
Definition: Matrix_List.h:162
bool equals(const Matrix_List &o) const
¿¿¿ (*this==o) ???
Definition: Matrix_List.h:238
friend Matrix_List operator-(const Matrix_List &A, const Matrix_List &B)
Retorna A-B.
Definition: Matrix_List.h:93