i6engine  1.0
i6eMatrix.h
Go to the documentation of this file.
1 /*
2  * i6engine
3  * Copyright (2016) Daniel Bonrath, Michael Baer, All rights reserved.
4  *
5  * This file is part of i6engine; i6engine is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
25 #ifndef __I6ENGINE_MATH_I6EMATRIX_H__
26 #define __I6ENGINE_MATH_I6EMATRIX_H__
27 
28 #include <vector>
29 
31 
33 
34 namespace boost {
35 namespace serialization {
36  class access;
37 } /* serialization */
38 } /* boost */
39 
40 namespace i6e {
41 namespace math {
42 
47  template<typename T>
48  class i6eMatrix {
49  public:
53  i6eMatrix() : _width(0), _height(0), _data() {
54  }
55 
59  i6eMatrix(uint32_t m, uint32_t n) : _width(n), _height(m), _data(m, std::vector<T>(n, T())) {
60  }
61 
65  i6eMatrix(const i6eMatrix & other) : _width(other.getWidth()), _height(other.getHeight()), _data(other._data) {
66  }
67 
71  explicit i6eMatrix(const i6eVector & vector) : _width(1), _height(3), _data(3, std::vector<T>(1, 0.0)) {
72  _data[0][0] = vector.getX();
73  _data[1][0] = vector.getY();
74  _data[2][0] = vector.getZ();
75  }
76 
80  i6eMatrix operator*(const T & value) {
81  i6eMatrix result(*this);
82 
83  result *= value;
84 
85  return result;
86  }
87 
91  i6eMatrix & operator*=(const T & value) {
92  i6eMatrix result(*this);
93 
94  for (unsigned int i = 0; i < _height; ++i) {
95  for (unsigned int j = 0; j < _width; ++j) {
96  _data[i][j] *= value;
97  }
98  }
99 
100  return *this;
101  }
102 
106  i6eMatrix operator/(const T & value) {
107  i6eMatrix result(*this);
108 
109  result /= value;
110 
111  return result;
112  }
113 
117  i6eMatrix & operator/=(const T & value) {
118  i6eMatrix result(*this);
119 
120  for (uint32_t i = 0; i < _height; ++i) {
121  for (uint32_t j = 0; j < _width; ++j) {
122  _data[i][j] /= value;
123  }
124  }
125 
126  return *this;
127  }
128 
132  i6eMatrix operator*(const i6eMatrix & other) {
133  i6eMatrix result(*this);
134 
135  result *= other;
136 
137  return result;
138  }
139 
143  i6eMatrix operator*=(const i6eMatrix & other) {
144  if (_width != other.getHeight()) {
145  ISIXE_THROW_API("i6eMatrix", "wrong dimension for matrix-matrix-multiplication");
146  }
147 
148  i6eMatrix result(_height, other.getWidth());
149 
150  for (uint32_t i = 0; i < _height; ++i) {
151  for (uint32_t j = 0; j < other.getWidth(); ++j) {
152  for (uint32_t k = 0; k < _width; ++k) {
153  result(i, j, result(i, j) + _data[i][k] * other(k, j));
154  }
155  }
156  }
157 
158  *this = result;
159 
160  return *this;
161  }
162 
166  i6eMatrix operator+(const i6eMatrix & other) {
167  i6eMatrix result(*this);
168 
169  result += other;
170 
171  return result;
172  }
173 
177  i6eMatrix & operator+=(const i6eMatrix & other) {
178  if (_height != other.getHeight() || _width != other.getWidth()) {
179  ISIXE_THROW_API("i6eMatrix", "wrong dimension for matrix-matrix-addition");
180  }
181 
182  for (uint32_t i = 0; i < _height; ++i) {
183  for (uint32_t j = 0; j < _width; ++j) {
184  _data[i][j] += other(i, j);
185  }
186  }
187 
188  return *this;
189  }
190 
194  i6eMatrix operator-(const i6eMatrix & other) {
195  i6eMatrix result(*this);
196 
197  result -= other;
198 
199  return result;
200  }
201 
205  i6eMatrix & operator-=(const i6eMatrix & other) {
206  if (_height != other.getHeight() || _width != other.getWidth()) {
207  ISIXE_THROW_API("i6eMatrix", "wrong dimension for matrix-matrix-subtraction");
208  }
209 
210  for (uint32_t i = 0; i < _height; ++i) {
211  for (uint32_t j = 0; j < _width; ++j) {
212  _data[i][j] -= other(i, j);
213  }
214  }
215 
216  return *this;
217  }
218 
223  i6eMatrix result(*this);
224 
225  for (uint32_t i = 0; i < _height; ++i) {
226  for (uint32_t j = 0; j < _width; ++j) {
227  result(i, j, -_data[i][j]);
228  }
229  }
230 
231  return result;
232  }
233 
237  void operator()(uint32_t m, uint32_t n, const T & value) {
238  setEntry(m, n, value);
239  }
240 
244  T operator()(uint32_t m, uint32_t n) const {
245  return getEntry(m, n);
246  }
247 
251  bool operator==(const i6eMatrix & other) {
252  if (_width != other.getWidth() || _height != other.getHeight()) {
253  return false;
254  }
255 
256  for (uint32_t i = 0; i < _height; ++i) {
257  for (uint32_t j = 0; j < _width; ++j) {
258  if (std::fabs(_data[i][j] - other._data[i][j]) > 0.0000001f) {
259  return false;
260  }
261  }
262  }
263 
264  return true;
265  }
266 
270  bool operator!=(const i6eMatrix & other) const {
271  return !(*this == other);
272  }
273 
277  void setEntry(uint32_t m, uint32_t n, T value) {
278  if (m >= _height || n >= _width) {
279  ISIXE_THROW_API("i6eMatrix", "field (" << m << ", " << n << ") not part of the matrix");
280  }
281 
282  _data[m][n] = value;
283  }
284 
288  void setZero() {
289  for (uint32_t i = 0; i < _height; ++i) {
290  for (uint32_t j = 0; j < _width; ++j) {
291  _data[i][j] = T();
292  }
293  }
294  }
295 
299  void setIdentity() {
300  for (uint32_t i = 0; i < _height; ++i) {
301  for (uint32_t j = 0; j < _width; ++j) {
302  if (i == j) {
303  _data[i][j] = 1;
304  } else {
305  _data[i][j] = 0;
306  }
307  }
308  }
309  }
310 
314  inline uint32_t getWidth() const {
315  return _width;
316  }
317 
321  inline uint32_t getHeight() const {
322  return _height;
323  }
324 
328  inline T getEntry(uint32_t m, uint32_t n) const {
329  if (m >= _height || n >= _width) {
330  ISIXE_THROW_API("i6eMatrix", "field (" << m << ", " << n << ") not part of the matrix");
331  }
332 
333  return _data[m][n];
334  }
335 
339  double calculateDeterminant() const {
340  double det = 1.0;
341 
342  if (_height != _width) {
343  ISIXE_THROW_API("i6eMatrix", "only nxn matrices have a determinant");
344  }
345 
346  if (getHeight() == 2) {
347  return _data[0][0] * _data[1][1] - _data[1][0] * _data[0][1];
348  }
349 
350  i6eMatrix l(getHeight(), getWidth());
351  i6eMatrix u(getHeight(), getWidth());
352 
353  decomposeLU(l, u);
354 
355  for (uint32_t i = 0; i < getHeight(); ++i) {
356  det *= u(i, i);
357  }
358 
359  return det;
360  }
361 
365  static i6eMatrix pow(const i6eMatrix & other, uint32_t amount) {
366  i6eMatrix result(other);
367 
368  for (uint32_t i = 1; i < amount; ++i) {
369  result *= other;
370  }
371 
372  return result;
373  }
374 
378  static i6eMatrix transpose(const i6eMatrix & other) {
379  i6eMatrix result(other.getWidth(), other.getHeight());
380 
381  for (uint32_t i = 0; i < other.getHeight(); ++i) {
382  for (uint32_t j = 0; j < other.getWidth(); ++j) {
383  result(j, i, other(i, j));
384  }
385  }
386 
387  return result;
388  }
389 
393  static i6eMatrix invert(const i6eMatrix & other) {
394  if (other.getHeight() != other.getWidth()) {
395  ISIXE_THROW_API("i6eMatrix", "only nxn matrices have an inverse");
396  }
397 
398  T det = T(other.calculateDeterminant());
399 
400  assert(std::fabs(det) > 1e-15);
401 
402  return adjoint(other) * (1.0f / det);
403  }
404 
408  static i6eMatrix adjoint(const i6eMatrix & other) {
409  if (other.getHeight() != other.getWidth()) {
410  ISIXE_THROW_API("i6eMatrix", "only nxn matrices have an adjoint");
411  }
412 
413  i6eMatrix result(other.getHeight(), other.getWidth());
414 
415  for (uint32_t i = 0; i < other.getHeight(); ++i) {
416  for (uint32_t j = 0; j < other.getWidth(); ++j) {
417  i6eMatrix m(other.getHeight() - 1, other.getWidth() - 1);
418 
419  uint32_t rowC = 0;
420  uint32_t columnC = 0;
421 
422  for (uint32_t x = 0; x < other.getHeight(); ++x) {
423  if (x == i) {
424  continue;
425  }
426  for (uint32_t y = 0; y < other.getWidth(); ++y) {
427  if (y == j) {
428  continue;
429  }
430 
431  m(rowC, columnC, other(x, y));
432 
433  columnC++;
434  }
435  rowC++;
436  columnC = 0;
437  }
438 
439  T k = T(std::pow(-1.0f, i + j) * m.calculateDeterminant());
440  result(i, j, k);
441  }
442  }
443 
444  return transpose(result);
445  }
446 
450  void solveSystem(const i6eMatrix & b, i6eMatrix & x) {
451  if (getHeight() != getWidth()) {
452  ISIXE_THROW_API("i6eMatrix", "only nxn matrices can be solved using LU decomposition");
453  }
454 
455  i6eMatrix l(*this);
456  i6eMatrix u(*this);
457 
458  decomposeLU(l, u);
459 
460  i6eMatrix y(getHeight(), 1);
461 
462  forwardSubstitution(l, b, y);
463  backwardSubstitution(u, y, x);
464  }
465 
466  private:
468 
469  uint32_t _width;
470  uint32_t _height;
471  std::vector<std::vector<T>> _data;
472 
476  void decomposeLU(i6eMatrix & l, i6eMatrix & u) const {
477  assert(getWidth() == getHeight());
478 
479  l.setZero();
480  u = *this;
481 
482  for (uint32_t i = 0; i < l.getWidth(); ++i) {
483  l(i, i, 1.0f);
484  }
485 
486  for (uint32_t i = 0; i < getHeight(); ++i) {
487  for (uint32_t j = i + 1; j < getHeight(); ++j) {
488  l(j, i, u(j, i) / u(i, i));
489 
490  for (uint32_t k = i; k < getWidth(); ++k) {
491  u(j, k, u(j, k) - l(j, i) * u(i, k));
492  }
493  }
494  }
495  }
496 
500  void forwardSubstitution(const i6eMatrix & l, const i6eMatrix & b, i6eMatrix & y) {
501  assert(l.getWidth() == l.getHeight());
502  assert(l.getHeight() == b.getHeight() && b.getWidth() == 1);
503 
504  y = i6eMatrix(l.getHeight(), 1);
505 
506  for (uint32_t i = 0; i < l.getWidth(); ++i) {
507  T tmp = b(i, 0);
508 
509  for (uint32_t j = 0; j < i; ++j) {
510  tmp -= y(j, 0) * l(i, j);
511  }
512 
513  y(i, 0, tmp);
514  }
515  }
516 
520  void backwardSubstitution(const i6eMatrix & u, const i6eMatrix & y, i6eMatrix & x) {
521  assert(u.getWidth() == u.getHeight());
522  assert(y.getHeight() == u.getHeight() && y.getWidth() == 1);
523 
524  x = i6eMatrix(u.getHeight(), 1);
525 
526  for (uint32_t i = u.getHeight(); i > 0; --i) {
527  T tmp = y(i - 1, 0);
528 
529  for (uint32_t j = u.getHeight() - 1; j > i - 1; --j) {
530  tmp -= x(j, 0) * u(i - 1, j);
531  }
532 
533  x(i - 1, 0, tmp / u(i - 1, i - 1));
534 
535  if (i == 0) {
536  break;
537  }
538  }
539  }
540 
544  template<class Archive>
545  void serialize(Archive & ar, const unsigned int version) {
546  ar & _width;
547  ar & _height;
548  ar & _data;
549  }
550  };
551 
552  template<>
554  i6eMatrix result(*this);
555 
556  result *= 1.0f / value;
557 
558  return result;
559  }
560 
561  template<>
563  *this *= 1.0f / value;
564 
565  return *this;
566  }
567 
568 } /* namespace math */
569 } /* namespace i6e */
570 
571 #endif /* __I6ENGINE_MATH_I6EMATRIX_H__ */
572 
void setZero()
sets all values of the matrix to zero
Definition: i6eMatrix.h:288
i6eMatrix(const i6eMatrix &other)
copy constructor
Definition: i6eMatrix.h:65
i6eMatrix operator-(const i6eMatrix &other)
operator for substraction of matrix
Definition: i6eMatrix.h:194
i6eMatrix operator+(const i6eMatrix &other)
operator for addition with matrix
Definition: i6eMatrix.h:166
void setIdentity()
sets matrix to be an identity matrix
Definition: i6eMatrix.h:299
i6eMatrix & operator-=(const i6eMatrix &other)
operator for substraction of matrix
Definition: i6eMatrix.h:205
bool operator==(const i6eMatrix &other)
returns true, if both matrixes are equal
Definition: i6eMatrix.h:251
uint32_t getHeight() const
returns height of the matrix
Definition: i6eMatrix.h:321
static i6eMatrix transpose(const i6eMatrix &other)
calculates the transposed matrix
Definition: i6eMatrix.h:378
double getY() const
Definition: i6eVector.h:107
i6eMatrix operator*=(const i6eMatrix &other)
multiplication with matrix
Definition: i6eMatrix.h:143
#define ISIXE_THROW_API(module, message)
Definition: Exceptions.h:45
i6eMatrix operator-()
flips values of the matrix
Definition: i6eMatrix.h:222
i6eMatrix & operator/=(const T &value)
division of matrix with a scalar
Definition: i6eMatrix.h:117
Implements 3-dimensional vectors.
Definition: i6eVector.h:48
i6eMatrix(const i6eVector &vector)
constructor taking an i6eVector
Definition: i6eMatrix.h:71
static i6eMatrix pow(const i6eMatrix &other, uint32_t amount)
calculates a given amount of multiplications for the given matrix
Definition: i6eMatrix.h:365
void setEntry(uint32_t m, uint32_t n, T value)
sets the given value to the given position
Definition: i6eMatrix.h:277
double calculateDeterminant() const
returns determinant of the matrix
Definition: i6eMatrix.h:339
T getEntry(uint32_t m, uint32_t n) const
returns entry at given position
Definition: i6eMatrix.h:328
i6eMatrix & operator+=(const i6eMatrix &other)
operator for addition with matrix
Definition: i6eMatrix.h:177
uint32_t getWidth() const
returns width of the matrix
Definition: i6eMatrix.h:314
i6eMatrix()
default constructor, creates an emtpy matrix
Definition: i6eMatrix.h:53
bool operator!=(const i6eMatrix &other) const
return true, if both matrixes aren't equal
Definition: i6eMatrix.h:270
void operator()(uint32_t m, uint32_t n, const T &value)
sets the given value to the given position
Definition: i6eMatrix.h:237
static i6eMatrix adjoint(const i6eMatrix &other)
calculates the adjoint of the given matrix
Definition: i6eMatrix.h:408
void solveSystem(const i6eMatrix &b, i6eMatrix &x)
solves the linear system mx = b using LU-decomposition, where m is the input square matrix and x is t...
Definition: i6eMatrix.h:450
Implements m x n matrix.
Definition: i6eMatrix.h:48
i6eMatrix operator*(const T &value)
multiplication of matrix with a scalar
Definition: i6eMatrix.h:80
double getX() const
getters for the values of the Vector
Definition: i6eVector.h:104
i6eMatrix operator*(const i6eMatrix &other)
multiplication with matrix
Definition: i6eMatrix.h:132
friend class boost::serialization::access
Definition: i6eMatrix.h:467
double getZ() const
Definition: i6eVector.h:110
i6eMatrix(uint32_t m, uint32_t n)
constructor taking dimension of the matrix setting all values to zero
Definition: i6eMatrix.h:59
static i6eMatrix invert(const i6eMatrix &other)
calculates the inverted of the given matrix
Definition: i6eMatrix.h:393
i6eMatrix operator/(const T &value)
division of matrix with scalar
Definition: i6eMatrix.h:106
i6eMatrix & operator*=(const T &value)
multiplication of matrix with a scalar
Definition: i6eMatrix.h:91
T operator()(uint32_t m, uint32_t n) const
returs the value at the given position
Definition: i6eMatrix.h:244