use core::fmt::{Debug, Formatter};
use crate::topology::sieve::oriented::Orientation;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Default)]
#[repr(transparent)]
pub struct BitFlip(pub bool);
impl Debug for BitFlip {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("BitFlip").field(&self.0).finish()
}
}
impl Orientation for BitFlip {
#[inline]
fn compose(a: Self, b: Self) -> Self {
BitFlip(a.0 ^ b.0)
}
#[inline]
fn inverse(a: Self) -> Self {
a
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Rot<const N: u8>(pub u8);
impl<const N: u8> Default for Rot<N> {
fn default() -> Self {
Rot(0)
}
}
impl<const N: u8> Debug for Rot<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Rot").field(&self.0).finish()
}
}
impl<const N: u8> Orientation for Rot<N> {
#[inline]
fn compose(a: Self, b: Self) -> Self {
Rot::<N>((a.0 + b.0) % N)
}
#[inline]
fn inverse(a: Self) -> Self {
Rot::<N>((N - (a.0 % N)) % N)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Dihedral<const N: u8> {
pub rot: u8,
pub flip: bool,
}
impl<const N: u8> Default for Dihedral<N> {
fn default() -> Self {
Self {
rot: 0,
flip: false,
}
}
}
impl<const N: u8> Debug for Dihedral<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Dihedral")
.field("rot", &self.rot)
.field("flip", &self.flip)
.finish()
}
}
impl<const N: u8> Orientation for Dihedral<N> {
#[inline]
fn compose(a: Self, b: Self) -> Self {
let add = if a.flip {
(N - (b.rot % N)) % N
} else {
b.rot % N
};
let rot = (a.rot + add) % N;
let flip = a.flip ^ b.flip;
Self { rot, flip }
}
#[inline]
fn inverse(a: Self) -> Self {
if !a.flip {
Self {
rot: (N - (a.rot % N)) % N,
flip: false,
}
} else {
Self {
rot: a.rot % N,
flip: true,
}
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct Perm<const K: usize>(pub [u8; K]);
impl<const K: usize> Default for Perm<K> {
fn default() -> Self {
let mut id = [0u8; K];
let mut i = 0;
while i < K {
id[i] = i as u8;
i += 1;
}
Perm(id)
}
}
impl<const K: usize> Debug for Perm<K> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Perm").field(&self.0).finish()
}
}
impl<const K: usize> Perm<K> {
#[inline]
pub fn new_unchecked(p: [u8; K]) -> Self {
Perm(p)
}
#[inline]
pub fn invert(&self) -> Self {
let mut inv = [0u8; K];
let mut i = 0;
while i < K {
inv[self.0[i] as usize] = i as u8;
i += 1;
}
Perm(inv)
}
}
impl<const K: usize> Orientation for Perm<K> {
#[inline]
fn compose(a: Self, b: Self) -> Self {
let mut out = [0u8; K];
let mut i = 0;
while i < K {
out[i] = a.0[b.0[i] as usize];
i += 1;
}
Perm(out)
}
#[inline]
fn inverse(a: Self) -> Self {
a.invert()
}
}
pub use BitFlip as Sign; pub type D3 = Dihedral<3>;
pub type D4 = Dihedral<4>;
pub type S3 = Perm<3>;
pub type S4 = Perm<4>;
#[inline]
pub fn accumulate_path<O, I>(path: I) -> O
where
O: Orientation,
I: IntoIterator<Item = O>,
{
path.into_iter()
.fold(O::default(), |acc, step| O::compose(acc, step))
}
pub trait AccumulatePathExt: Sized {
fn accumulate_path<O, I>(path: I) -> O
where
O: Orientation,
I: IntoIterator<Item = O>,
{
accumulate_path(path)
}
}
impl<T> AccumulatePathExt for T {}