182 lines
4 KiB
C++
182 lines
4 KiB
C++
#pragma once
|
|
|
|
#include <psemek/group/cyclic.hpp>
|
|
|
|
#include <cstddef>
|
|
#include <type_traits>
|
|
#include <limits>
|
|
|
|
namespace psemek::group
|
|
{
|
|
|
|
template <std::size_t N, typename Repr = std::size_t>
|
|
struct dihedral
|
|
{
|
|
static_assert(std::is_integral_v<Repr> && std::is_unsigned_v<Repr>);
|
|
static_assert(std::numeric_limits<Repr>::max() > N);
|
|
|
|
static constexpr std::size_t size()
|
|
{
|
|
return 2 * N;
|
|
}
|
|
|
|
dihedral() = default;
|
|
|
|
static dihedral identity()
|
|
{
|
|
return dihedral{};
|
|
}
|
|
|
|
static dihedral rotation(Repr const & repr)
|
|
{
|
|
return dihedral{repr % static_cast<Repr>(N)};
|
|
}
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
|
static dihedral rotation(T const & value)
|
|
{
|
|
if (value >= 0)
|
|
return dihedral{static_cast<Repr>(static_cast<std::size_t>(value) % N)};
|
|
else
|
|
{
|
|
auto r = (static_cast<std::int64_t>(value) % static_cast<std::int64_t>(N));
|
|
return dihedral{static_cast<Repr>((r < 0) ? r + static_cast<std::int64_t>(N) : r)};
|
|
}
|
|
}
|
|
|
|
template <typename Repr2>
|
|
static dihedral rotation(cyclic<N, Repr2> const & value)
|
|
{
|
|
return dihedral{static_cast<Repr>(value.repr())};
|
|
}
|
|
|
|
static dihedral reflection(Repr repr)
|
|
{
|
|
return dihedral{(repr % static_cast<Repr>(N)) + static_cast<Repr>(N)};
|
|
}
|
|
|
|
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
|
static dihedral reflection(T const & value)
|
|
{
|
|
if (value >= 0)
|
|
return dihedral{static_cast<Repr>((static_cast<std::size_t>(value) % N) + N)};
|
|
else
|
|
{
|
|
auto r = (static_cast<std::int64_t>(value) % static_cast<std::int64_t>(N));
|
|
return dihedral{static_cast<Repr>((r < 0) ? r + static_cast<std::int64_t>(2 * N) : r + static_cast<std::int64_t>(N))};
|
|
}
|
|
}
|
|
|
|
Repr value() const
|
|
{
|
|
return repr_;
|
|
}
|
|
|
|
bool is_rotation() const
|
|
{
|
|
return repr_ < N;
|
|
}
|
|
|
|
bool is_reflection() const
|
|
{
|
|
return repr_ >= N;
|
|
}
|
|
|
|
struct value_iterator
|
|
{
|
|
using difference_type = Repr;
|
|
using value_type = dihedral<N, Repr>;
|
|
using pointer = value_type *;
|
|
using reference = value_type &;
|
|
using iterator_category = std::forward_iterator_tag;
|
|
|
|
Repr repr;
|
|
|
|
dihedral<N, Repr> operator *() const
|
|
{
|
|
return dihedral<N, Repr>{repr};
|
|
}
|
|
|
|
value_iterator & operator++()
|
|
{
|
|
++repr;
|
|
return *this;
|
|
}
|
|
|
|
friend bool operator == (value_iterator const & it1, value_iterator const & it2)
|
|
{
|
|
return it1.repr == it2.repr;
|
|
}
|
|
|
|
friend auto operator - (value_iterator const & it1, value_iterator const & it2)
|
|
{
|
|
return it2.repr - it1.repr;
|
|
}
|
|
};
|
|
|
|
static auto values()
|
|
{
|
|
return util::range{value_iterator{0}, value_iterator{2 * N}};
|
|
}
|
|
|
|
private:
|
|
Repr repr_{0};
|
|
|
|
explicit dihedral(Repr const & repr)
|
|
: repr_(repr)
|
|
{}
|
|
};
|
|
|
|
template <std::size_t N, typename Repr>
|
|
bool operator == (dihedral<N, Repr> const & g1, dihedral<N, Repr> const & g2)
|
|
{
|
|
return g1.value() == g2.value();
|
|
}
|
|
|
|
template <std::size_t N, typename Repr>
|
|
auto operator <=> (dihedral<N, Repr> const & g1, dihedral<N, Repr> const & g2)
|
|
{
|
|
return g1.value() <=> g2.value();
|
|
}
|
|
|
|
template <std::size_t N, typename Repr>
|
|
dihedral<N, Repr> operator * (dihedral<N, Repr> const & g1, dihedral<N, Repr> const & g2)
|
|
{
|
|
if (g1.is_rotation())
|
|
{
|
|
auto repr = g1.value() + g2.value();
|
|
if (g2.is_rotation())
|
|
return dihedral<N, Repr>::rotation(repr);
|
|
else
|
|
return dihedral<N, Repr>::reflection(repr);
|
|
}
|
|
else
|
|
{
|
|
auto repr = g1.value() + static_cast<Repr>(N) - g2.value();
|
|
if (g2.is_rotation())
|
|
return dihedral<N, Repr>::reflection(repr);
|
|
else
|
|
return dihedral<N, Repr>::rotation(repr);
|
|
}
|
|
}
|
|
|
|
template <std::size_t N, typename Repr>
|
|
dihedral<N, Repr> inverse(dihedral<N, Repr> const & g)
|
|
{
|
|
if (g.is_rotation())
|
|
return dihedral<N, Repr>::rotation(N - g.value());
|
|
else
|
|
return g;
|
|
}
|
|
|
|
template <typename OStream, std::size_t N, typename Repr>
|
|
OStream & operator << (OStream & os, dihedral<N, Repr> const & g)
|
|
{
|
|
if (g.is_rotation())
|
|
os << 'D' << N << "(r" << static_cast<std::size_t>(g.value()) << ")";
|
|
else
|
|
os << 'D' << N << "(s" << (static_cast<std::size_t>(g.value()) % N) << ")";
|
|
return os;
|
|
}
|
|
|
|
}
|