use std::ops::{Deref, Mul, Not};
use bellframe::{Bell, Row, RowBuf, Stage};
use datasize::DataSize;
use gcd::Gcd;
#[derive(Debug, Clone)]
pub struct PartHeadGroup {
part_heads: Vec<RowBuf>,
is_generator_bitmap: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DataSize)]
pub struct PartHead {
index: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PhRotation {
rotation: u8,
num_parts: u8,
}
impl PartHeadGroup {
pub fn new(row: &Row) -> Self {
let part_heads = row.closure_from_rounds();
Self {
is_generator_bitmap: coprime_bitmap(part_heads.len()),
part_heads,
}
}
pub fn one_part(stage: Stage) -> Self {
Self::new(&RowBuf::rounds(stage))
}
pub fn effective_stage(&self) -> Stage {
self.part_heads.last().unwrap().effective_stage()
}
pub fn size(&self) -> usize {
self.part_heads.len()
}
pub fn is_one_part(&self) -> bool {
self.size() == 1
}
pub fn is_multi_part(&self) -> bool {
!self.is_one_part()
}
pub fn rows(&self) -> impl Iterator<Item = &Row> + Clone {
self.part_heads.iter().map(Deref::deref)
}
pub fn rotations(&self) -> impl Iterator<Item = (&Row, PhRotation)> {
self.part_heads.iter().enumerate().map(|(idx, row)| {
(
row.as_row(),
PhRotation {
rotation: idx as u8,
num_parts: self.size() as u8,
},
)
})
}
pub fn bell_cycles(&self) -> Vec<Vec<Bell>> {
let base_part_head = self.part_heads.last().unwrap();
let mut bells_used = vec![false; base_part_head.stage().num_bells()];
let mut groups = Vec::new();
while let Some(group_start) = bells_used.iter().position(|u| !*u) {
let group_start = Bell::from_index(group_start as u8);
let mut group = Vec::new();
let mut next_bell = group_start;
loop {
group.push(next_bell);
bells_used[next_bell.index()] = true;
next_bell = base_part_head[next_bell.index()];
if next_bell == group_start {
break; }
}
groups.push(group);
}
groups
}
pub fn get_row(&self, element: PartHead) -> &Row {
&self.part_heads[element.index as usize]
}
pub fn is_generator(&self, part_head: PartHead) -> bool {
self.is_generator_bitmap & (1 << part_head.index) != 0
}
}
impl PartHead {
pub fn rounds() -> Self {
PartHead { index: 0 }
}
}
impl PhRotation {
pub fn is_identity(self) -> bool {
self.rotation == 0
}
}
impl Not for PhRotation {
type Output = Self;
fn not(self) -> Self {
PhRotation {
rotation: (self.num_parts - self.rotation) % self.num_parts,
num_parts: self.num_parts,
}
}
}
impl Mul<PhRotation> for PartHead {
type Output = Self;
fn mul(self, rot: PhRotation) -> Self {
PartHead {
index: (self.index + rot.rotation) % rot.num_parts,
}
}
}
fn coprime_bitmap(n: usize) -> u64 {
assert!(n <= 64);
assert!(n > 0);
if n == 1 {
return 1; }
let mut mask = 0;
for i in 1..n {
if i.gcd(n) == 1 {
mask |= 1 << i;
}
}
mask
}