PX4 Firmware
PX4 Autopilot Software http://px4.io
Matrix.hpp
Go to the documentation of this file.
1 /**
2  * @file Matrix.hpp
3  *
4  * A simple matrix template library.
5  *
6  * @author James Goppert <james.goppert@gmail.com>
7  */
8 
9 #pragma once
10 
11 #include <cstdio>
12 #include <cstring>
13 
14 #if defined(SUPPORT_STDIOSTREAM)
15 #include <iostream>
16 #include <iomanip>
17 #endif // defined(SUPPORT_STDIOSTREAM)
18 
19 #include "math.hpp"
20 
21 // There is a bug in GCC 4.8, which causes the compiler to segfault due to array {} constructors.
22 // Do for-loop constructors just for GCC 4.8
23 #ifdef __GNUC__
24 #define MATRIX_GCC_4_8_WORKAROUND (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9))
25 #else
26 #define MATRIX_GCC_4_8_WORKAROUND 0
27 #endif
28 
29 namespace matrix
30 {
31 
32 template <typename Type, size_t M>
33 class Vector;
34 
35 template<typename Type, size_t M, size_t N>
36 class Matrix;
37 
38 template <typename Type, size_t P, size_t Q, size_t M, size_t N>
39 class Slice;
40 
41 template<typename Type, size_t M, size_t N>
42 class Matrix
43 {
44 #if MATRIX_GCC_4_8_WORKAROUND
45  Type _data[M][N];
46 #else
47  Type _data[M][N] {};
48 #endif
49 
50 public:
51 
52  // Constructors
53 #if MATRIX_GCC_4_8_WORKAROUND
54  Matrix()
55  {
56  for (size_t i = 0; i < M; i++) {
57  for (size_t j = 0; j < N; j++) {
58  _data[i][j] = Type{};
59  }
60  }
61  }
62 #else
63  Matrix() = default;
64 #endif
65 
66  explicit Matrix(const Type data_[M*N])
67  {
68  memcpy(_data, data_, sizeof(_data));
69  }
70 
71  explicit Matrix(const Type data_[M][N])
72  {
73  memcpy(_data, data_, sizeof(_data));
74  }
75 
76  Matrix(const Matrix &other)
77  {
78  memcpy(_data, other._data, sizeof(_data));
79  }
80 
81  template<size_t P, size_t Q>
83  {
84  Matrix<Type, M, N>& self = *this;
85  for (size_t i = 0; i < M; i++) {
86  for (size_t j = 0; j < N; j++) {
87  self(i, j) = in_slice(i, j);
88  }
89  }
90  }
91 
92  /**
93  * Accessors/ Assignment etc.
94  */
95 
96 
97  inline Type operator()(size_t i, size_t j) const
98  {
99  return _data[i][j];
100  }
101 
102  inline Type &operator()(size_t i, size_t j)
103  {
104  return _data[i][j];
105  }
106 
108  {
109  if (this != &other) {
110  memcpy(_data, other._data, sizeof(_data));
111  }
112  return (*this);
113  }
114 
115  void copyTo(Type dst[M*N]) const
116  {
117  memcpy(dst, _data, sizeof(Type)*M*N);
118  }
119 
120  void copyToColumnMajor(Type dst[M*N]) const
121  {
122  const Matrix<Type, M, N> &self = *this;
123 
124  for (size_t i = 0; i < M; i++) {
125  for (size_t j = 0; j < N; j++) {
126  dst[i+(j*M)] = self(i, j);
127  }
128  }
129  }
130 
131  /**
132  * Matrix Operations
133  */
134 
135  // this might use a lot of programming memory
136  // since it instantiates a class for every
137  // required mult pair, but it provides
138  // compile time size_t checking
139  template<size_t P>
141  {
142  const Matrix<Type, M, N> &self = *this;
143  Matrix<Type, M, P> res;
144  res.setZero();
145 
146  for (size_t i = 0; i < M; i++) {
147  for (size_t k = 0; k < P; k++) {
148  for (size_t j = 0; j < N; j++) {
149  res(i, k) += self(i, j) * other(j, k);
150  }
151  }
152  }
153 
154  return res;
155  }
156 
158  {
159  Matrix<Type, M, N> res;
160  const Matrix<Type, M, N> &self = *this;
161 
162  for (size_t i = 0; i < M; i++) {
163  for (size_t j = 0; j < N; j++) {
164  res(i, j) = self(i, j)*other(i, j);
165  }
166  }
167 
168  return res;
169  }
170 
172  {
173  Matrix<Type, M, N> res;
174  const Matrix<Type, M, N> &self = *this;
175 
176  for (size_t i = 0; i < M; i++) {
177  for (size_t j = 0; j < N; j++) {
178  res(i, j) = self(i, j)/other(i, j);
179  }
180  }
181 
182  return res;
183  }
184 
186  {
187  Matrix<Type, M, N> res;
188  const Matrix<Type, M, N> &self = *this;
189 
190  for (size_t i = 0; i < M; i++) {
191  for (size_t j = 0; j < N; j++) {
192  res(i, j) = self(i, j) + other(i, j);
193  }
194  }
195 
196  return res;
197  }
198 
200  {
201  Matrix<Type, M, N> res;
202  const Matrix<Type, M, N> &self = *this;
203 
204  for (size_t i = 0; i < M; i++) {
205  for (size_t j = 0; j < N; j++) {
206  res(i, j) = self(i, j) - other(i, j);
207  }
208  }
209 
210  return res;
211  }
212 
213  // unary minus
215  {
216  Matrix<Type, M, N> res;
217  const Matrix<Type, M, N> &self = *this;
218 
219  for (size_t i = 0; i < M; i++) {
220  for (size_t j = 0; j < N; j++) {
221  res(i, j) = -self(i, j);
222  }
223  }
224 
225  return res;
226  }
227 
228  void operator+=(const Matrix<Type, M, N> &other)
229  {
230  Matrix<Type, M, N> &self = *this;
231  self = self + other;
232  }
233 
234  void operator-=(const Matrix<Type, M, N> &other)
235  {
236  Matrix<Type, M, N> &self = *this;
237  self = self - other;
238  }
239 
240  template<size_t P>
241  void operator*=(const Matrix<Type, N, P> &other)
242  {
243  Matrix<Type, M, N> &self = *this;
244  self = self * other;
245  }
246 
247  /**
248  * Scalar Operations
249  */
250 
251  Matrix<Type, M, N> operator*(Type scalar) const
252  {
253  Matrix<Type, M, N> res;
254  const Matrix<Type, M, N> &self = *this;
255 
256  for (size_t i = 0; i < M; i++) {
257  for (size_t j = 0; j < N; j++) {
258  res(i, j) = self(i, j) * scalar;
259  }
260  }
261 
262  return res;
263  }
264 
265  inline Matrix<Type, M, N> operator/(Type scalar) const
266  {
267  return (*this)*(1/scalar);
268  }
269 
270  Matrix<Type, M, N> operator+(Type scalar) const
271  {
272  Matrix<Type, M, N> res;
273  const Matrix<Type, M, N> &self = *this;
274 
275  for (size_t i = 0; i < M; i++) {
276  for (size_t j = 0; j < N; j++) {
277  res(i, j) = self(i, j) + scalar;
278  }
279  }
280 
281  return res;
282  }
283 
284  inline Matrix<Type, M, N> operator-(Type scalar) const
285  {
286  return (*this) + (-1*scalar);
287  }
288 
289  void operator*=(Type scalar)
290  {
291  Matrix<Type, M, N> &self = *this;
292 
293  for (size_t i = 0; i < M; i++) {
294  for (size_t j = 0; j < N; j++) {
295  self(i, j) = self(i, j) * scalar;
296  }
297  }
298  }
299 
300  void operator/=(Type scalar)
301  {
302  Matrix<Type, M, N> &self = *this;
303  self = self * (Type(1) / scalar);
304  }
305 
306  inline void operator+=(Type scalar)
307  {
308  *this = (*this) + scalar;
309  }
310 
311  inline void operator-=(Type scalar)
312  {
313  *this = (*this) - scalar;
314  }
315 
316  bool operator==(const Matrix<Type, M, N> &other) const
317  {
318  return isEqual(*this, other);
319  }
320 
321  bool operator!=(const Matrix<Type, M, N> &other) const
322  {
323  const Matrix<Type, M, N> &self = *this;
324  return !(self == other);
325  }
326 
327  /**
328  * Misc. Functions
329  */
330 
331  void write_string(char * buf, size_t n) const
332  {
333  buf[0] = '\0'; // make an empty string to begin with (we need the '\0' for strlen to work)
334  const Matrix<Type, M, N> &self = *this;
335  for (size_t i = 0; i < M; i++) {
336  for (size_t j = 0; j < N; j++) {
337  snprintf(buf + strlen(buf), n - strlen(buf), "\t%8.8g", double(self(i, j))); // directly append to the string buffer
338  }
339  snprintf(buf + strlen(buf), n - strlen(buf), "\n");
340  }
341  }
342 
343  void print(FILE *stream = stdout) const
344  {
345  // element: tab, point, 8 digits; row: newline; string: \0 end
346  static const size_t n = 10*N*M + M + 1;
347  char * buf = new char[n];
348  write_string(buf, n);
349  fprintf(stream, "%s\n", buf);
350  delete[] buf;
351  }
352 
354  {
355  Matrix<Type, N, M> res;
356  const Matrix<Type, M, N> &self = *this;
357 
358  for (size_t i = 0; i < M; i++) {
359  for (size_t j = 0; j < N; j++) {
360  res(j, i) = self(i, j);
361  }
362  }
363 
364  return res;
365  }
366 
367  // tranpose alias
368  inline Matrix<Type, N, M> T() const
369  {
370  return transpose();
371  }
372 
373  template<size_t P, size_t Q>
374  const Slice<Type, P, Q, M, N> slice(size_t x0, size_t y0) const
375  {
376  return Slice<Type, P, Q, M, N>(x0, y0, this);
377  }
378 
379  template<size_t P, size_t Q>
380  Slice<Type, P, Q, M, N> slice(size_t x0, size_t y0)
381  {
382  return Slice<Type, P, Q, M, N>(x0, y0, this);
383  }
384 
385  const Slice<Type, 1, N, M, N> row(size_t i) const
386  {
387  return slice<1, N>(i,0);
388  }
389 
391  {
392  return slice<1, N>(i,0);
393  }
394 
395  const Slice<Type, M, 1, M, N> col(size_t j) const
396  {
397  return slice<M, 1>(0,j);
398  }
399 
401  {
402  return slice<M, 1>(0,j);
403  }
404 
405  void setRow(size_t i, const Matrix<Type, N, 1> &row_in)
406  {
407  slice<1,N>(i,0) = row_in.transpose();
408  }
409 
410 
411  void setCol(size_t j, const Matrix<Type, M, 1> &column)
412  {
413  slice<M,1>(0,j) = column;
414  }
415 
416  void setZero()
417  {
418  memset(_data, 0, sizeof(_data));
419  }
420 
421  inline void zero()
422  {
423  setZero();
424  }
425 
426  void setAll(Type val)
427  {
428  Matrix<Type, M, N> &self = *this;
429 
430  for (size_t i = 0; i < M; i++) {
431  for (size_t j = 0; j < N; j++) {
432  self(i, j) = val;
433  }
434  }
435  }
436 
437  inline void setOne()
438  {
439  setAll(1);
440  }
441 
442  inline void setNaN()
443  {
444  setAll(NAN);
445  }
446 
447  void setIdentity()
448  {
449  setZero();
450  Matrix<Type, M, N> &self = *this;
451 
452  for (size_t i = 0; i < M && i < N; i++) {
453  self(i, i) = 1;
454  }
455  }
456 
457  inline void identity()
458  {
459  setIdentity();
460  }
461 
462  inline void swapRows(size_t a, size_t b)
463  {
464  if (a == b) {
465  return;
466  }
467 
468  Matrix<Type, M, N> &self = *this;
469 
470  for (size_t j = 0; j < N; j++) {
471  Type tmp = self(a, j);
472  self(a, j) = self(b, j);
473  self(b, j) = tmp;
474  }
475  }
476 
477  inline void swapCols(size_t a, size_t b)
478  {
479  if (a == b) {
480  return;
481  }
482 
483  Matrix<Type, M, N> &self = *this;
484 
485  for (size_t i = 0; i < M; i++) {
486  Type tmp = self(i, a);
487  self(i, a) = self(i, b);
488  self(i, b) = tmp;
489  }
490  }
491 
493  {
495  for (size_t i=0; i<M; i++) {
496  for (size_t j=0; j<N; j++) {
497  r(i,j) = Type(fabs((*this)(i,j)));
498  }
499  }
500  return r;
501  }
502 
503  Type max() const
504  {
505  Type max_val = (*this)(0,0);
506  for (size_t i=0; i<M; i++) {
507  for (size_t j=0; j<N; j++) {
508  Type val = (*this)(i,j);
509  if (val > max_val) {
510  max_val = val;
511  }
512  }
513  }
514  return max_val;
515  }
516 
517  Type min() const
518  {
519  Type min_val = (*this)(0,0);
520  for (size_t i=0; i<M; i++) {
521  for (size_t j=0; j<N; j++) {
522  Type val = (*this)(i,j);
523  if (val < min_val) {
524  min_val = val;
525  }
526  }
527  }
528  return min_val;
529  }
530 
531  bool isAllNan() const {
532  const Matrix<float, M, N> &self = *this;
533  bool result = true;
534  for (size_t i = 0; i < M; i++) {
535  for (size_t j = 0; j < N; j++) {
536  result = result && isnan(self(i, j));
537  }
538  }
539  return result;
540  }
541 };
542 
543 template<typename Type, size_t M, size_t N>
546  m.setZero();
547  return m;
548 }
549 
550 template<typename Type, size_t M, size_t N>
553  m.setOne();
554  return m;
555 }
556 
557 template<size_t M, size_t N>
560  m.setNaN();
561  return m;
562 }
563 
564 template<typename Type, size_t M, size_t N>
566 {
567  return other * scalar;
568 }
569 
570 template<typename Type, size_t M, size_t N>
572  const Matrix<Type, M, N> &y, const Type eps=1e-4f) {
573  for (size_t i = 0; i < M; i++) {
574  for (size_t j = 0; j < N; j++) {
575  if (!isEqualF(x(i,j), y(i,j), eps)) {
576  return false;
577  }
578  }
579  }
580  return true;
581 }
582 
583 namespace typeFunction
584 {
585 template<typename Type>
586 Type min(const Type x, const Type y) {
587  bool x_is_nan = isnan(x);
588  bool y_is_nan = isnan(y);
589  // z > nan for z != nan is required by C the standard
590  if (x_is_nan || y_is_nan) {
591  if (x_is_nan && !y_is_nan) {
592  return y;
593  }
594  if (!x_is_nan && y_is_nan) {
595  return x;
596  }
597  return x;
598  }
599  return (x < y) ? x : y;
600 }
601 template<typename Type>
602 Type max(const Type x, const Type y) {
603  bool x_is_nan = isnan(x);
604  bool y_is_nan = isnan(y);
605  // z > nan for z != nan is required by C the standard
606  if (x_is_nan || y_is_nan) {
607  if (x_is_nan && !y_is_nan) {
608  return y;
609  }
610  if (!x_is_nan && y_is_nan) {
611  return x;
612  }
613  return x;
614  }
615  return (x > y) ? x : y;
616 }
617 template<typename Type>
618 Type constrain(const Type x, const Type lower_bound, const Type upper_bound) {
619  if (lower_bound > upper_bound) {
620  return NAN;
621  } else if(isnan(x)) {
622  return NAN;
623  } else {
624  return typeFunction::max(lower_bound, typeFunction::min(upper_bound, x));
625  }
626 }
627 }
628 
629 template<typename Type, size_t M, size_t N>
630 Matrix<Type, M, N> min(const Matrix<Type, M, N> &x, const Type scalar_upper_bound) {
632  for (size_t i = 0; i < M; i++) {
633  for (size_t j = 0; j < N; j++) {
634  m(i,j) = typeFunction::min(x(i,j),scalar_upper_bound);
635  }
636  }
637  return m;
638 }
639 
640 template<typename Type, size_t M, size_t N>
641 Matrix<Type, M, N> min(const Type scalar_upper_bound, const Matrix<Type, M, N> &x) {
642  return min(x, scalar_upper_bound);
643 }
644 
645 template<typename Type, size_t M, size_t N>
648  for (size_t i = 0; i < M; i++) {
649  for (size_t j = 0; j < N; j++) {
650  m(i,j) = typeFunction::min(x1(i,j),x2(i,j));
651  }
652  }
653  return m;
654 }
655 
656 template<typename Type, size_t M, size_t N>
657 Matrix<Type, M, N> max(const Matrix<Type, M, N> &x, const Type scalar_lower_bound) {
659  for (size_t i = 0; i < M; i++) {
660  for (size_t j = 0; j < N; j++) {
661  m(i,j) = typeFunction::max(x(i,j),scalar_lower_bound);
662  }
663  }
664  return m;
665 }
666 
667 template<typename Type, size_t M, size_t N>
668 Matrix<Type, M, N> max(const Type scalar_lower_bound, const Matrix<Type, M, N> &x) {
669  return max(x, scalar_lower_bound);
670 }
671 
672 template<typename Type, size_t M, size_t N>
675  for (size_t i = 0; i < M; i++) {
676  for (size_t j = 0; j < N; j++) {
677  m(i,j) = typeFunction::max(x1(i,j),x2(i,j));
678  }
679  }
680  return m;
681 }
682 
683 template<typename Type, size_t M, size_t N>
685  const Type scalar_lower_bound,
686  const Type scalar_upper_bound) {
688  if (scalar_lower_bound > scalar_upper_bound) {
689  m.setNaN();
690  } else {
691  for (size_t i = 0; i < M; i++) {
692  for (size_t j = 0; j < N; j++) {
693  m(i,j) = typeFunction::constrain(x(i,j), scalar_lower_bound, scalar_upper_bound);
694  }
695  }
696  }
697  return m;
698 }
699 
700 template<typename Type, size_t M, size_t N>
702  const Matrix<Type, M, N> &x_lower_bound,
703  const Matrix<Type, M, N> &x_upper_bound) {
705  for (size_t i = 0; i < M; i++) {
706  for (size_t j = 0; j < N; j++) {
707  m(i,j) = typeFunction::constrain(x(i,j), x_lower_bound(i,j), x_upper_bound(i,j));
708  }
709  }
710  return m;
711 }
712 
713 #if defined(SUPPORT_STDIOSTREAM)
714 template<typename Type, size_t M, size_t N>
715 std::ostream& operator<<(std::ostream& os,
717 {
718  for (size_t i = 0; i < M; ++i) {
719  os << "[";
720  for (size_t j = 0; j < N; ++j) {
721  os << std::setw(10) << matrix(i, j);
722  os << "\t";
723  }
724  os << "]" << std::endl;
725  }
726  return os;
727 }
728 #endif // defined(SUPPORT_STDIOSTREAM)
729 
730 } // namespace matrix
731 
732 /* vim: set et fenc=utf-8 ff=unix sts=0 sw=4 ts=4 : */
Matrix< Type, N, M > T() const
Definition: Matrix.hpp:368
void write_string(char *buf, size_t n) const
Misc.
Definition: Matrix.hpp:331
bool operator==(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:316
Matrix< Type, M, N > operator-(Type scalar) const
Definition: Matrix.hpp:284
Matrix< Type, M, N > & operator=(const Matrix< Type, M, N > &other)
Definition: Matrix.hpp:107
bool isAllNan() const
Definition: Matrix.hpp:531
Matrix< Type, M, N > constrain(const Matrix< Type, M, N > &x, const Type scalar_lower_bound, const Type scalar_upper_bound)
Definition: Matrix.hpp:684
void operator*=(const Matrix< Type, N, P > &other)
Definition: Matrix.hpp:241
Matrix< Type, M, N > ones()
Definition: Matrix.hpp:551
void setCol(size_t j, const Matrix< Type, M, 1 > &column)
Definition: Matrix.hpp:411
Matrix< Type, M, N > operator-() const
Definition: Matrix.hpp:214
void copyTo(Type dst[M *N]) const
Definition: Matrix.hpp:115
Type min(const Type x, const Type y)
Definition: Matrix.hpp:586
Matrix< Type, N, M > transpose() const
Definition: Matrix.hpp:353
void operator/=(Type scalar)
Definition: Matrix.hpp:300
void operator+=(const Matrix< Type, M, N > &other)
Definition: Matrix.hpp:228
void swapRows(size_t a, size_t b)
Definition: Matrix.hpp:462
void setRow(size_t i, const Matrix< Type, N, 1 > &row_in)
Definition: Matrix.hpp:405
Matrix< Type, M, N > operator/(Type scalar) const
Definition: Matrix.hpp:265
const Slice< Type, M, 1, M, N > col(size_t j) const
Definition: Matrix.hpp:395
void operator+=(Type scalar)
Definition: Matrix.hpp:306
Matrix< Type, M, N > operator-(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:199
Slice< Type, 1, N, M, N > row(size_t i)
Definition: Matrix.hpp:390
void setIdentity()
Definition: Matrix.hpp:447
Slice< Type, P, Q, M, N > slice(size_t x0, size_t y0)
Definition: Matrix.hpp:380
Slice< Type, M, 1, M, N > col(size_t j)
Definition: Matrix.hpp:400
const Slice< Type, P, Q, M, N > slice(size_t x0, size_t y0) const
Definition: Matrix.hpp:374
Matrix< Type, M, N > operator+(Type scalar) const
Definition: Matrix.hpp:270
Type & operator()(size_t i, size_t j)
Definition: Matrix.hpp:102
bool isEqual(const Matrix< Type, M, N > &x, const Matrix< Type, M, N > &y, const Type eps=1e-4f)
Definition: Matrix.hpp:571
void print(FILE *stream=stdout) const
Definition: Matrix.hpp:343
Type _data[M][N]
Definition: Matrix.hpp:47
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
Matrix< Type, M, N > abs() const
Definition: Matrix.hpp:492
Matrix(const Slice< Type, M, N, P, Q > &in_slice)
Definition: Matrix.hpp:82
void zero()
Definition: Matrix.hpp:421
Matrix< Type, M, P > operator*(const Matrix< Type, N, P > &other) const
Matrix Operations.
Definition: Matrix.hpp:140
Matrix< Type, M, N > operator*(Type scalar) const
Scalar Operations.
Definition: Matrix.hpp:251
void operator-=(Type scalar)
Definition: Matrix.hpp:311
Matrix< Type, M, N > edivide(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:171
void setNaN()
Definition: Matrix.hpp:442
Matrix< float, M, N > nans()
Definition: Matrix.hpp:558
Matrix()=default
Type min() const
Definition: Matrix.hpp:517
void operator-=(const Matrix< Type, M, N > &other)
Definition: Matrix.hpp:234
Type max() const
Definition: Matrix.hpp:503
void setOne()
Definition: Matrix.hpp:437
const Slice< Type, 1, N, M, N > row(size_t i) const
Definition: Matrix.hpp:385
bool isEqualF(const Type x, const Type y, const Type eps=1e-4f)
Compare if two floating point numbers are equal.
P[0][0]
Definition: quatCovMat.c:44
Matrix(const Type data_[M][N])
Definition: Matrix.hpp:71
void setZero()
Definition: Matrix.hpp:416
Matrix(const Type data_[M *N])
Definition: Matrix.hpp:66
void copyToColumnMajor(Type dst[M *N]) const
Definition: Matrix.hpp:120
void identity()
Definition: Matrix.hpp:457
void setAll(Type val)
Definition: Matrix.hpp:426
Type operator()(size_t i, size_t j) const
Accessors/ Assignment etc.
Definition: Matrix.hpp:97
void swapCols(size_t a, size_t b)
Definition: Matrix.hpp:477
bool operator!=(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:321
Matrix< Type, M, N > operator+(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:185
Matrix< Type, M, N > emult(const Matrix< Type, M, N > &other) const
Definition: Matrix.hpp:157
void operator*=(Type scalar)
Definition: Matrix.hpp:289
Matrix(const Matrix &other)
Definition: Matrix.hpp:76
Matrix< Type, M, N > zeros()
Definition: Matrix.hpp:544
Type constrain(const Type x, const Type lower_bound, const Type upper_bound)
Definition: Matrix.hpp:618
Type max(const Type x, const Type y)
Definition: Matrix.hpp:602