use std::ops::BitXorAssign;
use bitm::{BitAccess, BitVec};
pub trait VertexIndex: BitXorAssign + Default + Copy + Sized {
fn from_usize(u: usize) -> Self;
fn to_usize(self) -> usize;
}
impl VertexIndex for usize {
#[inline(always)] fn from_usize(u: usize) -> Self { u }
#[inline(always)] fn to_usize(self) -> usize { self }
}
impl VertexIndex for u32 {
#[inline(always)] fn from_usize(u: usize) -> Self { u as u32 }
#[inline(always)] fn to_usize(self) -> usize { self as usize }
}
#[derive(Default, Clone, Copy)]
struct XoredAdjacencyList<VertexIndex = usize> {
v0: VertexIndex, v1: VertexIndex, len: usize }
impl<VI: VertexIndex> XoredAdjacencyList<VI> {
#[inline] pub fn add_canonized_edge(&mut self, v0: usize, v1: usize) {
self.v0 ^= VI::from_usize(v0);
self.v1 ^= VI::from_usize(v1);
self.len += 1;
}
#[inline] pub fn add_edge(&mut self, v0: usize, v1: usize) {
if v0 < v1 { self.add_canonized_edge(v0, v1) } else { self.add_canonized_edge(v1, v0) }
}
#[inline] pub fn remove_canonized_edge(&mut self, v0: usize, v1: usize) {
self.v0 ^= VI::from_usize(v0);
self.v1 ^= VI::from_usize(v1);
self.len -= 1;
}
#[inline] pub fn remove_edge(&mut self, v0: usize, v1: usize) {
if v0 < v1 { self.remove_canonized_edge(v0, v1) } else { self.remove_canonized_edge(v1, v0) }
}
#[inline] pub fn try_get_edge(&mut self) -> Option<(usize, usize)> {
(self.len == 1).then(|| (self.v0.to_usize(), self.v1.to_usize()))
}
}
pub trait EdgeValues {
type Value;
fn add_or_remove_value(&mut self, a: usize, b: usize, c: usize, value: Self::Value);
fn get_value(&self, vertex: usize) -> Self::Value;
}
impl EdgeValues for () {
type Value = ();
#[inline(always)] fn add_or_remove_value(&mut self, _a: usize, _b: usize, _c: usize, _value: Self::Value) {}
#[inline(always)] fn get_value(&self, _vertex: usize) -> Self::Value {}
}
pub struct PackedInts {
values: Box<[u64]>,
bits_per_value: u8
}
impl PackedInts {
pub fn new(number_of_values: usize, bits_per_value: u8) -> Self {
Self { values: Box::with_zeroed_bits(number_of_values * bits_per_value as usize), bits_per_value }
}
}
impl EdgeValues for PackedInts {
type Value = u64;
fn add_or_remove_value(&mut self, a: usize, b: usize, c: usize, value: Self::Value) {
self.values.xor_fragment(a, value, self.bits_per_value);
self.values.xor_fragment(b, value, self.bits_per_value);
self.values.xor_fragment(c, value, self.bits_per_value);
}
fn get_value(&self, vertex: usize) -> Self::Value {
self.values.get_fragment(vertex, self.bits_per_value)
}
}
pub struct HyperGraph<VertexIndex, Values> {
adjacency_list: Vec<XoredAdjacencyList<VertexIndex>>,
values: Values }
impl<VI: VertexIndex> HyperGraph<VI, ()> {
#[inline] pub fn new(number_of_vertices: usize) -> Self {
Self::with_values(number_of_vertices, ())
}
#[inline] pub fn add_edge(&mut self, a: usize, b: usize, c: usize) {
self.add_edge_with_value(a, b, c, ());
}
#[inline] pub fn peel(self, number_of_edges: usize) -> Vec<(VI, VI, VI)> {
self.peel_with_values(number_of_edges, |_| {})
}
}
impl<VI: VertexIndex> HyperGraph<VI, PackedInts> {
#[inline] pub fn with_bits_per_value(number_of_vertices: usize, bits_per_value: u8) -> Self {
Self::with_values(number_of_vertices, PackedInts::new(number_of_vertices, bits_per_value))
}
}
impl<VI: VertexIndex, Values: EdgeValues> HyperGraph<VI, Values> {
pub fn with_values(number_of_vertices: usize, values: Values) -> Self {
Self { adjacency_list: vec![Default::default(); number_of_vertices], values }
}
pub fn add_edge_with_value(&mut self, a: usize, b: usize, c: usize, value: Values::Value) {
self.adjacency_list[a].add_edge(b, c);
self.adjacency_list[b].add_edge(a, c);
self.adjacency_list[c].add_edge(a, b);
self.values.add_or_remove_value(a, b, c, value);
}
fn try_move_degree1_vertex_into_vec<VC: FnMut(&Values::Value)>(&mut self, vertex: usize, vec: &mut Vec<(VI, VI, VI)>, value_consumer: &mut VC) {
if let Some((v0, v1)) = self.adjacency_list[vertex as usize].try_get_edge() {
self.adjacency_list[vertex as usize].remove_canonized_edge(v0, v1);
self.adjacency_list[v0 as usize].remove_edge(vertex, v1);
self.adjacency_list[v1 as usize].remove_edge(v0, vertex);
vec.push((VI::from_usize(vertex), VI::from_usize(v0), VI::from_usize(v1)));
let value = self.values.get_value(vertex);
value_consumer(&value);
self.values.add_or_remove_value(vertex, v0, v1, value)
}
}
pub fn peel_with_values<VC: FnMut(&Values::Value)>(mut self, number_of_edges: usize, mut value_consumer: VC) -> Vec<(VI, VI, VI)> {
let mut result = Vec::with_capacity(number_of_edges);
for vertex in 0..self.adjacency_list.len() {
self.try_move_degree1_vertex_into_vec(vertex, &mut result, &mut value_consumer);
}
let mut i = 0;
while i < result.len() {
debug_assert_eq!(self.adjacency_list[result[i].0.to_usize()].len, 0);
self.try_move_degree1_vertex_into_vec(result[i].1.to_usize(), &mut result, &mut value_consumer);
self.try_move_degree1_vertex_into_vec(result[i].2.to_usize(), &mut result, &mut value_consumer);
i += 1;
}
result
}
}