psemek/libs/group/include/psemek/group/dihedral.hpp

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;
}
}