use std::hash::Hash;
use nalgebra::DMatrix;
use super::*;
pub trait GraphProperties<'a>: GraphBasics<'a> {
fn incident_edges(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
) -> Option<HashSet<<Self as GraphBasics<'a>>::EdgeIndex>>;
fn contained_nodes(
&'a self,
edge_index: <Self as GraphBasics<'a>>::EdgeIndex,
) -> Option<HashSet<<Self as GraphBasics<'a>>::NodeIndex>>;
fn neighbours(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
) -> Option<HashSet<<Self as GraphBasics<'a>>::NodeIndex>>;
fn neighbour_count(&'a self, node_index: usize) -> Option<usize>;
fn degree(&'a self, node_index: <Self as GraphBasics<'a>>::NodeIndex) -> Option<usize>;
fn degree_by_order(
&'a self,
node_index: <Self as GraphBasics<'a>>::NodeIndex,
order: usize,
) -> Option<usize>;
fn degree_sequence(&'a self) -> Vec<usize> {
(0..self.node_count())
.map(|n| self.degree(n.into()).unwrap())
.collect()
}
fn degree_sequence_by_order(&'a self, order: usize) -> Vec<usize> {
(0..self.node_count())
.map(|n| self.degree_by_order(n.into(), order).unwrap())
.collect()
}
fn connected_components(&'a self) -> Vec<Vec<<Self as GraphBasics<'a>>::NodeIndex>>;
fn is_connected(&'a self) -> bool {
self.connected_components().len() == 1
}
type Subgraph;
fn component(&'a self, node_index: usize) -> Option<Vec<usize>>;
fn extract_component(&'a self, node_index: usize) -> Option<Self::Subgraph>;
fn edges_connecting(
&'a self,
a: <Self as GraphBasics<'a>>::NodeIndex,
b: <Self as GraphBasics<'a>>::NodeIndex,
) -> Option<Vec<<Self as GraphBasics<'a>>::EdgeIndex>> {
let aset = self.incident_edges(a)?;
let bset = self.incident_edges(b)?;
let out = aset.intersection(&bset).map(|e| *e).collect::<Vec<_>>();
Some(out)
}
}
pub trait Measures<'a, N, E>: GraphProperties<'a> {
fn degree_distribution(&'a self) -> HashMap<usize, usize> {
let mut dist = HashMap::new();
for node_index in 0..self.node_count() {
let degree = self.degree(node_index.into()).unwrap();
*dist.entry(degree).or_insert(0) += 1;
}
dist
}
fn jaccard_similarity(&'a self, a: Self::EdgeIndex, b: Self::EdgeIndex) -> Option<f64> {
let a_nodes = self.contained_nodes(a)?;
let b_nodes = self.contained_nodes(b)?;
let intersection = a_nodes.intersection(&b_nodes).count();
let union = a_nodes.union(&b_nodes).count();
Some(if union == 0 {
0.0
} else {
intersection as f64 / union as f64
})
}
fn jaccard_similarity_matrix(&'a self) -> DMatrix<f64> {
let mut matrix = DMatrix::zeros(self.edge_count(), self.edge_count());
for (i, j) in (0..self.edge_count()).cartesian_product(0..self.edge_count()) {
if let Some(sim) = self.jaccard_similarity(i.into(), j.into()) {
matrix[(i, j)] = sim;
}
}
matrix
}
}
impl<'a, N, E, T> Measures<'a, N, E> for T
where
T: GraphProperties<'a>,
N: 'a + Clone + Eq + Hash,
E: 'a + Clone + Eq + Hash,
{
}
pub trait EigenMeasures<'a, N, E>: Measures<'a, N, E> {
fn cec(&'a self) -> Vec<f64>;
fn zec(&'a self) -> Vec<f64>;
fn hec(&'a self) -> Vec<f64>;
}
pub trait Centralities<'a, N, E>: Measures<'a, N, E> {
fn closeness_centrality(&'a self) -> Vec<f64>;
fn betweenness_centrality(&'a self) -> Vec<f64>;
fn closeness_centrality_nodes(&'a self) -> Vec<f64>;
fn betweenness_centrality_nodes(&'a self) -> Vec<f64>;
fn shgraph_centrality(&'a self) -> Vec<f64>;
}
pub trait HypergraphProperties<'a, N, E>: GraphProperties<'a> + HypergraphBasics<'a> {
fn order(&'a self, edge_index: <Self as GraphBasics<'a>>::EdgeIndex) -> Option<usize>;
fn order_sequence(&'a self) -> Vec<usize> {
(0..self.edge_count())
.map(|e| self.order(e.into()).unwrap())
.collect()
}
fn rank(&'a self) -> usize {
(0..self.edge_count())
.map(|e| self.contained_nodes(e.into()).unwrap().len())
.max()
.unwrap_or(0)
}
fn graph_view(&'a self) -> Graph<&'a N, &'a E>;
fn edges_containing(
&'a self,
a: &[<Self as GraphBasics<'a>>::NodeIndex],
) -> Option<Vec<<Self as GraphBasics<'a>>::EdgeIndex>> {
if a.is_empty() {
return Some(Vec::new());
}
let mut wset = self.incident_edges(a[0])?;
for &node_index in &a[1..] {
let eset = self.incident_edges(node_index)?;
wset.retain(|x| eset.contains(x));
}
Some(wset.into_iter().collect())
}
}