Add permutation groups & implement converting cyclic & dihedral groups into permutations
This commit is contained in:
parent
1f57c76036
commit
ce829f7356
3 changed files with 183 additions and 0 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/group/permutation.hpp>
|
||||||
#include <psemek/util/range.hpp>
|
#include <psemek/util/range.hpp>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
@ -55,6 +56,14 @@ namespace psemek::group
|
||||||
return repr_;
|
return repr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group::permutation<N, Repr> permutation() const
|
||||||
|
{
|
||||||
|
typename group::permutation<N, Repr>::repr_type repr;
|
||||||
|
for (Repr i = 0; i < N; ++i)
|
||||||
|
repr[i] = (i + repr_) % N;
|
||||||
|
return group::permutation<N, Repr>::from_repr(repr);
|
||||||
|
}
|
||||||
|
|
||||||
struct value_iterator
|
struct value_iterator
|
||||||
{
|
{
|
||||||
using difference_type = Repr;
|
using difference_type = Repr;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/group/cyclic.hpp>
|
#include <psemek/group/cyclic.hpp>
|
||||||
|
#include <psemek/group/permutation.hpp>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
@ -87,6 +88,25 @@ namespace psemek::group
|
||||||
return repr_ >= N;
|
return repr_ >= N;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group::permutation<N, Repr> permutation() const
|
||||||
|
{
|
||||||
|
if (repr_ < N)
|
||||||
|
{
|
||||||
|
typename group::permutation<N, Repr>::repr_type repr;
|
||||||
|
for (Repr i = 0; i < N; ++i)
|
||||||
|
repr[i] = (i + repr_) % N;
|
||||||
|
return group::permutation<N, Repr>::from_repr(repr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
typename group::permutation<N, Repr>::repr_type repr;
|
||||||
|
for (Repr i = 0; i < N; ++i)
|
||||||
|
repr[i] = (N - i) % N;
|
||||||
|
|
||||||
|
return rotation(repr_ % N).permutation() * group::permutation<N, Repr>::from_repr(repr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct value_iterator
|
struct value_iterator
|
||||||
{
|
{
|
||||||
using difference_type = Repr;
|
using difference_type = Repr;
|
||||||
|
|
|
||||||
154
libs/group/include/psemek/group/permutation.hpp
Normal file
154
libs/group/include/psemek/group/permutation.hpp
Normal file
|
|
@ -0,0 +1,154 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <psemek/util/range.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <limits>
|
||||||
|
#include <array>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
namespace psemek::group
|
||||||
|
{
|
||||||
|
|
||||||
|
template <std::size_t N, typename Repr = std::size_t>
|
||||||
|
struct permutation
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral_v<Repr> && std::is_unsigned_v<Repr>);
|
||||||
|
static_assert(std::numeric_limits<Repr>::max() > N);
|
||||||
|
|
||||||
|
using repr_type = std::array<Repr, N>;
|
||||||
|
|
||||||
|
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<N, Repr>;
|
||||||
|
using pointer = value_type *;
|
||||||
|
using reference = value_type &;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
|
||||||
|
repr_type repr;
|
||||||
|
bool end;
|
||||||
|
|
||||||
|
permutation<N, Repr> operator *() const
|
||||||
|
{
|
||||||
|
return permutation<N, Repr>{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 <std::size_t N, typename Repr>
|
||||||
|
bool operator == (permutation<N, Repr> const & g1, permutation<N, Repr> const & g2)
|
||||||
|
{
|
||||||
|
return g1.value() == g2.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, typename Repr>
|
||||||
|
auto operator <=> (permutation<N, Repr> const & g1, permutation<N, Repr> const & g2)
|
||||||
|
{
|
||||||
|
return g1.value() <=> g2.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, typename Repr>
|
||||||
|
permutation<N, Repr> operator * (permutation<N, Repr> const & g1, permutation<N, Repr> const & g2)
|
||||||
|
{
|
||||||
|
typename permutation<N, Repr>::repr_type repr;
|
||||||
|
for (Repr i = 0; i < N; ++i)
|
||||||
|
repr[i] = g1.value()[g2.value()[i]];
|
||||||
|
return permutation<N, Repr>::from_repr(repr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t N, typename Repr>
|
||||||
|
permutation<N, Repr> inverse(permutation<N, Repr> const & g)
|
||||||
|
{
|
||||||
|
typename permutation<N, Repr>::repr_type repr;
|
||||||
|
for (Repr i = 0; i < N; ++i)
|
||||||
|
repr[g.value()[i]] = i;
|
||||||
|
return permutation<N, Repr>::from_repr(repr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OStream, std::size_t N, typename Repr>
|
||||||
|
OStream & operator << (OStream & os, permutation<N, Repr> const & g)
|
||||||
|
{
|
||||||
|
os << 'S' << N << '(';
|
||||||
|
for (Repr i = 0; i < N; ++i)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
os << ", ";
|
||||||
|
os << g.value()[i];
|
||||||
|
}
|
||||||
|
os << ')';
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OStream, std::size_t N, typename Repr>
|
||||||
|
void write(OStream & out, permutation<N, Repr> const & g)
|
||||||
|
{
|
||||||
|
write(out, g.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename IStream, std::size_t N, typename Repr>
|
||||||
|
void read(IStream & in, permutation<N, Repr> & g)
|
||||||
|
{
|
||||||
|
typename permutation<N, Repr>::repr_type value;
|
||||||
|
read(in, value);
|
||||||
|
g = permutation<N, Repr>::from_repr(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue