use fixedbitset::FixedBitSet;
use hashbrown::HashSet;
use itertools::Itertools;
use crate::prelude::*;
pub trait GraphType: Send + Sync {}
pub struct Undirected;
impl GraphType for Undirected {}
pub struct Directed;
impl GraphType for Directed {}
#[cfg(feature = "multiplex")]
pub struct Multiplex;
#[cfg(feature = "multiplex")]
impl GraphType for Multiplex {}
#[cfg(feature = "temporal")]
pub struct Temporal;
#[cfg(feature = "temporal")]
impl GraphType for Temporal {}
pub trait CommonProperties<'a, T: GraphType>: GraphBasics<'a> {
fn graph_type(&self) -> T;
fn visit_map(&'a self) -> FixedBitSet {
FixedBitSet::with_capacity(self.node_count())
}
fn is_empty(&'a self) -> bool {
self.node_count() == 0 && self.edge_count() == 0
}
fn costed_neighbours<F, K>(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
cost: F,
) -> impl Iterator<Item = (K, HashSet<Self::NodeIndex>)>
where
F: Fn(<Self as GraphBasics<'a>>::EdgeIndex) -> K;
fn costed_pairs<F, K>(
&'a self,
cost: F,
) -> (
bool,
impl Iterator<Item = (K, Vec<(Self::NodeIndex, Self::NodeIndex)>)>,
)
where
F: Fn(<Self as GraphBasics<'a>>::EdgeIndex) -> K;
fn neighbours_or_out_neighbours(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
) -> Option<impl Iterator<Item = Self::NodeIndex>>;
fn connects_nodes(
&'a self,
n1: Self::NodeIndex,
n2: Self::NodeIndex,
e: Self::EdgeIndex,
) -> bool;
fn neighbours_with_edges(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
) -> impl Iterator<Item = (Self::EdgeIndex, HashSet<Self::NodeIndex>)> {
self.costed_neighbours(node_index, |e| e)
}
}
impl<'a, T> CommonProperties<'a, Undirected> for T
where
T: GraphBasics<'a> + GraphProperties<'a>,
{
fn graph_type(&self) -> Undirected {
Undirected
}
fn costed_neighbours<F, K>(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
cost: F,
) -> impl Iterator<Item = (K, HashSet<Self::NodeIndex>)>
where
F: Fn(<Self as GraphBasics<'a>>::EdgeIndex) -> K,
{
self.incident_edges(node_index)
.unwrap()
.into_iter()
.map(move |edge_index| {
let nodes = self.contained_nodes(edge_index).unwrap();
let cost_value = cost(edge_index);
(cost_value, nodes)
})
}
fn is_empty(&'a self) -> bool {
self.node_count() == 0 && self.edge_count() == 0
}
fn costed_pairs<F, K>(
&'a self,
cost: F,
) -> (
bool,
impl Iterator<Item = (K, Vec<(Self::NodeIndex, Self::NodeIndex)>)>,
)
where
F: Fn(<Self as GraphBasics<'a>>::EdgeIndex) -> K,
{
(
true,
(0..self.edge_count()).map(move |e| {
let nodes = self.contained_nodes(e.into()).unwrap();
let cost_value = cost(e.into());
(
cost_value,
nodes
.iter()
.map(|&n| n)
.tuple_combinations()
.collect::<Vec<_>>(),
)
}),
)
}
fn neighbours_or_out_neighbours(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
) -> Option<impl Iterator<Item = Self::NodeIndex>> {
self.neighbours(node_index).map(|x| x.into_iter())
}
fn connects_nodes(
&'a self,
n1: Self::NodeIndex,
n2: Self::NodeIndex,
e: Self::EdgeIndex,
) -> bool {
self.contained_nodes(e)
.map(|v| v.contains(&n1) && v.contains(&n2))
.unwrap_or(false)
}
}
impl<'a, T> CommonProperties<'a, Directed> for T
where
T: GraphBasics<'a> + DiGraphProperties<'a>,
{
fn graph_type(&self) -> Directed {
Directed
}
fn costed_neighbours<F, K>(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
cost: F,
) -> impl Iterator<Item = (K, HashSet<Self::NodeIndex>)>
where
F: Fn(<Self as GraphBasics<'a>>::EdgeIndex) -> K,
{
self.out_edges(node_index)
.unwrap()
.into_iter()
.map(move |edge_index| {
let nodes = self.target(edge_index).unwrap();
let cost_value = cost(edge_index);
(cost_value, nodes)
})
}
fn costed_pairs<F, K>(
&'a self,
cost: F,
) -> (
bool,
impl Iterator<Item = (K, Vec<(Self::NodeIndex, Self::NodeIndex)>)>,
)
where
F: Fn(<Self as GraphBasics<'a>>::EdgeIndex) -> K,
{
(
false,
(0..self.edge_count()).map(move |e| {
let source = self.source(e.into()).unwrap();
let target = self.target(e.into()).unwrap();
let cost_value = cost(e.into());
(
cost_value,
source
.iter()
.cartesian_product(target.iter())
.map(|(s, t)| (*s, *t))
.collect::<Vec<_>>(),
)
}),
)
}
fn neighbours_or_out_neighbours(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
) -> Option<impl Iterator<Item = Self::NodeIndex>> {
self.out_neighbours(node_index).map(|x| x.into_iter())
}
fn connects_nodes(
&'a self,
n1: Self::NodeIndex,
n2: Self::NodeIndex,
e: Self::EdgeIndex,
) -> bool {
self.source(e).map(|v| v.contains(&n1)).unwrap_or(false)
&& self.target(e).map(|v| v.contains(&n2)).unwrap_or(false)
}
}