emlabcpp
modern opinionated embedded C++ library
matrix.h
Go to the documentation of this file.
1 
24 #pragma once
25 
26 #include "../algorithm.h"
27 #include "../range.h"
28 
29 namespace emlabcpp
30 {
31 
32 template < std::size_t N, std::size_t M, typename T = float >
33 class matrix
34 {
35 public:
36  using value_type = T;
37  static constexpr std::size_t rows = N;
38  static constexpr std::size_t cols = M;
39  using row_type = std::array< value_type, M >;
40 
41  constexpr matrix()
42  {
43  for ( row_type& row : data_ )
44  for ( value_type& val : row )
45  val = 0.f;
46  };
47 
48  constexpr matrix( std::array< row_type, N > data )
49  : data_( data )
50  {
51  }
52 
53  [[nodiscard]] constexpr auto begin() const
54  {
55  return data_.begin();
56  }
57 
58  [[nodiscard]] constexpr auto end() const
59  {
60  return data_.end();
61  }
62 
63  constexpr row_type const& operator[]( std::size_t i ) const
64  {
65  return data_[i];
66  }
67 
68  constexpr row_type& operator[]( std::size_t i )
69  {
70  return data_[i];
71  }
72 
73  constexpr bool operator==( matrix const& other ) const = default;
74 
75 private:
76  std::array< row_type, N > data_;
77 };
78 
79 template < typename Matrix >
81 {
82  template < typename Matrix2 >
83  class stub
84  {
85  public:
86  stub( std::size_t i, Matrix2& m )
87  : i_( i )
88  , m_( m )
89  {
90  }
91 
92  constexpr auto const& operator[]( std::size_t j ) const
93  {
94  return m_[j][i_];
95  }
96 
97  constexpr auto& operator[]( std::size_t j )
98  {
99  return m_[j][i_];
100  }
101 
102  private:
103  std::size_t i_;
104  Matrix2& m_;
105  };
106 
107 public:
108  using value_type = typename Matrix::value_type;
109  static constexpr std::size_t rows = Matrix::cols;
110  static constexpr std::size_t cols = Matrix::rows;
111 
112  constexpr transposed_matrix( Matrix& m )
113  : m_( m )
114  {
115  }
116 
117  constexpr stub< Matrix const > operator[]( std::size_t i ) const
118  {
119  return { i, m_ };
120  }
121 
122  constexpr stub< Matrix > operator[]( std::size_t i )
123  {
124  return { i, m_ };
125  }
126 
128  {
130  for ( std::size_t const i : range( rows ) )
131  for ( std::size_t const j : range( cols ) )
132  res[i][j] = m_[j][i];
133  return res;
134  }
135 
136  constexpr bool operator==( transposed_matrix const& other ) const = default;
137 
138 private:
139  Matrix& m_;
140 };
141 
142 template < std::size_t N, typename T = float >
144 {
145  class stub
146  {
147  public:
148  stub( std::size_t i )
149  : i_( i )
150  {
151  }
152 
153  constexpr T operator[]( std::size_t j ) const
154  {
155  return i_ == j ? 1 : 0;
156  }
157 
158  private:
159  std::size_t i_;
160  };
161 
162 public:
163  using value_type = T;
164  static constexpr std::size_t rows = N;
165  static constexpr std::size_t cols = N;
166 
167  constexpr identity_matrix() = default;
168 
169  constexpr stub operator[]( std::size_t i ) const
170  {
171  return { i };
172  }
173 
175  {
177  for ( std::size_t const i : range( rows ) )
178  for ( std::size_t const j : range( cols ) )
179  res[i][j] = i == j ? 1 : 0;
180  return res;
181  }
182 };
183 
184 template < typename M >
185 concept matrix_like = requires( M m, std::size_t i, std::size_t j ) {
186  { M::rows } -> std::convertible_to< std::size_t >;
187  { M::cols } -> std::convertible_to< std::size_t >;
188  { m[i][j] } -> std::convertible_to< typename M::value_type >;
189 };
190 
191 template < matrix_like Matrix, std::size_t I, std::size_t J >
193 {
194  template < typename Matrix2 >
195  class stub
196  {
197  public:
198  stub( std::size_t i, Matrix2& m )
199  : i_( i )
200  , m_( m )
201  {
202  }
203 
204  constexpr auto const& operator[]( std::size_t j ) const
205  {
206  return m_[i_][j < J ? j : j + 1];
207  }
208 
209  constexpr auto& operator[]( std::size_t j )
210  {
211  return m_[i_][j < J ? j : j + 1];
212  }
213 
214  private:
215  std::size_t i_;
216  Matrix2& m_;
217  };
218 
219 public:
220  using value_type = typename Matrix::value_type;
221  static constexpr std::size_t rows = Matrix::rows - 1;
222  static constexpr std::size_t cols = Matrix::cols - 1;
223 
224  constexpr rowcol_submatrix( Matrix& m )
225  : m_( m )
226  {
227  }
228 
229  constexpr stub< Matrix const > operator[]( std::size_t i ) const
230  {
231  return { i < I ? i : i + 1, m_ };
232  }
233 
234  constexpr stub< Matrix > operator[]( std::size_t i )
235  {
236  return { i < I ? i : i + 1, m_ };
237  }
238 
239 private:
240  Matrix& m_;
241 };
242 
243 #ifdef EMLABCPP_USE_OSTREAM
244 template < matrix_like Matrix >
245 std::ostream& operator<<( std::ostream& os, Matrix const& m )
246 {
247  for ( std::size_t const i : range( Matrix::rows ) ) {
248  for ( std::size_t const j : range( Matrix::cols ) )
249  os << m[i][j] << '\t';
250  os << '\n';
251  }
252  return os;
253 }
254 #endif
255 
256 template < matrix_like LH, matrix_like RH >
257 requires( LH::rows == RH::rows && LH::cols == RH::cols )
258 constexpr auto operator==( const LH& lh, const RH& rh )
259 {
260  for ( std::size_t const i : range( LH::rows ) ) {
261  for ( std::size_t const j : range( LH::cols ) )
262  if ( lh[i][j] != rh[i][j] )
263  return false;
264  }
265  return true;
266 }
267 
268 template < matrix_like LH, matrix_like RH, typename T = typename LH::value_type >
269 requires( LH::cols == RH::rows )
270 constexpr matrix< LH::rows, RH::cols, T > operator*( const LH& lh, const RH& rh )
271 {
272  matrix< LH::rows, RH::cols, T > res;
273 
274  for ( std::size_t const i : range( LH::rows ) ) {
275  for ( std::size_t const j : range( RH::cols ) ) {
276  T v{};
277  for ( std::size_t const k : range( LH::cols ) )
278  v += lh[i][k] * rh[k][j];
279  res[i][j] = v;
280  }
281  }
282 
283  return res;
284 }
285 
286 template < matrix_like LH >
287 constexpr matrix< LH::rows, LH::cols, typename LH::value_type >
288 operator*( const LH& lh, typename LH::value_type const& val )
289 {
290  auto res = lh;
291  for ( std::size_t const i : range( LH::rows ) )
292  for ( std::size_t const j : range( LH::cols ) )
293  res[i][j] *= val;
294 
295  return res;
296 }
297 
298 template < matrix_like LH >
299 constexpr matrix< LH::rows, LH::cols, typename LH::value_type >
300 operator*( typename LH::value_type const& val, const LH& lh )
301 {
302  return lh * val;
303 }
304 
305 template < matrix_like LH, matrix_like RH, typename T = typename LH::value_type >
306 requires( LH::cols == RH::cols && LH::rows == RH::rows )
307 constexpr matrix< LH::rows, LH::cols, T > operator+( const LH& lh, const RH& rh )
308 {
309  matrix< LH::rows, LH::cols, T > res{};
310  for ( std::size_t const i : range( LH::rows ) )
311  for ( std::size_t const j : range( LH::cols ) )
312  res[i][j] = lh[i][j] + rh[i][j];
313  return res;
314 }
315 
316 template < matrix_like LH, matrix_like RH, typename T = typename LH::value_type >
317 requires( LH::cols == RH::cols && LH::rows == RH::rows )
318 constexpr matrix< LH::rows, LH::cols, T > operator-( const LH& lh, const RH& rh )
319 {
320  matrix< LH::rows, LH::cols, T > res{};
321  for ( std::size_t const i : range( LH::rows ) )
322  for ( std::size_t const j : range( LH::cols ) )
323  res[i][j] = lh[i][j] - rh[i][j];
324  return res;
325 }
326 
327 template < matrix_like M >
328 constexpr transposed_matrix< M > transpose( M& m )
329 {
330  return { m };
331 }
332 
333 template < matrix_like M >
334 constexpr matrix< M::cols, M::rows, typename M::value_type > transpose( M&& m )
335 {
336  return transpose( m );
337 };
338 
339 template < matrix_like M >
340 requires( M::rows == 2 && M::cols == 2 )
341 constexpr auto determinant( M const& m )
342 {
343  return m[0][0] * m[1][1] - m[0][1] * m[1][0];
344 }
345 
346 template < matrix_like M >
347 requires( M::rows > 2 && M::cols == M::rows )
348 constexpr auto determinant( M const& m )
349 {
350  // TODO: tests!
351  constexpr std::size_t N = M::rows;
352  float res = 0.f;
353  for_each_index< N >( [&]< std::size_t i > {
354  rowcol_submatrix< M const, i, 0 > const submatrix{ m };
355  res += ( i % 2 == 0 ? 1 : -1 ) * m[i][0] * determinant( submatrix );
356  } );
357  return res;
358 }
359 
360 template < matrix_like M >
361 requires( M::rows == 1 && M::cols == 1 )
362 constexpr matrix< M::rows, M::cols, typename M::value_type > inverse( M const& m )
363 {
365  res[0][0] = 1.f / m[0][0];
366  return res;
367 }
368 
369 template < matrix_like M >
370 requires( M::rows == 2 && M::cols == 2 )
371 constexpr matrix< M::rows, M::cols, typename M::value_type > inverse( M const& m )
372 {
373  auto v = 1.f / determinant( m );
374 
375  matrix< M::rows, M::cols, typename M::value_type > res;
376  res[0] = { m[1][1], -m[0][1] };
377  res[1] = { -m[1][0], m[0][0] };
378  return v * res;
379 }
380 
381 } // namespace emlabcpp
Definition: matrix.h:144
static constexpr std::size_t cols
Definition: matrix.h:165
T value_type
Definition: matrix.h:163
constexpr identity_matrix()=default
constexpr stub operator[](std::size_t i) const
Definition: matrix.h:169
static constexpr std::size_t rows
Definition: matrix.h:164
Definition: matrix.h:34
constexpr matrix(std::array< row_type, N > data)
Definition: matrix.h:48
constexpr row_type & operator[](std::size_t i)
Definition: matrix.h:68
std::array< value_type, M > row_type
Definition: matrix.h:39
static constexpr std::size_t rows
Definition: matrix.h:37
constexpr auto end() const
Definition: matrix.h:58
static constexpr std::size_t cols
Definition: matrix.h:38
constexpr matrix()
Definition: matrix.h:41
T value_type
Definition: matrix.h:36
constexpr bool operator==(matrix const &other) const =default
constexpr auto begin() const
Definition: matrix.h:53
constexpr row_type const & operator[](std::size_t i) const
Definition: matrix.h:63
Definition: matrix.h:193
static constexpr std::size_t cols
Definition: matrix.h:222
static constexpr std::size_t rows
Definition: matrix.h:221
typename Matrix::value_type value_type
Definition: matrix.h:220
constexpr stub< Matrix > operator[](std::size_t i)
Definition: matrix.h:234
constexpr stub< Matrix const > operator[](std::size_t i) const
Definition: matrix.h:229
constexpr rowcol_submatrix(Matrix &m)
Definition: matrix.h:224
Definition: matrix.h:81
typename Matrix::value_type value_type
Definition: matrix.h:108
static constexpr std::size_t rows
Definition: matrix.h:109
static constexpr std::size_t cols
Definition: matrix.h:110
constexpr bool operator==(transposed_matrix const &other) const =default
constexpr stub< Matrix const > operator[](std::size_t i) const
Definition: matrix.h:117
constexpr transposed_matrix(Matrix &m)
Definition: matrix.h:112
constexpr stub< Matrix > operator[](std::size_t i)
Definition: matrix.h:122
std::variant< int64_t, float, bool, string_buffer > value_type
Definition: base.h:51
MIT License.
Definition: impl.h:31
constexpr pointer data() noexcept
Returns pointer to first item of the storage.
Definition: static_storage.h:108
constexpr point< N > operator+(point< N > a, vector< N > const &b)
Returns a result of addition a to b, viz += operator.
Definition: point.h:93
constexpr point< N > operator*(point< N > a, point< N > const &b)
Multiplication of points multiplies each coordinate of A by coordinate of B on same dimension.
Definition: point.h:74
T value_type
Definition: static_storage.h:100
concept matrix_like
Definition: matrix.h:185
T res
Definition: algorithm.h:505
constexpr pose inverse(pose const &x)
Definition: pose.h:164
requires(!range_container< Container >) const expr std
Returns index of an element in tuple 't', for which call to predicate f(x) holds true,...
Definition: algorithm.h:127
constexpr vector< N > operator-(point< N > a, point< N > const &b)
Returns a result of subtraction of A from B, viz -= operator.
Definition: point.h:84
constexpr view< iterators::numeric_iterator< Numeric > > range(Numeric from, Numeric to)
Builds numeric view over interval [from, to)
Definition: range.h:34
std::ostream & operator<<(std::ostream &os, string_buffer< N > const &sb)
Definition: string_buffer.h:112
N
Definition: static_storage.h:97
constexpr bool operator==(pose const &x, pose const &y)
compares poses on their position and orientation
Definition: pose.h:93