use crate::dot::render_to_graphviz_dot;
pub(super) use crate::private::ExtendedDebug;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use std::{
fmt::{Debug, Formatter, Result},
hash::Hash,
};
pub type HyperedgeVertices = Vec<usize>;
pub type HyperedgeIndex = usize;
pub type WeightedHyperedgeIndex = (HyperedgeIndex, usize);
pub type VertexIndex = usize;
pub struct Hypergraph<V, HE> {
pub vertices: IndexMap<V, IndexSet<HyperedgeVertices>>,
pub hyperedges: IndexMap<HyperedgeVertices, IndexSet<HE>>,
}
impl<V: Eq + Hash + Debug, HE: Debug> Debug for Hypergraph<V, HE> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
self.vertices.fmt(f)
}
}
pub trait SharedTrait: Copy + Debug + Eq + Hash {}
impl<T> SharedTrait for T where T: Copy + Debug + Eq + Hash {}
impl<'a, V, HE> Default for Hypergraph<V, HE>
where
V: SharedTrait + ExtendedDebug<'a>,
HE: SharedTrait + ExtendedDebug<'a>,
{
fn default() -> Self {
Hypergraph::new()
}
}
impl<V, HE> Hypergraph<V, HE>
where
V: SharedTrait,
HE: SharedTrait,
{
pub fn new() -> Self {
Hypergraph::with_capacity(0, 0)
}
pub fn with_capacity(vertices: usize, hyperedges: usize) -> Self {
Hypergraph {
vertices: IndexMap::with_capacity(vertices),
hyperedges: IndexMap::with_capacity(hyperedges),
}
}
pub fn add_vertex(&mut self, weight: V) -> VertexIndex {
self.vertices
.entry(weight)
.or_insert(IndexSet::with_capacity(0));
self.vertices.get_index_of(&weight).unwrap()
}
pub fn get_vertex_weight(&self, index: VertexIndex) -> Option<&V> {
self.vertices.get_index(index).map(|(weight, _)| weight)
}
pub fn count_vertices(&self) -> usize {
self.vertices.len()
}
pub fn add_hyperedge(&mut self, vertices: &[usize], weight: HE) -> WeightedHyperedgeIndex {
for vertex in vertices.iter() {
let mut set = self.vertices[*vertex].clone();
set.insert(vertices.to_vec());
self.vertices
.insert(self.vertices.get_index(*vertex).unwrap().0.to_owned(), set);
}
match self.hyperedges.get(vertices) {
Some(weights) => {
let mut new_weights = weights.clone();
let (weight_index, _) = new_weights.insert_full(weight);
let (hyperedge_index, _) = self
.hyperedges
.insert_full(vertices.to_owned(), new_weights);
(hyperedge_index, weight_index)
}
None => {
let mut weights = IndexSet::new();
let (weight_index, _) = weights.insert_full(weight);
let (hyperedge_index, _) =
self.hyperedges.insert_full(vertices.to_owned(), weights);
(hyperedge_index, weight_index)
}
}
}
pub fn count_hyperedges(&self) -> usize {
self.hyperedges
.iter()
.fold(0, |count, (_, weights)| count + weights.len())
}
pub fn get_hyperedge_weight(
&self,
(hyperedge_index, weight_index): WeightedHyperedgeIndex,
) -> Option<&HE> {
match self.hyperedges.get_index(hyperedge_index) {
Some((_, weights)) => weights.get_index(weight_index),
None => None,
}
}
pub fn get_hyperedge_vertices(&self, index: HyperedgeIndex) -> Option<&HyperedgeVertices> {
self.hyperedges
.get_index(index)
.map(|(vertices, _)| vertices)
}
pub fn get_hyperedges_intersections(&self, hyperedges: &[HyperedgeIndex]) -> HyperedgeVertices {
hyperedges
.iter()
.filter_map(|index| {
self.hyperedges
.get_index(*index)
.map(|(vertices, _)| vertices.iter().unique().collect_vec())
})
.flatten()
.sorted()
.map(|index| (*index, 0))
.into_group_map()
.iter()
.filter_map(|(index, occurences)| {
if occurences.len() == hyperedges.len() {
Some(*index)
} else {
None
}
})
.sorted()
.collect::<Vec<usize>>()
}
pub fn render_to_graphviz_dot(&self) {
println!("{}", render_to_graphviz_dot(&self));
}
}