From ce829f7356a69d4110e81c2e762bc27d876917a9 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 12 Jul 2025 01:28:40 +0300 Subject: [PATCH] Add permutation groups & implement converting cyclic & dihedral groups into permutations --- libs/group/include/psemek/group/cyclic.hpp | 9 + libs/group/include/psemek/group/dihedral.hpp | 20 +++ .../include/psemek/group/permutation.hpp | 154 ++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 libs/group/include/psemek/group/permutation.hpp diff --git a/libs/group/include/psemek/group/cyclic.hpp b/libs/group/include/psemek/group/cyclic.hpp index aad2a145..132c66e2 100644 --- a/libs/group/include/psemek/group/cyclic.hpp +++ b/libs/group/include/psemek/group/cyclic.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -55,6 +56,14 @@ namespace psemek::group return repr_; } + group::permutation permutation() const + { + typename group::permutation::repr_type repr; + for (Repr i = 0; i < N; ++i) + repr[i] = (i + repr_) % N; + return group::permutation::from_repr(repr); + } + struct value_iterator { using difference_type = Repr; diff --git a/libs/group/include/psemek/group/dihedral.hpp b/libs/group/include/psemek/group/dihedral.hpp index a1a5e364..cc199a35 100644 --- a/libs/group/include/psemek/group/dihedral.hpp +++ b/libs/group/include/psemek/group/dihedral.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -87,6 +88,25 @@ namespace psemek::group return repr_ >= N; } + group::permutation permutation() const + { + if (repr_ < N) + { + typename group::permutation::repr_type repr; + for (Repr i = 0; i < N; ++i) + repr[i] = (i + repr_) % N; + return group::permutation::from_repr(repr); + } + else + { + typename group::permutation::repr_type repr; + for (Repr i = 0; i < N; ++i) + repr[i] = (N - i) % N; + + return rotation(repr_ % N).permutation() * group::permutation::from_repr(repr); + } + } + struct value_iterator { using difference_type = Repr; diff --git a/libs/group/include/psemek/group/permutation.hpp b/libs/group/include/psemek/group/permutation.hpp new file mode 100644 index 00000000..f8efffa1 --- /dev/null +++ b/libs/group/include/psemek/group/permutation.hpp @@ -0,0 +1,154 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +namespace psemek::group +{ + + template + struct permutation + { + static_assert(std::is_integral_v && std::is_unsigned_v); + static_assert(std::numeric_limits::max() > N); + + using repr_type = std::array; + + static constexpr std::size_t size() + { + return N; + } + + permutation() = default; + + static permutation identity() + { + return permutation{}; + } + + static permutation from_repr(repr_type const & value) + { + return permutation{value}; + } + + repr_type const & value() const + { + return repr_; + } + + repr_type operator() (repr_type const & value) const + { + repr_type result; + for (Repr i = 0; i < N; ++i) + result[repr_[i]] = value[i]; + return result; + } + + struct value_iterator + { + using difference_type = Repr; + using value_type = permutation; + using pointer = value_type *; + using reference = value_type &; + using iterator_category = std::forward_iterator_tag; + + repr_type repr; + bool end; + + permutation operator *() const + { + return permutation{repr}; + } + + value_iterator & operator++() + { + end = std::next_permutation(repr.begin(), repr.end()); + return *this; + } + + friend bool operator == (value_iterator const & it1, value_iterator const & it2) + { + return it1.repr == it2.repr && it1.end == it2.end; + } + }; + + static auto values() + { + repr_type repr; + std::iota(repr.begin(), repr.end(), Repr{0}); + return util::range{value_iterator{repr, false}, value_iterator{repr, true}}; + } + + private: + repr_type repr_{0}; + + explicit permutation(repr_type const & repr) + : repr_(repr) + {} + }; + + template + bool operator == (permutation const & g1, permutation const & g2) + { + return g1.value() == g2.value(); + } + + template + auto operator <=> (permutation const & g1, permutation const & g2) + { + return g1.value() <=> g2.value(); + } + + template + permutation operator * (permutation const & g1, permutation const & g2) + { + typename permutation::repr_type repr; + for (Repr i = 0; i < N; ++i) + repr[i] = g1.value()[g2.value()[i]]; + return permutation::from_repr(repr); + } + + template + permutation inverse(permutation const & g) + { + typename permutation::repr_type repr; + for (Repr i = 0; i < N; ++i) + repr[g.value()[i]] = i; + return permutation::from_repr(repr); + } + + template + OStream & operator << (OStream & os, permutation const & g) + { + os << 'S' << N << '('; + for (Repr i = 0; i < N; ++i) + { + if (i > 0) + os << ", "; + os << g.value()[i]; + } + os << ')'; + return os; + } + + template + void write(OStream & out, permutation const & g) + { + write(out, g.value()); + } + + template + void read(IStream & in, permutation & g) + { + typename permutation::repr_type value; + read(in, value); + g = permutation::from_repr(value); + } + +}