tinymatrixmath
TMM_matrix.hpp
1 #pragma once
2 
3 
4 
5 #include "TMM_enable_if.hpp"
6 #ifdef ARDUINO
7 
8  #pragma weak dtostrf // for fixed-width float printing to serial to create uniform-looking matrices
9  extern "C" {
10  extern char* dtostrf (double __val, signed char __width, unsigned char __prec, char * __s);
11  }
12  extern char* (*dtostrf_func)(double, signed char, unsigned char, char *);
13 
14  #include <Arduino.h>
15 #endif
16 #ifdef USING_STANDARD_LIBRARY // a macro defined in CMakeLists.txt
17  #include <iostream>
18  #include <iomanip>
19 #endif
20 
21 
22 namespace tmm{
23 
24 
25  typedef unsigned char Size;
26 
27  template<Size n, Size m, typename Scalar = float>
28  class Matrix{
29  public:
30 
31  Scalar data[n][m];
32 
33  Matrix(){
34  for(Size i = 0; i < n; i++)
35  for(Size j = 0; j < m; j++)
36  data[i][j]=0;
37  }
38 
39  Matrix(const float M[n][m]){
40  for(Size i = 0; i < n; i++)
41  for(Size j = 0; j < m; j++)
42  data[i][j]=M[i][j];
43  }
44 
45  Matrix(const float M){
46  for(Size i = 0; i < n; i++)
47  for(Size j = 0; j < m; j++)
48  data[i][j]=M;
49  }
50 
51 
52  // Set this matrix to the value of another matrix
53  void
54  operator=(const Matrix<n,m,Scalar> &M){
55  for(Size i = 0; i < n; i++)
56  for(Size j = 0; j < m; j++)
57  data[i][j]=M.data[i][j];
58  }
59 
60 
61  // Set this matrix to the value of a 2D array of scalars
62  void
63  operator=(const Scalar M[n][m])
64  {
65  for(Size i = 0; i < n; i++)
66  for(Size j = 0; j < m; j++)
67  data[i][j]=M[i][j];
68  }
69 
70 
71  // Set all values in the matrix to be a scalar
72  void
73  operator=(const Scalar value)
74  {
75  for(Size i = 0; i < n; i++)
76  for(Size j = 0; j < m; j++)
77  data[i][j]=value;
78  }
79 
80 
81  Scalar*
82  operator[](Size i)
83  {return data[i];}
84 
86  template<typename T = Scalar, typename = tmm::enable_if_t<(m==1&&n==1), T>> operator T() {
87  return data[0][0];
88  }
89 
95  template<typename Other_Scalar>
96  bool equals(const Matrix<n,m,Scalar> &other, Scalar tolerance) const {
97  for(Size i = 0; i < n; i++)
98  for(Size j = 0; j < m; j++){
99  Scalar comp = data[i][j]-other.data[i][j];
100  if(comp < -tolerance || comp > tolerance) return false;
101  }
102  return true;
103  }
104 
109  template<typename Other_Scalar>
110  bool operator==(const Matrix<n,m,Other_Scalar> &other) const {
111  return equals<Other_Scalar>(other, 0.f);
112  }
113 
114 
115 
116  template<Size q>
118  augmentAfter(const Matrix<n,q,Scalar> &other) const
119  {
121  for(Size i = 0; i < n; i++)
122  for(Size j = 0; j < m; j++)
123  M[i][j]=data[i][j];
124 
125 
126  for(Size i = 0; i < n; i++)
127  for(Size j = 0; j < m; j++)
128  M[i][j+m]=other.data[i][j];
129 
130  return M;
131  }
132 
133 
134  template<Size q>
135  Matrix<n,m+q,Scalar>
136  augmentBefore(const Matrix<n,q,Scalar> &other) const
137  {
138  Matrix<n,m+q,Scalar> M;
139  for(Size i = 0; i < n; i++)
140  for(Size j = 0; j < m; j++)
141  M[i][j+q]=data[i][j];
142 
143 
144  for(Size i = 0; i < n; i++)
145  for(Size j = 0; j < m; j++)
146  M[i][j]=other[i][j];
147 
148  return M;
149  }
150 
151 
152  template<Size p>
153  Matrix<n+p,m,Scalar>
154  augmentAbove(const Matrix<p,m,Scalar> &other) const
155  {
156  Matrix<n+p,m,Scalar> M;
157  for(Size i = 0; i < n; i++)
158  for(Size j = 0; j < m; j++)
159  M[i+p][j]=data[i][j];
160 
161 
162  for(Size i = 0; i < n; i++)
163  for(Size j = 0; j < m; j++)
164  M[i][j]=other.data[i][j];
165 
166  return M;
167  }
168 
169 
170 
171  template<Size p>
172  Matrix<n+p,m,Scalar>
173  augmentBelow(const Matrix<p,m,Scalar> &other) const
174  {
175  Matrix<n+p,m,Scalar> M;
176  for(Size i = 0; i < n; i++)
177  for(Size j = 0; j < m; j++)
178  M[i][j]=data[i][j];
179 
180 
181  for(Size i = 0; i < n; i++)
182  for(Size j = 0; j < m; j++)
183  M[i+n][j]=other.data[i][j];
184 
185  return M;
186  }
187 
188 
189  // Matrix-matrix multiplication
190  // For elementwise multiplication, use elementwise_multiplication(...)
191  template<Size q>
192  Matrix<n,q,Scalar>
193  operator *(const Matrix<m,q,Scalar> &other) const
194  {
195  Matrix<n,q,Scalar> M;
196  for(Size i = 0; i < n; i++)
197  for(Size j = 0; j < q; j++)
198  for(Size k = 0; k < m; k++)
199  M[i][j]+=data[i][k]*other.data[k][j];
200  return M;
201  }
202 
203 
204 
205 
206  // Elementwise multiplication
207  Matrix<n,m,Scalar>
208  elementwise_times(const Matrix<n,m,Scalar> &other) const
209  {
210  Matrix<n,m,Scalar> M;
211  for(Size i = 0; i < n; i++)
212  for(Size j = 0; j < m; j++)
213  M[i][j]=data[i][j]*other.data[i][j];
214  return M;
215  }
216 
217 
218 
219 
220  // Elementwise multiplication
221  Matrix<n,m,Scalar>
222  negate() const
223  {
224  Matrix<n,m,Scalar> M;
225  for(Size i = 0; i < n; i++)
226  for(Size j = 0; j < m; j++)
227  M[i][j]=-data[i][j];
228  return M;
229  }
230 
231 
232 
233 
234 
235  Matrix<n,m,Scalar>
236  operator +(const Matrix<n,m,Scalar> &other) const
237  {
238  Matrix<n,m,Scalar> M;
239  for(Size i = 0; i < n; i++)
240  for(Size j = 0; j < m; j++)
241  M[i][j]=data[i][j]+other.data[i][j];
242  return M;
243  }
244 
245 
246 
247  Matrix<n,m,Scalar>
248  operator -(const Matrix<n,m,Scalar> &other) const
249  {
250  Matrix<n,m,Scalar> M;
251  for(Size i = 0; i < n; i++)
252  for(Size j = 0; j < m; j++)
253  M[i][j]=data[i][j]-other.data[i][j];
254  return M;
255  }
256 
257 
258 
259  Matrix<n,m,Scalar>
260  operator +(Scalar a) const
261  {
262  Matrix<n,m,Scalar> M;
263  for(Size i = 0; i < n; i++)
264  for(Size j = 0; j < m; j++)
265  M[i][j]=data[i][j]+a;
266  return M;
267  }
268 
269  Matrix<n,m,Scalar>
270  operator -(Scalar a) const
271  {
272  Matrix<n,m,Scalar> M;
273  for(Size i = 0; i < n; i++)
274  for(Size j = 0; j < m; j++)
275  M[i][j]=data[i][j]-a;
276  return M;
277  }
278 
279  // Multiplication by a scalar
280  Matrix<n,m,Scalar>
281  operator *(Scalar a) const
282  {
283  Matrix<n,m,Scalar> M;
284  for(Size i = 0; i < n; i++)
285  for(Size j = 0; j < m; j++)
286  M[i][j]=data[i][j]*a;
287  return M;
288  }
289  Matrix<n,m,Scalar>
290  operator /(Scalar a) const
291  {
292  Matrix<n,m,Scalar> M;
293  for(Size i = 0; i < n; i++)
294  for(Size j = 0; j < m; j++)
295  M[i][j]=data[i][j]/a;
296  return M;
297  }
298 
299 
300 
301  Matrix<m,n,Scalar>
302  transpose() const
303  {
304  Matrix<m,n,Scalar> M;
305  for(Size i = 0; i < n; i++)
306  for(Size j = 0; j < m; j++)
307  M[j][i]=data[i][j];
308  return M;
309  }
310 
311 
312  // Scalar
313  // get(Size i, Size j) const
314  // {
315  // return data[i][j];
316  // }
317 
318 
319  template<Size p, Size q>
320  Matrix<p,q,Scalar>
321  get(Size c, Size d) const
322  {
323  Matrix<p,q,Scalar> M;
324  for(Size i = 0; i < p; i++)
325  for(Size j = 0; j < q; j++)
326  M[i][j]=data[i+c][j+d];
327  return M;
328  }
329 
330  void
331  set(Size i, Size j, Scalar newVal)
332  {
333  data[i][j] = newVal;
334  }
335 
336 
337  template<Size p, Size q>
338  void
339  set(Size c, Size d, Matrix<p,q,Scalar> newVal)
340  {
341  for(Size i = 0; i < p; i++)
342  for(Size j = 0; j < q; j++)
343  data[i+c][j+d] = newVal[i][j];
344  }
345 
346 
347 
348  Matrix<1,m,Scalar>
349  row(Size i) const
350  {
351  return get<1, m>(i, 0);
352  }
353 
354 
355  Matrix<1,m,Scalar>
356  column(Size j) const
357  {
358  return get<n,1>(0, j);
359  }
360 
363  void
365  {
366  for(Size i = 0; i < n; i++)
367  for(Size j = 0; j < m; j++)
368  other[i][j]=data[i][j];
369  }
370 
371  // Implementation-specific functions
372  #ifdef ARDUINO
373  void
374  printTo(Print &serial) const
375  {
376  for(Size i = 0; i < n; i++)
377  {
378  for(Size j = 0; j < m; j++)
379  {
380  if(dtostrf_func){
381  char buf[7];
382  dtostrf_func(data[i][j], 6, 3, buf);
383  serial.print(buf);
384  }
385  else{
386  serial.print(data[i][j]);
387  }
388  serial.print("\t");
389  }
390  serial.println();
391  }
392  } // end printTo
393  #endif
394  #ifdef USING_STANDARD_LIBRARY
395  void
396  printTo(std::ostream &out) const
397  {
398  for(Size i = 0; i < n; i++)
399  {
400  for(Size j = 0; j < m; j++)
401  {
402  out << std::setw(6) << data[i][j];
403  out << "\t";
404  }
405  out << std::endl;
406  }
407  }
408  #endif
409 
410 
411  #ifndef TMM_DISABLE_RECURSIVE
412  template <typename T = Scalar>
413  tmm::enable_if_t<(m==n), T>
414  determinant() const
415  {
416  if(n == 0) { return 1; }
417  if(n == 1) { return Matrix<n,n,Scalar>::data[0][0]; }
418  if(n == 2) { return Matrix<n,n,Scalar>::data[0][0] * Matrix<n,n,Scalar>::data[1][1] - Matrix<n,n,Scalar>::data[0][1] * Matrix<n,n,Scalar>::data[1][0]; }
419  Scalar sign = 1;
420  Scalar ret = 0;
421  for(Size i = 0; i < n; i++){
422  // Get submatrix
423  Matrix<(n>0?n-1:n),(n>0?n-1:n),Scalar> submatrix;
424  // the (n>0?n-1:n) trickery means decrement by one,
425  // stopping at zero (in wich case this code is unreachable)
426  // It's a hack that can be replaced in newer C++ compilers
427 
428 
429  for(Size p = 0; p < n-1; p ++){ // for each row in submatrix
430  for(Size q = 0; q < i; q++){ // for each column in submatrix until hitting the i'th column
431  submatrix[p][q]=Matrix<n,n,Scalar>::data[p+1][q];
432  }
433  // skip the i'th column
434  for(Size q = i+1; q < n; q++){
435  submatrix[p][q]=Matrix<n,n,Scalar>::data[p+1][q-1];
436  }
437  }
438  // end of code snippet
439  ret = ret + sign * Matrix<n,n,Scalar>::data[0][i] * submatrix.determinant();
440  sign = -sign;
441  }
442  return ret;
443  } // end determinant
444 
445 
446 
447 
448 
449  template <typename T = Matrix<n,n,Scalar>>
450  tmm::enable_if_t<(m==n), T>
451  cofactor() const
452  {
453  Matrix<n,n,Scalar> M;
454  for(Size i = 0; i < n; i ++){
455  for(Size j = 0; j < n; j++){
456  // Take the determinant of the matrix
457  // formed by all elements that are not
458  // in the i'th row or the j'th column.
459  //
460  // Construct a temporary matrix with these
461  // values so we can take the determinant
462  // of it.
463  //
464  // TODO simplify this garbage
465  Matrix<n-1,n-1,Scalar> t;
466  for(Size p = 0; p < i; p ++){
467  for(Size q = 0; q < j; q++){
468  t[p][q]=Matrix<n,n,Scalar>::data[p][q];
469  }
470  for(Size q = j+1; q < n; q++){
471  t[p][q]=Matrix<n,n,Scalar>::data[p][q-1];
472  }
473  }
474  for(Size p = i+1; p < n; p ++){
475  for(Size q = 0; q < j; q++){
476  t[p-1][q]=Matrix<n,n,Scalar>::data[p-1][q];
477  }
478  for(Size q = j+1; q < n; q++){
479  t[p-1][q]=Matrix<n,n,Scalar>::data[p-1][q-1];
480  }
481  }
482  M[i][j] = t.determinant();
483 
484  // Without this line, M would be a matrix of minors
485  if (i+j%2==1) M[i][j] = -M[i][j];
486  }
487  }
488  return M;
489  }// end cofactor
490 
491 
492 
493 
499  template <typename T = Matrix<n,n,Scalar>>
500  tmm::enable_if_t<(m==n), T>
501  inverse() const
502  {
503  // The matrix is the adjugate divided by the determinant,
504  // where the adjugate is the cofactor transposed
505  Matrix<n,n,Scalar> adjugate = cofactor().transpose();
506 
507  return adjugate / determinant();
508  } // end inverse
509 
510 
511  #endif // ifndef DISABLE_RECURSIVE
512 
513 
514 
515  }; // end Matrix class
516 
517  template<Size n, typename Scalar = float>
518  Matrix<n,n,Scalar>
519  Identity(){
520  Matrix<n,n,Scalar> I;
521  for(Size i = 0; i < n; i++)
522  I[i][i]=1;
523  return I;
524  }
525 
526  template<Size n, Size m, typename Scalar = float>
527  Matrix<n,m,Scalar>
528  Zeros(){
529  Matrix<n,m,Scalar> M;
530  return M;
531  }
532 
533 
534 
535 }
536 
Definition: TMM_matrix.hpp:28
bool operator==(const Matrix< n, m, Other_Scalar > &other) const
Returns true if all elements of this matrix are identically equal to the elements of another matrix.
Definition: TMM_matrix.hpp:110
void copyTo(Matrix< n, m, Scalar > &other) const
Copies the contents of this matrix to another matrix.
Definition: TMM_matrix.hpp:364
tmm::enable_if_t<(m==n), T > inverse() const
Attempts to invert the matrix.
Definition: TMM_matrix.hpp:501
bool equals(const Matrix< n, m, Scalar > &other, Scalar tolerance) const
Returns true if all elements of this matrix are equal to the elements of another matrix,...
Definition: TMM_matrix.hpp:96