CARMA C++
Matrix.h
Go to the documentation of this file.
1 #ifndef CARMA_SERVICES_MATRIX_H
2 #define CARMA_SERVICES_MATRIX_H
3 
11 #include <iostream>
12 #include <cmath>
13 
15 #include "carma/services/Vector.h"
16 
17 namespace carma {
18  namespace services {
19 
20  // Some C++ ugliness: To declare non-member friend template
21  // functions under the new standard, the function templates must
22  // be forward-declared before appearing in the class definition.
23  // I suspect this won't even compile with gcc versions < 3.2.2
24 
25  template<class type>
26  class Matrix;
27 
28  template<class type>
29  std::ostream& operator<<(std::ostream& os,
30  Matrix<type>& mat);
31 
32  template<class type>
33  std::ostringstream& operator<<(std::ostringstream& os,
34  Matrix<type>& mat);
35 
36  template<class type>
37  Vector<type> operator*(Vector<type>& vec,
38  Matrix<type>& mat);
39 
40  // Multiplication operators
41 
42  template<class type>
43  Matrix<type> operator*(unsigned fac, Matrix<type>& mat);
44 
45  template<class type>
46  Matrix<type> operator*(int fac, Matrix<type>& mat);
47 
48  template<class type>
49  Matrix<type> operator*(float fac, Matrix<type>& mat);
50 
51  template<class type>
52  Matrix<type> operator*(double fac, Matrix<type>& mat);
53 
58  template<class type>
59  class Matrix {
60 
61  public:
62 
66  Matrix();
67 
71  Matrix(const Matrix<type>& mat);
72 
76  Matrix(unsigned nRow, unsigned nCol);
77 
81  virtual ~Matrix();
82 
86  Vector<type>& operator[](unsigned iRow);
87 
92 
96  void operator=(const Matrix<type>& mat);
97 
101  template <class T>
103 
107  template <class T>
109 
113  template <class T>
115 
119  template <class T>
121 
126 
130  Matrix<type> reduce(unsigned iRow, unsigned iCol);
131 
136  Matrix<type> trans();
137 
142  Matrix<type> adj();
143 
148  Matrix<type> inv();
149 
153  type determinant();
154  type det();
155  type determinant(unsigned i, unsigned j);
156  type det(unsigned i, unsigned j);
157 
161  type trace();
162 
166  type cofactor(unsigned iRow, unsigned iCol);
167 
168 
169  //------------------------------------------------------------
170  // Non-member friends
171  //------------------------------------------------------------
172 
176  friend Vector<type> carma::services::operator * <>
177  ( Vector<type>& vec, Matrix<type>& mat);
178 
182  friend std::ostream& carma::services::operator << <>
183  (std::ostream& os, Matrix<type>& mat);
184 
188  friend std::ostringstream& carma::services::operator << <>
189  (std::ostringstream& os, Matrix<type>& mat);
190 
191  private:
192 
193  // Privately, Matrix is implemented as a vector of vectors
194 
195  Vector<Vector<type> > data_;
196 
197  // Store the size
198 
199  unsigned nRow_;
200  unsigned nCol_;
201 
202  }; // End class Matrix
203 
204  //------------------------------------------------------------
205  // Method bodies
206  //------------------------------------------------------------
207 
211  template<class type>
213  {
214  nRow_ = 0;
215  nCol_ = 0;
216  }
217 
221  template<class type>
223  {
224  if(&mat == this)
225  return;
226 
227  nRow_ = mat.nRow_;
228  nCol_ = mat.nCol_;
229 
230  data_ = mat.data_;
231  }
232 
236  template<class type>
238  {
239  if(&mat == this)
240  return;
241 
242  nRow_ = mat.nRow_;
243  nCol_ = mat.nCol_;
244 
245  data_.resize(nRow_);
246  for(unsigned irow=0; irow < nRow_; irow++) {
247  data_[irow].resize(nCol_);
248  }
249 
250  data_ = mat.data_;
251  }
252 
256  template<class type>
257  Matrix<type>::Matrix(unsigned nRow, unsigned nCol)
258  {
259  data_.resize(nRow);
260 
261  for(unsigned irow=0; irow < nRow; irow++)
262  data_[irow].resize(nCol);
263 
264  nRow_ = nRow;
265  nCol_ = nCol;
266  }
267 
271  template<class type>
273 
277  template<class type>
279  {
280  if(iRow > data_.size()-1) {
281  std::ostringstream os;
282  os << "Matrix::operator[] : Matrix has no row: " << iRow;
284  }
285 
286  return data_[iRow];
287  }
288 
293  // Matrix
294 
295  template<class type>
296  Matrix<type>
298  {
299  // Make sure no dimension is zero
300 
301  if(mat.data_.size() == 0 || data_.size() == 0) {
303  "Matrix::operator*(Matrix) : Zero dimension encountered"
304  );
305  }
306 
307  // Make sure all rows have the same number of columns
308 
309  for(unsigned iRow=0; iRow < mat.data_.size(); iRow++)
310  if(mat.data_[iRow].size() != mat.nCol_) {
312  "Matrix::operator*(Matrix) : Matrix has variable dimensions"
313  );
314  }
315 
316  for(unsigned iRow=0; iRow < data_.size(); iRow++)
317  if(data_[iRow].size() != nCol_) {
319  "Matrix::operator*(Matrix) : Matrix has variable dimensions"
320  );
321  }
322 
323  // Make sure the matrices can in fact be multiplied.
324 
325  if(nRow_ != mat.nCol_ || nCol_ != mat.nRow_)
327  "Matrix::operator*(Matrix) : Matrices have incompatible dimensions"
328  );
329 
330  Matrix<type> result(nRow_, mat.nCol_);
331 
332  bool first;
333  for(unsigned iRow=0; iRow < nRow_; iRow++)
334  for(unsigned iCol=0; iCol < mat.nCol_; iCol++) {
335  first = true;
336  for(unsigned j=0; j < nCol_; j++) {
337  if(first) {
338  result[iRow][iCol] = data_[iRow][j] * mat.data_[j][iCol];
339  first = false;
340  } else {
341  result[iRow][iCol] += data_[iRow][j] * mat.data_[j][iCol];
342  }
343  }
344  }
345  return result;
346  }
347 
351  template<class type>
352  Vector<type>
354  {
355  if(nCol_==0 || vec.size()==0) {
357  "Matrix::operator*(Vector) : Zero dimension encountered"
358  );
359  }
360 
361  if(nCol_ != vec.size()) {
363  "Matrix::operator*(Vector) : Vector has incompatible dimensions"
364  );
365  }
366 
367  // Now do the calculation
368 
369  Vector<type> result;
370 
371  result.resize(nRow_);
372 
373  bool first = true;
374 
375  for(unsigned iRow=0; iRow < nRow_; iRow++)
376  for(unsigned j=0; j < nCol_; j++) {
377  if(first) {
378  result[iRow] = data_[iRow][j] * vec[j];
379  first = false;
380  } else {
381  result[iRow] += data_[iRow][j] * vec[j];
382  }
383  }
384 
385  return result;
386  }
387 
388  // Factors
389 
390  template<class type>
391  template<class T>
393  {
394  Matrix<type> result = *this;
395 
396  for(unsigned iRow=0; iRow < nRow_; iRow++)
397  for(unsigned iCol=0; iCol < nCol_; iCol++)
398  result[iRow][iCol] *= fac;
399 
400  return result;
401  }
402 
403  template<class type>
404  template<class T>
406  {
407  Matrix<type> result = *this;
408 
409  for(unsigned iRow=0; iRow < nRow_; iRow++)
410  for(unsigned iCol=0; iCol < nCol_; iCol++)
411  result[iRow][iCol] /= fac;
412 
413  return result;
414  }
415 
416  template<class type>
417  template<class T>
419  {
420  Matrix<type> result = *this;
421 
422  for(unsigned iRow=0; iRow < nRow_; iRow++)
423  for(unsigned iCol=0; iCol < nCol_; iCol++)
424  result[iRow][iCol] += fac;
425 
426  return result;
427  }
428 
429  template<class type>
430  template<class T>
432  {
433  Matrix<type> result = *this;
434 
435  for(unsigned iRow=0; iRow < nRow_; iRow++)
436  for(unsigned iCol=0; iCol < nCol_; iCol++)
437  result[iRow][iCol] -= fac;
438 
439  return result;
440  }
441 
442  //------------------------------------------------------------
443  // Non-member operators
444  //------------------------------------------------------------
445 
449  template<class type>
450  Vector<type> operator*( Vector<type>& vec,
451  Matrix<type>& mat)
452  {
453  if(mat.nRow_==0 || vec.size()==0) {
455  "operator*(Vector,Matrix) : zero dimension encountered"
456  );
457  }
458 
459  if(mat.nRow_ != vec.size()) {
461  "operator*(Vector,Matrix) : Vector has incompatible dimension"
462  );
463  }
464 
465  // Now do the calculation
466 
467  Vector<type> result;
468 
469  result.resize(mat.nCol_);
470 
471  bool first = true;
472 
473  for(unsigned iCol=0; iCol < mat.nCol_; iCol++)
474  for(unsigned j=0; j < mat.nRow_; j++) {
475  if(first) {
476  result[iCol] = mat.data_[j][iCol] * vec[j];
477  first = false;
478  } else {
479  result[iCol] += mat.data_[j][iCol] * vec[j];
480  }
481  }
482 
483  return result;
484  }
485 
489  template<class type>
490  Matrix<type> operator*(unsigned fac, Matrix<type>& mat)
491  {
492  return mat * fac; // Member operator is already defined
493  }
494 
495  template<class type>
496  Matrix<type> operator*(int fac, Matrix<type>& mat)
497  {
498  return mat * fac; // Member operator is already defined
499  }
500 
501  template<class type>
502  Matrix<type> operator*(float fac, Matrix<type>& mat)
503  {
504  return mat * fac; // Member operator is already defined
505  }
506 
507  template<class type>
508  Matrix<type> operator*(double fac, Matrix<type>& mat)
509  {
510  return mat * fac; // Member operator is already defined
511  }
512 
516  template<class type>
517  std::ostream& operator<<(std::ostream& os,
518  Matrix<type>& mat)
519  {
520  for(unsigned iRow=0; iRow < mat.nRow_; iRow++) {
521  os << "|";
522  for(unsigned iCol=0; iCol < mat.nCol_; iCol++) {
523  if(iCol != 0)
524  os << " ";
525  os << ::std::setw(15) << ::std::setprecision(8) << mat.data_[iRow][iCol];
526  }
527  os << "|" << ::std::endl;
528  }
529  return os;
530  }
531 
535  template<class type>
536  std::ostringstream& operator<<(std::ostringstream& os,
537  Matrix<type>& mat)
538  {
539  for(unsigned iRow=0; iRow < mat.nRow_; iRow++) {
540  os << "|";
541  for(unsigned iCol=0; iCol < mat.nCol_; iCol++) {
542  if(iCol != 0)
543  os << " ";
544  os << mat.data_[iRow][iCol];
545  }
546  os << "|" << ::std::endl;
547  }
548  return os;
549  }
550 
554  template<class type>
556  {
557  Matrix<type> result(nCol_, nRow_);
558 
559  for(unsigned i=0; i < nRow_; i++)
560  for(unsigned j=0; j < nCol_; j++)
561  result.data_[j][i] = data_[i][j];
562 
563  return result;
564  }
565 
566  template<class type>
568  {
569  return transpose();
570  }
571 
575  template<class type>
577  {
578  Matrix<type> result(nCol_, nRow_);
579  int prefac;
580 
581  for(unsigned i=0; i < nRow_; i++)
582  for(unsigned j=0; j < nCol_; j++) {
583  prefac = (i+j)%2 == 0 ? 1 : -1;
584  result.data_[i][j] = prefac * determinant(i, j);
585  }
586 
587  return result.transpose();
588  }
589 
590  template<class type>
592  {
593  return adjoint();
594  }
595 
599  template<class type>
601  {
602  Matrix<type> result = adjoint();
603  type deter = determinant();
604 
605  if(::std::isfinite(1.0/(double)deter))
606  return result/deter;
607  else {
609  "Matrix::inverse() : Matrix is not invertible"
610  );
611  }
612  }
613 
614  template<class type>
616  {
617  return inverse();
618  }
619 
623  template<class type>
625  {
626  if(nRow_ != nCol_) {
628  "Matrix::trace() : Not an N x N matrix"
629  );
630  }
631 
632  type result = data_[0][0];
633 
634  for(unsigned i=1; i < nRow_; i++)
635  result += data_[i][i];
636 
637  return result;
638  }
639 
643  template<class type>
644  type Matrix<type>::cofactor(unsigned i, unsigned j)
645  {
646  if(nRow_ != nCol_) {
648  "Matrix::cofactor() : Not an N x N matrix"
649  );
650  }
651 
652  if(nRow_ < 2) {
654  "Matrix::cofactor() : Cannot determine cofactors for dimensions < 2"
655  );
656  }
657 
658  int prefac = (i+j)%2 == 0 ? 1 : -1;
659 
660  return prefac * determinant(i, j);
661  }
662 
666  template<class type>
668  {
669  if(nRow_ != nCol_) {
671  "Matrix::determinant() : Not and N x N matrix"
672  );
673  }
674 
675  // If this is a N x N matrix with N < 3, the determinant is trivial
676 
677  if(nCol_ == 0)
678  return 0;
679 
680  if(nCol_ == 1)
681  return data_[0][0];
682 
683  if(nCol_ == 2)
684  return data_[0][0] * data_[1][1] - data_[1][0] * data_[0][1];
685 
686  type sum = data_[0][0] * cofactor(0, 0);
687 
688  for(unsigned iCol=1; iCol < nCol_; iCol++) {
689  sum += data_[0][iCol] * cofactor(0, iCol);
690  }
691 
692  return sum;
693  }
694 
698  template<class type>
700  {
701  return determinant();
702  }
703 
707  template<class type>
708  type Matrix<type>::determinant(unsigned i, unsigned j)
709  {
710  if(nRow_ != nCol_) {
712  "Matrix::determinant(i,j) : Not and N x N matrix"
713  );
714  }
715 
716  if(nRow_ < 2) {
718  "Matrix::determinant(i,j) : Cannot compute determinant for dimensions < 2"
719  );
720  }
721 
722  Matrix<type> reduced = reduce(i, j);
723 
724  return reduced.determinant();
725  }
726 
730  template<class type>
731  type Matrix<type>::det(unsigned i, unsigned j)
732  {
733  return determinant(i, j);
734  }
735 
739  template<class type>
740  Matrix<type> Matrix<type>::reduce(unsigned i, unsigned j)
741  {
742  if(nCol_ == 1 || nRow_ == 1) {
744  "Matrix dimensions cannot be reduced.");
745  }
746 
747  // Else output the reduced matrix
748 
749  Matrix<type> result(nRow_-1, nCol_-1);
750 
751  // Copy the original matrix, exclusive of the specified row and column
752 
753  for(unsigned iRow=0, iRowRed=0; iRow < nRow_; iRow++) {
754 
755  if(iRow != i) {
756 
757  for(unsigned iCol=0, iColRed=0; iCol < nCol_; iCol++) {
758 
759  if(iCol != j) {
760  result.data_[iRowRed][iColRed] = data_[iRow][iCol];
761  iColRed++;
762  }
763  }
764 
765  iRowRed++;
766  }
767  }
768  return result;
769  }
770 
771  } // End namespace services
772 } // End namespace carma
773 
774 
775 
776 #endif // End #ifndef CARMA_SERVICES_MATRIX_H
This class handles standard mathematical vector operations.
Definition: Location.h:21
type det()
Determinant of a matrix.
Definition: Matrix.h:699
Matrix()
Constructor.
Definition: Matrix.h:212
Exception class for errors.
Matrix< type > adjoint()
Define an adjoint operator.
Definition: Matrix.h:576
Matrix< type > operator+(T)
Define a matrix addition operator.
Definition: Matrix.h:418
Matrix< type > inverse()
Define an inverse operator.
Definition: Matrix.h:600
Matrix< type > operator*(Matrix< type > &mat)
Define a matrix multiplication operator.
Definition: Matrix.h:297
This class handles standard mathematical matrix operations.
Definition: Matrix.h:26
virtual ~Matrix()
Destructor.
Definition: Matrix.h:272
unsigned size() const
Query the size of the vector.
Definition: Vector.h:71
Vector< type > & operator[](unsigned iRow)
Define an operator for accessing rows of the matrix.
Definition: Matrix.h:278
Exception class for errors The exception comes with a text string that can be printed or logged...
#define CARMA_EXCEPTION(x, y)
Trick to get the file name and line number passed to the exception handler.
Matrix< type > operator/(T)
Define a matrix division operator.
Definition: Matrix.h:405
std::ostream & operator<<(std::ostream &os, const carma::services::Angle &angle)
Define the &lt;&lt; operator to allow, e.g.
type cofactor(unsigned iRow, unsigned iCol)
Return the cofactor of an element.
Definition: Matrix.h:644
void resize(unsigned n)
Private resize operator.
Definition: Vector.h:156
type trace()
Get the trace of a matrix (sum of the diagonals)
Definition: Matrix.h:624
Matrix< type > operator-(T)
Define a matrix subtraction operator.
Definition: Matrix.h:431
type determinant()
Get the determinant of a matrix.
Definition: Matrix.h:667
Matrix< type > transpose()
Define a transpose operator.
Definition: Matrix.h:555
void operator=(const Matrix< type > &mat)
Assignment operator.
Definition: Matrix.h:237
Matrix< type > reduce(unsigned iRow, unsigned iCol)
Define a reduction operator.
Definition: Matrix.h:740