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