Linear Algebra  arduino
Accessible implementations of linear algebra algorithms
PermutationMatrix.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "Matrix.hpp"
4 
7 
12 
15 
16  public:
17  enum Type {
21  };
22 
23  public:
26 
28  PermutationMatrix() = default;
29 
32 
35  : storage(rows), type(type) {
36  fill_identity();
37  }
38 
40  PermutationMatrix(std::initializer_list<size_t> init,
43  PermutationMatrix &operator=(std::initializer_list<size_t> init);
44 
49 
54 
56 
57  public:
60 
62  size_t size() const { return storage.size(); }
64  size_t rows() const { return size(); }
66  size_t cols() const { return size(); }
68  size_t num_elems() const { return size(); }
70  void resize(size_t size) { storage.resize(size); }
71 
73 
74  public:
77 
81  size_t &operator()(size_t index) { return storage[index]; }
83  const size_t &operator()(size_t index) const { return storage[index]; }
84 
86 
87  public:
90 
92  void reverse() { reverse_ = !reverse_; }
93 
95  void transpose_inplace() { reverse(); }
96 
98  bool is_reversed() const { return reverse_; }
99 
102  Type get_type() const { return type; }
105  void set_type(Type type) { this->type = type; }
106 
108 
109  public:
112 
115 
119 
121  Permutation to_permutation() const;
122 
124 
125  public:
128 
130  void permute_columns(Matrix &A) const;
132  void permute_rows(Matrix &A) const;
133 
135 
136  public:
139 
142  storage_t().swap(this->storage); // replace storage with empty storage
143  // temporary storage goes out of scope and deallocates original storage
144  }
145 
147 
148  public:
151 
152 #ifndef NO_RANDOM_SUPPORT
154  static Permutation
155  random_permutation(size_t length,
156  std::default_random_engine::result_type seed =
157  std::default_random_engine::default_seed);
158 #endif
159 
161  static Permutation identity_permutation(size_t length);
162 
164 
165  public:
168 
170  void fill_identity() { std::iota(begin(), end(), size_t(0)); }
171 
179  void fill_from_permutation(Permutation permutation);
180 
181 #ifndef NO_RANDOM_SUPPORT
184  void fill_random(std::default_random_engine::result_type seed =
185  std::default_random_engine::default_seed) {
187  }
188 #endif
189 
191 
192  public:
195 
199  return p;
200  }
201 
204  Type type = Unspecified) {
205  PermutationMatrix p(permutation.size(), type);
206  p.fill_from_permutation(std::move(permutation));
207  return p;
208  }
209 
210 #ifndef NO_RANDOM_SUPPORT
213  static PermutationMatrix
215  std::default_random_engine::result_type seed =
216  std::default_random_engine::default_seed) {
218  p.fill_random(seed);
219  return p;
220  }
221 #endif
222 
224 
225  public:
228 
230  storage_t::iterator begin() { return storage.begin(); }
232  storage_t::const_iterator begin() const { return storage.begin(); }
234  storage_t::const_iterator cbegin() const { return storage.begin(); }
235 
237  storage_t::iterator end() { return storage.end(); }
239  storage_t::const_iterator end() const { return storage.end(); }
241  storage_t::const_iterator cend() const { return storage.end(); }
242 
244 
245  public:
248 
258  void print(std::ostream &os, uint8_t precision = 0,
259  uint8_t width = 0) const;
260 
262 
263  protected:
265  bool reverse_ = false;
267 };
268 
270 
273 std::ostream &operator<<(std::ostream &os, const PermutationMatrix &M);
274 
275 // :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: //
276 
279 
281 inline Matrix operator*(const PermutationMatrix &P, const Matrix &A) {
282  Matrix result = A;
283  P.permute_rows(result);
284  return result;
285 }
287 inline Matrix &&operator*(const PermutationMatrix &P, Matrix &&A) {
288  P.permute_rows(A);
289  return std::move(A);
290 }
292 inline Matrix operator*(const Matrix &A, const PermutationMatrix &P) {
293  Matrix result = A;
294  P.permute_columns(result);
295  return result;
296 }
298 inline Matrix &&operator*(Matrix &&A, const PermutationMatrix &P) {
299  P.permute_columns(A);
300  return std::move(A);
301 }
302 
305  const SquareMatrix &A) {
306  SquareMatrix result = A;
307  P.permute_rows(result);
308  return result;
309 }
312  P.permute_rows(A);
313  return std::move(A);
314 }
317  const PermutationMatrix &P) {
318  SquareMatrix result = A;
319  P.permute_columns(result);
320  return result;
321 }
324  P.permute_columns(A);
325  return std::move(A);
326 }
327 
329 inline Vector operator*(const PermutationMatrix &P, const Vector &v) {
330  Vector result = v;
331  P.permute_rows(result);
332  return result;
333 }
335 inline Vector &&operator*(const PermutationMatrix &P, Vector &&v) {
336  P.permute_rows(v);
337  return std::move(v);
338 }
339 
341 inline RowVector operator*(const RowVector &v, const PermutationMatrix &P) {
342  RowVector result = v;
343  P.permute_columns(result);
344  return result;
345 }
348  P.permute_columns(v);
349  return std::move(v);
350 }
351 
353 
356 
359  PermutationMatrix result = P;
360  result.transpose_inplace();
361  return result;
362 }
365  P.transpose_inplace();
366  return std::move(P);
367 }
368 
370 
371 // Implementations //
372 // -------------------------------------------------------------------------- //
373 
375  *this = std::move(other);
376 }
377 
378 inline PermutationMatrix &
380  // By explicitly defining move assignment, we can be sure that the object
381  // that's being moved from has a consistent state.
382  this->storage = std::move(other.storage);
383  std::swap(this->type, other.type);
384  std::swap(this->reverse_, other.reverse_);
385  other.clear_and_deallocate();
386  return *this;
387 }
388 
389 inline PermutationMatrix::PermutationMatrix(std::initializer_list<size_t> init,
390  Type type)
391  : type(type) {
392  *this = init;
393 }
394 
396  // TODO: I'm sure this can be sped up
397  Type actual_type = type == Unspecified ? this->type : type;
398  assert(actual_type != Unspecified);
399  if (actual_type == RowPermutation) {
401  permute_rows(P);
402  return P;
403  } else if (actual_type == ColumnPermutation) {
405  permute_columns(P);
406  return P;
407  }
408  assert(false);
409  return {};
410 }
411 
415  auto &This = *this;
416  if (is_reversed()) {
417  // Count down
418  for (size_t i = size(); i-- > 0;)
419  if (i != This(i))
420  std::swap(p[i], p[This(i)]);
421  } else {
422  // Count up
423  for (size_t i = 0; i < size(); ++i)
424  if (i != This(i))
425  std::swap(p[i], p[This(i)]);
426  }
427  return p;
428 }
429 
430 inline PermutationMatrix &
431 PermutationMatrix::operator=(std::initializer_list<size_t> init) {
432  storage_t permutation(init.size());
433  std::copy(init.begin(), init.end(), permutation.begin());
434  fill_from_permutation(std::move(permutation));
435 
436  return *this;
437 }
438 
440  assert(A.cols() == size());
441  assert(get_type() != RowPermutation);
442  auto &This = *this;
443  if (is_reversed()) {
444  // Count down
445  for (size_t i = size(); i-- > 0;)
446  if (i != This(i))
447  A.swap_columns(i, This(i));
448  } else {
449  // Count up
450  for (size_t i = 0; i < size(); ++i)
451  if (i != This(i))
452  A.swap_columns(i, This(i));
453  }
454 }
455 
457  assert(A.rows() == size());
458  assert(get_type() != ColumnPermutation);
459  auto &This = *this;
460  if (is_reversed()) {
461  // Count down
462  for (size_t i = size(); i-- > 0;)
463  if (i != This(i))
464  A.swap_rows(i, This(i));
465  } else {
466  // Count up
467  for (size_t i = 0; i < size(); ++i)
468  if (i != This(i))
469  A.swap_rows(i, This(i));
470  }
471 }
std::ostream & operator<<(std::ostream &os, const HouseholderQR &qr)
Print the Q and R matrices of a HouseholderQR object.
General matrix class.
Definition: Matrix.hpp:34
void swap_columns(size_t a, size_t b)
Swap two columns of the matrix.
Definition: Matrix.cpp:184
void swap_rows(size_t a, size_t b)
Swap two rows of the matrix.
Definition: Matrix.cpp:189
size_t rows() const
Get the number of rows of the matrix.
Definition: Matrix.hpp:81
size_t cols() const
Get the number of columns of the matrix.
Definition: Matrix.hpp:83
Class that represents matrices that permute the rows or columns of other matrices.
storage_t::const_iterator begin() const
Get the iterator to the first element of the swapping sequence.
PermutationMatrix & operator=(std::initializer_list< size_t > init)
Assign the given permutation to the matrix.
@ RowPermutation
Can be used for permuting rows only.
@ Unspecified
Can be used for permuting rows or columns.
@ ColumnPermutation
Can be used for permuting columns only.
size_t size() const
Get the size of the permutation matrix.
void fill_random(std::default_random_engine::result_type seed=std::default_random_engine::default_seed)
Fill the matrix with a random permutation.
static PermutationMatrix from_permutation(Permutation permutation, Type type=Unspecified)
Create a permutation matrix from the given permutation.
void reverse()
Reverse the order of the permutations.
Permutation to_permutation() const
Convert a permutation matrix into a mathematical permutation.
storage_t::iterator end()
Get the iterator to the element past the end of the swapping sequence.
PermutationMatrix & operator=(const PermutationMatrix &)=default
Default copy assignment.
PermutationMatrix(const PermutationMatrix &)=default
Default copy constructor.
PermutationMatrix()=default
Default constructor.
void permute_columns(Matrix &A) const
Apply the permutation to the columns of matrix A.
void resize(size_t size)
Resize the permutation matrix.
void transpose_inplace()
Transpose or invert the permutation matrix.
bool is_reversed() const
Check if the permutation should be applied in reverse.
storage_t::const_iterator cend() const
Get the iterator to the element past the end of the swapping sequence.
const size_t & operator()(size_t index) const
Get the element at the given position in the swap sequence.
PermutationMatrix(Type type)
Create an empty permutation matrix with the given type.
static PermutationMatrix random(size_t rows, Type type=Unspecified, std::default_random_engine::result_type seed=std::default_random_engine::default_seed)
Create a random permutation matrix.
size_t num_elems() const
Get the number of elements in the matrix:
void fill_from_permutation(Permutation permutation)
Create a permutation matrix from the given permutation.
void set_type(Type type)
Set the type of permutation matrix (whether it permutes rows or columns, or unspecified).
Type get_type() const
Get the type of permutation matrix (whether it permutes rows or columns, or unspecified).
storage_t Permutation
Type that represents a permutation (in the mathematical sense, a permutation of the integers 0 throug...
size_t & operator()(size_t index)
Get the element at the given position in the swap sequence.
size_t rows() const
Get the number of rows of the permutation matrix.
PermutationMatrix(size_t rows, Type type=Unspecified)
Create a permutation matrix without permutations.
storage_t::const_iterator cbegin() const
Get the iterator to the first element of the swapping sequence.
static PermutationMatrix identity(size_t rows, Type type=Unspecified)
Create an identity permutation matrix.
void clear_and_deallocate()
Set the size to zero, and deallocate the storage.
util::storage_t< size_t > storage_t
Container to store the elements of the permutation matrix internally.
void fill_identity()
Fill the matrix as an identity permutation.
SquareMatrix to_matrix(Type type=Unspecified) const
Convert a permutation matrix into a full matrix.
size_t cols() const
Get the number of columns of the permutation matrix.
storage_t::iterator begin()
Get the iterator to the first element of the swapping sequence.
static Permutation identity_permutation(size_t length)
Return the identity permutation (0, 1, 2, 3, ..., length-1).
storage_t::const_iterator end() const
Get the iterator to the element past the end of the swapping sequence.
void permute_rows(Matrix &A) const
Apply the permutation to the rows of matrix A.
void print(std::ostream &os, uint8_t precision=0, uint8_t width=0) const
Print a permutation matrix.
static Permutation random_permutation(size_t length, std::default_random_engine::result_type seed=std::default_random_engine::default_seed)
Return a random permutation of the integers 0 through length-1.
A row vector (1×n matrix).
Definition: Matrix.hpp:437
Square matrix class.
Definition: Matrix.hpp:572
static SquareMatrix identity(size_t rows)
Create a square identity matrix.
Definition: Matrix.cpp:596
A column vector (n×1 matrix).
Definition: Matrix.hpp:278
Matrix operator*(const PermutationMatrix &P, const Matrix &A)
Left application of permutation matrix (P permutes rows of A).
PermutationMatrix transpose(const PermutationMatrix &P)
Transpose a permutation matrix (inverse permutation).
std::vector< T > storage_t
Container to store the elements of a matrix internally.