mu
matrix.h
Go to the documentation of this file.
1 
6 #ifndef MU_MATRIX_H_
7 #define MU_MATRIX_H_
8 
9 #include <algorithm>
10 #include <array>
11 #include <cassert>
12 #include <type_traits>
13 #include <vector>
14 
15 #include "mu/typetraits.h"
16 #include "mu/utility.h"
17 #include "vector.h"
18 
19 namespace mu {
20 
35 template <std::size_t N, std::size_t M, typename T>
36 class Matrix {
37  static_assert(N != 0, "first matrix dimension (rows) cannot be zero");
38  static_assert(M != 0, "second matrix dimension (columns) cannot be zero");
39  static_assert(std::is_arithmetic<T>::value,
40  "Matrix type T must be an arithmetic type");
41 
42  public:
43  /* value and size type from the underlying container */
44  using value_type = typename std::array<Vector<M, T>, N>::value_type;
45  using size_type = typename std::array<Vector<M, T>, N>::size_type;
46  /* use iterators from the underlying container */
47  using iterator = typename std::array<Vector<M, T>, N>::iterator;
48  using const_iterator = typename std::array<Vector<M, T>, N>::const_iterator;
49 
56  constexpr Matrix() = default;
57 
69  template <typename... TArgs,
70  std::enable_if_t<
71  sizeof...(TArgs) == N &&
72  (mu::conjunction<std::is_same<
73  T, std::remove_reference_t<TArgs>>::value...>::value),
74  int> = 0>
75  // NOLINTNEXTLINE(runtime/explicit) implicit to make copy-init. work
76  Matrix(TArgs const(&&... rows)[M]) : data_{mu::to_array(rows)...} {}
77 
92  template <std::size_t Nn, std::size_t Mm, class U>
93  // NOLINTNEXTLINE(runtime/explicit) implicit conversion is intentional
95  static_assert(N == Nn, "Matrix dimension mismatch (rows)");
96  static_assert(M == Mm, "Matrix dimension mismatch (columns)");
97  std::transform(m.begin(), m.end(), begin(),
98  [](Vector<M, U> data) { return data; });
99  }
100 
108  // NOLINTNEXTLINE(runtime/explicit) implicit to make copy-init. work
109  Matrix(const std::array<Vector<M, T>, N> &a) : data_{a} {}
110 
123  template <typename U = T>
124  // NOLINTNEXTLINE(runtime/explicit) implicit to make copy-init. work
125  Matrix(const std::array<Vector<M, U>, N> &a) {
126  std::transform(a.begin(), a.end(), begin(),
127  [](Vector<M, U> data) { return data; });
128  }
129 
142  template <typename U = T,
143  std::enable_if_t<std::is_arithmetic<U>::value, int> = 0>
144  // NOLINTNEXTLINE(runtime/explicit) implicit to make copy-init. work
145  Matrix(const std::array<std::array<U, M>, N> &a) {
146  std::transform(a.begin(), a.end(), begin(),
147  [](Vector<M, U> data) { return data; });
148  }
149 
163  template <typename U = T,
164  std::enable_if_t<std::is_arithmetic<U>::value, int> = 0>
165  // NOLINTNEXTLINE(runtime/explicit) implicit to make copy-init. work
166  Matrix(const U &value) {
167  data_.fill(value);
168  }
169 
174  ~Matrix() = default;
175 
183  Matrix(const Matrix &other) = default;
184 
192  Matrix(Matrix &&other) noexcept = default;
193 
202  Matrix &operator=(const Matrix &other) = default;
203 
212  Matrix &operator=(Matrix &&other) noexcept = default;
213 
224  Vector<M, T> &operator[](size_type idx) noexcept { return data_[idx]; }
225 
236  const Vector<M, T> &operator[](size_type idx) const noexcept {
237  return data_[idx];
238  }
239 
249  Vector<M, T> &at(size_type idx) { return data_.at(idx); }
250 
260  const Vector<M, T> &at(size_type idx) const { return data_.at(idx); }
261 
272  constexpr std::array<size_type, 2> size() const noexcept {
273  return std::array<size_type, 2>{N, M};
274  }
275 
283  constexpr size_type n_rows() const noexcept { return N; }
284 
292  constexpr size_type n_cols() const noexcept { return M; }
293 
301  iterator begin() noexcept { return data_.begin(); }
302 
310  const_iterator begin() const noexcept { return data_.begin(); }
311 
319  iterator end() noexcept { return data_.end(); }
320 
328  const_iterator end() const noexcept { return data_.end(); }
329 
340  Vector<M, T> row(const size_type &idx) const {
341  /* runtime check for out-of-range. only in debug mode */
342  assert(idx >= 0 && idx < N);
343  return data_[idx];
344  }
345 
356  Vector<N, T> col(const size_type &idx) const {
357  /* runtime check for out-of-range. only in debug mode */
358  assert(idx >= 0 && idx < M);
359  Vector<N, T> ret;
360  for (std::size_t i = 0; i < N; i++) {
361  ret[i] = data_[i][idx];
362  }
363  return ret;
364  }
365 
373  T min() const {
374  T ret(data_[0][0]);
375  for (const auto &row : data_) {
376  ret = mu::min(ret, mu::min(row));
377  }
378  return ret;
379  }
380 
388  T max() const {
389  T ret(data_[0][0]);
390  for (const auto &row : data_) {
391  ret = mu::max(ret, mu::max(row));
392  }
393  return ret;
394  }
395 
403  T sum() const {
404  T ret{};
405  for (const auto &row : data_) {
406  ret += mu::sum(row);
407  }
408  return ret;
409  }
410 
422  template <typename U = T>
423  U mean() const {
424  return U(sum()) / (N * M);
425  }
426 
442  auto diag() const {
443  constexpr std::size_t s = N < M ? N : M;
444  Vector<s, T> ret;
445  for (std::size_t i = 0; i < s; i++) {
446  ret[i] = data_[i][i];
447  }
448  return ret;
449  }
450 
460  T det() const {
461  static_assert(N == M,
462  "Matrix dimensions must match to calculate the determinant");
463  std::vector<std::vector<T>> vv;
464  for (std::size_t i = 0; i < N; i++) {
465  vv.push_back(std::vector<T>());
466  for (const auto &item : data_[i]) {
467  vv[i].push_back(item);
468  }
469  }
470  return calc_det(vv);
471  }
472 
481  void transpose() {
482  static_assert(
483  N == M,
484  "Matrix dimensions must match to transpose this object. For Matrices "
485  "with unequal dimensions, i.e. N != M, the \"transposed()\" method can "
486  "be used instead");
487  Matrix<N, M, T> copy = data_;
488  for (std::size_t i = 0; i < N; i++) {
489  for (std::size_t j = 0; j < M; j++) {
490  data_[j][i] = copy[i][j];
491  }
492  }
493  }
494 
503  Matrix<M, N, T> ret;
504  for (std::size_t i = 0; i < N; i++) {
505  for (std::size_t j = 0; j < M; j++) {
506  ret[j][i] = data_[i][j];
507  }
508  }
509  return ret;
510  }
511 
547  template <typename U = void, std::size_t N2, std::size_t M2, typename T2>
548  std::conditional_t<std::is_same<U, void>::value, Matrix<N, M2, T>,
550  dot(const Matrix<N2, M2, T2> &rhs) const {
551  static_assert(
552  M == N2,
553  "Matrix dimension mismatch. Second dimension of first matrix must be "
554  "equal to the first dimension of the second matrix");
555  using U_ = std::conditional_t<!std::is_same<T, T2>::value, U, T>;
556  static_assert(!std::is_same<U_, void>::value,
557  "Matrix types are different. please specify the return "
558  "type. e.g. \"mat1.dot<float>(mat2);\"");
559  Matrix<N, M2, U_> ret;
560  for (std::size_t i = 0; i < N; i++) {
561  for (std::size_t j = 0; j < M2; j++) {
562  U_ sum{0};
563  for (std::size_t k = 0; k < M; k++) {
564  sum += (data_[i][k] * rhs[k][j]);
565  }
566  ret[i][j] = sum;
567  }
568  }
569  return ret;
570  }
571 
603  template <typename U = void, std::size_t N2, typename T2>
604  std::conditional_t<std::is_same<U, void>::value, Vector<N, T>, Vector<N, U>>
605  dot(const Vector<N2, T2> &rhs) const {
606  static_assert(
607  M == N2,
608  "Matrix-Vector dimension mismatch. Second dimension of the matrix "
609  "must be equal to the vector size");
610  using U_ = std::conditional_t<!std::is_same<T, T2>::value, U, T>;
611  static_assert(
612  !std::is_same<U_, void>::value,
613  "Matrix and Vector types are different. please specify the return "
614  "type. e.g. \"mat.dot<float>(vec);\"");
615  Vector<N, U_> ret;
616  for (std::size_t i = 0; i < N; i++) {
617  U_ sum{0};
618  for (std::size_t k = 0; k < M; k++) {
619  sum += (data_[i][k] * rhs[k]);
620  }
621  ret[i] = sum;
622  }
623  return ret;
624  }
625 
636  template <class U = T>
637  U std() const {
638  U sum{0};
639  U m = mean<U>();
640  for (const auto &row : data_) {
641  for (const auto &item : row) {
642  sum += mu::pow(item - m, 2);
643  }
644  }
645  return U(mu::sqrt(sum / (N * M)));
646  }
647 
648  /********************************* I/O ***********************************/
649 
663  template <std::size_t Nn, std::size_t Mm, class U>
664  friend std::ostream &operator<<(std::ostream &os, const Matrix<Nn, Mm, U> &m);
665 
666  /*************************** matrix <> matrix ****************************/
667 
676  template <typename U = T>
677  bool operator==(const Matrix<N, M, U> &rhs) const {
678  for (std::size_t i = 0; i < N; i++) {
679  /* forward comparison to Vector class */
680  if (data_[i] != rhs[i]) {
681  return false;
682  }
683  }
684  return true;
685  }
686 
693  template <typename U = T>
694  bool operator!=(const Matrix<N, M, U> &rhs) const {
695  return !operator==(rhs);
696  }
697 
707  template <typename U = T>
709  for (std::size_t i = 0; i < N; i++) {
710  data_[i] += rhs[i];
711  }
712  return *this;
713  }
714 
724  template <typename U = T>
726  for (std::size_t i = 0; i < N; i++) {
727  data_[i] -= rhs[i];
728  }
729  return *this;
730  }
731 
741  template <typename U = T>
743  for (std::size_t i = 0; i < N; i++) {
744  data_[i] *= rhs[i];
745  }
746  return *this;
747  }
748 
758  template <typename U = T>
760  for (std::size_t i = 0; i < N; i++) {
761  data_[i] /= rhs[i];
762  }
763  return *this;
764  }
765 
766  /*************************** matrix <> scalar ****************************/
767 
768  /*
769  * see Vector for more information
770  */
771 
780  template <class TScalar>
781  typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
782  Matrix<N, M, T> &>
783  operator+=(const TScalar &scalar) {
784  for (auto &row : data_) {
785  row += scalar;
786  }
787  return *this;
788  }
789 
798  template <class TScalar>
799  typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
800  Matrix<N, M, T> &>
801  operator-=(const TScalar &scalar) {
802  for (auto &row : data_) {
803  row -= scalar;
804  }
805  return *this;
806  }
807 
816  template <class TScalar>
817  typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
818  Matrix<N, M, T> &>
819  operator*=(const TScalar &scalar) {
820  for (auto &row : data_) {
821  row *= scalar;
822  }
823  return *this;
824  }
825 
836  template <class TScalar>
837  typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
838  Matrix<N, M, T> &>
839  operator/=(const TScalar &scalar) {
840  /* a division by zero is forwarded to and handled by the Vector class */
841  for (auto &row : data_) {
842  row /= scalar;
843  }
844  return *this;
845  }
846 
847  /*************************************************************************/
848 
849  protected:
850  std::array<Vector<M, T>, N> data_;
851 };
852 
853 /********************************** I/O ************************************/
854 
855 template <std::size_t Nn, std::size_t Mm, class U>
856 std::ostream &operator<<(std::ostream &os, const Matrix<Nn, Mm, U> &m) {
857  os << "[ ";
858  for (std::size_t i = 0; i < Nn; i++) {
859  os << m.data_[i];
860  if (i < (Nn - 1)) {
861  os << ",\n ";
862  } else {
863  os << " ";
864  }
865  }
866  os << "]";
867  return os;
868 }
869 
870 /**************************** matrix <> matrix *****************************/
871 
883 template <std::size_t N, std::size_t M, class T, class U = T>
885  const Matrix<N, M, U> &rhs) {
886  return Matrix<N, M, T>(lhs) += rhs;
887 }
888 
900 template <std::size_t N, std::size_t M, class T, class U = T>
902  const Matrix<N, M, U> &rhs) {
903  return Matrix<N, M, T>(lhs) -= rhs;
904 }
905 
917 template <std::size_t N, std::size_t M, class T, class U = T>
919  const Matrix<N, M, U> &rhs) {
920  return Matrix<N, M, T>(lhs) *= rhs;
921 }
922 
934 template <std::size_t N, std::size_t M, class T, class U = T>
936  const Matrix<N, M, U> &rhs) {
937  return Matrix<N, M, T>(lhs) /= rhs;
938 }
939 
940 /**************************** matrix <> scalar *****************************/
941 
954 template <std::size_t N, std::size_t M, class T, class TScalar>
955 typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
956  Matrix<N, M, T>> inline
957 operator+(const Matrix<N, M, T> &lhs, const TScalar &rhs) {
958  return Matrix<N, M, T>(lhs) += rhs;
959 }
960 
973 template <std::size_t N, std::size_t M, class T, class TScalar>
974 typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
975  Matrix<N, M, T>> inline
976 operator+(const TScalar &lhs, const Matrix<N, M, T> &rhs) {
977  return Matrix<N, M, T>(rhs) += lhs;
978 }
979 
990 template <std::size_t N, std::size_t M, class T, class TScalar>
991 typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
992  Matrix<N, M, T>> inline
993 operator-(const Matrix<N, M, T> &lhs, const TScalar &rhs) {
994  return Matrix<N, M, T>(lhs) -= rhs;
995 }
996 
1009 template <std::size_t N, std::size_t M, class T, class TScalar>
1010 typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
1011  Matrix<N, M, T>> inline
1012 operator*(const Matrix<N, M, T> &lhs, const TScalar &rhs) {
1013  return Matrix<N, M, T>(lhs) *= rhs;
1014 }
1015 
1028 template <std::size_t N, std::size_t M, class T, class TScalar>
1029 typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
1030  Matrix<N, M, T>> inline
1031 operator*(const TScalar &lhs, const Matrix<N, M, T> &rhs) {
1032  return Matrix<N, M, T>(rhs) *= lhs;
1033 }
1034 
1045 template <std::size_t N, std::size_t M, class T, class TScalar>
1046 typename std::enable_if_t<std::is_arithmetic<TScalar>::value,
1047  Matrix<N, M, T>> inline
1048 operator/(const Matrix<N, M, T> &lhs, const TScalar &rhs) {
1049  return Matrix<N, M, T>(lhs) /= rhs;
1050 }
1051 
1052 /************************* convenience functions ***************************/
1053 
1054 template <std::size_t N, std::size_t M, class T>
1055 inline T min(const Matrix<N, M, T> &m) {
1056  return m.min();
1057 }
1058 
1059 template <std::size_t N, std::size_t M, class T>
1060 inline T max(const Matrix<N, M, T> &m) {
1061  return m.max();
1062 }
1063 
1064 template <std::size_t N, std::size_t M, class T>
1065 inline T sum(const Matrix<N, M, T> &m) {
1066  return m.sum();
1067 }
1068 
1069 template <class U = void, std::size_t N, std::size_t M, typename T>
1070 inline std::conditional_t<std::is_same<U, void>::value, T, U> mean(
1071  const Matrix<N, M, T> &m) {
1072  return m
1073  .template mean<std::conditional_t<std::is_same<U, void>::value, T, U>>();
1074 }
1075 
1076 template <std::size_t N, std::size_t M, typename T>
1077  std::conditional_t <
1078  N<M, Vector<N, T>, Vector<M, T>> diag(const Matrix<N, M, T> &m) {
1079  return m.diag();
1080 }
1081 
1092 template <std::size_t N, typename T>
1093 inline Matrix<N, N, T> diag(const Vector<N, T> &v) {
1094  Matrix<N, N, T> ret{};
1095  for (std::size_t i = 0; i < N; i++) {
1096  ret[i][i] = v[i];
1097  }
1098  return ret;
1099 }
1100 
1101 template <std::size_t N, std::size_t M, typename T>
1102 T det(const Matrix<N, M, T> &m) {
1103  return m.det();
1104 }
1105 
1106 template <std::size_t N, std::size_t M, typename T>
1107 // NOLINTNEXTLINE(runtime/references) intentional non-const reference
1108 inline void transpose(Matrix<N, M, T> &m) {
1109  m.transpose();
1110 }
1111 
1112 template <std::size_t N, std::size_t M, typename T>
1114  return m.transposed();
1115 }
1116 
1117 template <typename U = void, std::size_t N1, std::size_t M1, typename T1,
1118  std::size_t N2, std::size_t M2, typename T2>
1119 std::conditional_t<std::is_same<U, void>::value, Matrix<N1, M2, T1>,
1121 dot(const Matrix<N1, M1, T1> &lhs, const Matrix<N2, M2, T2> &rhs) {
1122  return lhs.template dot<U>(rhs);
1123 }
1124 
1125 template <typename U = void, std::size_t N, std::size_t M, typename T,
1126  std::size_t N2, typename T2>
1127 std::conditional_t<std::is_same<U, void>::value, Vector<N, T>, Vector<N, U>>
1128 dot(const Matrix<N, M, T> &lhs, const Vector<N2, T2> &rhs) {
1129  return lhs.template dot<U>(rhs);
1130 }
1131 
1132 template <std::size_t S, typename T = int>
1133 inline Matrix<S, S, T> eye() {
1134  Matrix<S, S, T> ret{};
1135  for (std::size_t i = 0; i < S; i++) {
1136  ret[i][i] = T{1};
1137  }
1138  return ret;
1139 }
1140 
1141 template <std::size_t N, std::size_t M, typename T = int>
1142 inline Matrix<N, M, T> ones() {
1143  return Matrix<N, M, T>{T{1}};
1144 }
1145 
1146 template <std::size_t N, std::size_t M, typename T = int>
1147 inline Matrix<N, M, T> zeros() {
1148  return Matrix<N, M, T>{T{0}};
1149 }
1150 
1151 } // namespace mu
1152 
1153 namespace mu {
1154 
1155 /* alias templates for Matrix */
1156 
1163 template <std::size_t N, typename T>
1165 
1171 template <typename T>
1173 
1179 template <typename T>
1181 
1182 } // namespace mu
1183 #endif // MU_MATRIX_H_
Matrix< N, M, T > operator-(const Matrix< N, M, T > &lhs, const Matrix< N, M, U > &rhs)
minus operator
Definition: matrix.h:901
std::enable_if_t< std::is_arithmetic< TScalar >::value, Matrix< N, M, T > & > operator*=(const TScalar &scalar)
multiply a scalar with this matrix
Definition: matrix.h:819
Matrix< N, M, T > & operator/=(const Matrix< N, M, U > &rhs)
divison equal operator
Definition: matrix.h:759
Vector< M, T > row(const size_type &idx) const
get a matrix row as a vector
Definition: matrix.h:340
U mean() const
mean of all the elements of the matrix
Definition: matrix.h:423
Matrix< N, M, T > operator/(const Matrix< N, M, T > &lhs, const Matrix< N, M, U > &rhs)
division operator
Definition: matrix.h:935
Matrix(TArgs const(&&... rows)[M])
Construct a new Matrix object from a number of NxM values.
Definition: matrix.h:76
constexpr size_type n_cols() const noexcept
returns the number of columns
Definition: matrix.h:292
constexpr size_type n_rows() const noexcept
returns the number of rows
Definition: matrix.h:283
auto diag() const
returns the diagonal of the matrix as a vector
Definition: matrix.h:442
Vector< M, T > & operator[](size_type idx) noexcept
access a row within the matrix
Definition: matrix.h:224
std::enable_if_t< std::is_arithmetic< TScalar >::value, Matrix< N, M, T > & > operator+=(const TScalar &scalar)
add a scalar to this matrix
Definition: matrix.h:783
Matrix< N, M, T > operator*(const Matrix< N, M, T > &lhs, const Matrix< N, M, U > &rhs)
multiplication operator
Definition: matrix.h:918
Vector< N, T > col(const size_type &idx) const
get a matrix column as a vector
Definition: matrix.h:356
std::conditional_t< std::is_same< U, void >::value, Vector< N, T >, Vector< N, U > > dot(const Vector< N2, T2 > &rhs) const
dot product of a matrix and a vector
Definition: matrix.h:605
Matrix< N, M, T > & operator*=(const Matrix< N, M, U > &rhs)
multiplication equal operator
Definition: matrix.h:742
A generic vector.
Definition: vector.h:48
U std() const
calculates the standard deviation
Definition: matrix.h:637
iterator end() noexcept
returns a iterator starting at one after the last row
Definition: matrix.h:319
void transpose()
transposes this Matrix object
Definition: matrix.h:481
constexpr Matrix()=default
Construct a new Matrix object.
T det() const
calculates the determinant of the matrix
Definition: matrix.h:460
Matrix(const std::array< Vector< M, T >, N > &a)
Construct a new Matrix object from an std::array of Vectors.
Definition: matrix.h:109
iterator begin() noexcept
returns an iterator starting at the first row
Definition: matrix.h:301
bool operator==(const Matrix< N, M, U > &rhs) const
equality operator
Definition: matrix.h:677
Matrix(const std::array< std::array< U, M >, N > &a)
Construct a new Matrix object from an std::array of std::arrays. possibly of a different type...
Definition: matrix.h:145
bool operator!=(const Matrix< N, M, U > &rhs) const
unequality operator
Definition: matrix.h:694
Vector< M, T > & at(size_type idx)
access a row within the matrix
Definition: matrix.h:249
Matrix< N, M, T > operator+(const Matrix< N, M, T > &lhs, const Matrix< N, M, U > &rhs)
plus operator
Definition: matrix.h:884
const_iterator end() const noexcept
returns a const iterator starting at one after the last row
Definition: matrix.h:328
T min() const
get the min value of the matrix
Definition: matrix.h:373
const Vector< M, T > & at(size_type idx) const
const access a row within the matrix
Definition: matrix.h:260
const_iterator begin() const noexcept
returns a const iterator starting at the first row
Definition: matrix.h:310
Matrix(const U &value)
Construct a new Matrix object from a single value possibly of a different type.
Definition: matrix.h:166
Matrix(const std::array< Vector< M, U >, N > &a)
Construct a new Matrix object from an std::array of Vectors of a different type.
Definition: matrix.h:125
Definition: literals.h:11
Matrix(const Matrix< Nn, Mm, U > &m)
Construct a new Matrix from an existing Matrix of a different type.
Definition: matrix.h:94
A generic matrix.
Definition: matrix.h:36
const Vector< M, T > & operator[](size_type idx) const noexcept
const access a row within the matrix
Definition: matrix.h:236
std::enable_if_t< std::is_arithmetic< TScalar >::value, Matrix< N, M, T > & > operator/=(const TScalar &scalar)
divide every element of this matrix by a scalar
Definition: matrix.h:839
~Matrix()=default
Destroy the Matrix object.
Matrix< N, M, T > & operator-=(const Matrix< N, M, U > &rhs)
minus equal operator
Definition: matrix.h:725
std::enable_if_t< std::is_arithmetic< TScalar >::value, Matrix< N, M, T > & > operator-=(const TScalar &scalar)
subtract a scalar from every element of this matrix
Definition: matrix.h:801
Matrix & operator=(const Matrix &other)=default
Copy assignment operator.
constexpr std::array< size_type, 2 > size() const noexcept
returns the matrix dimensions as an array of size 2
Definition: matrix.h:272
Matrix< M, N, T > transposed() const
creates and returns a transposed Matrix object
Definition: matrix.h:502
std::conditional_t< std::is_same< U, void >::value, Matrix< N, M2, T >, Matrix< N, M2, U > > dot(const Matrix< N2, M2, T2 > &rhs) const
dot product of two matrices
Definition: matrix.h:550
Matrix< N, M, T > & operator+=(const Matrix< N, M, U > &rhs)
plus equal operator
Definition: matrix.h:708
T max() const
get the max value of the matrix
Definition: matrix.h:388
T sum() const
sum up all the elements of the matrix
Definition: matrix.h:403