pub mod centrality;
pub mod community;
pub mod components;
pub mod cycles;
pub mod kcore;
pub mod pathfinding;
pub mod similarity;
pub mod stats;
#[derive(Clone, Debug)]
pub struct Adjacency {
pub n: usize,
pub out: Vec<Vec<(usize, f32)>>,
pub inc: Vec<Vec<(usize, f32)>>,
pub und: Vec<Vec<(usize, f32)>>,
}
impl Adjacency {
#[must_use]
pub fn from_edges(n: usize, edges: &[(usize, usize)]) -> Self {
let weighted: Vec<(usize, usize, f32)> = edges.iter().map(|&(a, b)| (a, b, 1.0)).collect();
Self::from_weighted(n, &weighted)
}
#[must_use]
pub fn from_weighted(n: usize, edges: &[(usize, usize, f32)]) -> Self {
let mut out = vec![Vec::new(); n];
let mut inc = vec![Vec::new(); n];
let mut und = vec![Vec::new(); n];
for &(a, b, w) in edges {
if a == b || a >= n || b >= n {
continue;
}
accumulate(&mut out[a], b, w);
accumulate(&mut inc[b], a, w);
accumulate(&mut und[a], b, w);
accumulate(&mut und[b], a, w);
}
Self { n, out, inc, und }
}
#[must_use]
pub fn out_degree(&self, i: usize) -> usize {
self.out.get(i).map_or(0, Vec::len)
}
#[must_use]
pub fn in_degree(&self, i: usize) -> usize {
self.inc.get(i).map_or(0, Vec::len)
}
#[must_use]
pub fn degree(&self, i: usize) -> usize {
self.und.get(i).map_or(0, Vec::len)
}
}
fn accumulate(list: &mut Vec<(usize, f32)>, j: usize, w: f32) {
if let Some(e) = list.iter_mut().find(|(k, _)| *k == j) {
e.1 += w;
} else {
list.push((j, w));
}
}
#[cfg(test)]
pub(crate) fn fixture() -> (usize, Vec<(usize, usize)>) {
(5, vec![(0, 1), (1, 2), (2, 0), (3, 4)])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adjacency_builds_directed_and_undirected_views() {
let (n, edges) = fixture();
let g = Adjacency::from_edges(n, &edges);
assert_eq!(g.n, 5);
assert_eq!(g.out_degree(0), 1); assert_eq!(g.in_degree(0), 1); assert_eq!(g.degree(0), 2); assert_eq!(g.degree(3), 1);
assert_eq!(g.degree(4), 1);
}
#[test]
fn self_loops_and_out_of_range_dropped_parallel_accumulate() {
let g = Adjacency::from_weighted(3, &[(0, 0, 1.0), (0, 5, 1.0), (0, 1, 2.0), (0, 1, 3.0)]);
assert_eq!(g.out_degree(0), 1); assert_eq!(g.out[0][0], (1, 5.0)); }
}