use crate::graph::Graph;
pub fn walk_counts<G: Graph>(graph: &G, len: usize) -> Vec<f64> {
let n = graph.node_count();
let mut counts = vec![1.0_f64; n];
for _ in 0..len {
let mut next = vec![0.0_f64; n];
for (v, out) in next.iter_mut().enumerate() {
for u in graph.neighbors(v) {
if u < n {
*out += counts[u];
}
}
}
counts = next;
}
counts
}
pub fn closed_walk_counts<G: Graph>(graph: &G, len: usize) -> Vec<f64> {
let n = graph.node_count();
let mut out = vec![0.0_f64; n];
for (start, slot) in out.iter_mut().enumerate() {
let mut x = vec![0.0_f64; n];
x[start] = 1.0;
for _ in 0..len {
let mut next = vec![0.0_f64; n];
for (v, o) in next.iter_mut().enumerate() {
for u in graph.neighbors(v) {
if u < n {
*o += x[u];
}
}
}
x = next;
}
*slot = x[start];
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use crate::AdjacencyMatrix;
fn k3() -> Vec<Vec<f64>> {
vec![
vec![0.0, 1.0, 1.0],
vec![1.0, 0.0, 1.0],
vec![1.0, 1.0, 0.0],
]
}
#[test]
fn triangle_counts_match_hand_computation() {
let m = k3();
let g = AdjacencyMatrix(&m);
assert_eq!(walk_counts(&g, 0), vec![1.0; 3]);
assert_eq!(walk_counts(&g, 1), vec![2.0; 3]);
assert_eq!(walk_counts(&g, 2), vec![4.0; 3]);
assert_eq!(closed_walk_counts(&g, 3), vec![2.0; 3]);
}
#[test]
fn four_cycle_closed_walks_match_the_spectrum() {
let m = vec![
vec![0.0, 1.0, 0.0, 1.0],
vec![1.0, 0.0, 1.0, 0.0],
vec![0.0, 1.0, 0.0, 1.0],
vec![1.0, 0.0, 1.0, 0.0],
];
let g = AdjacencyMatrix(&m);
assert_eq!(closed_walk_counts(&g, 3), vec![0.0; 4]);
assert_eq!(closed_walk_counts(&g, 4), vec![8.0; 4]);
}
#[test]
fn path_graph_has_no_closed_odd_walks() {
let m = vec![
vec![0.0, 1.0, 0.0],
vec![1.0, 0.0, 1.0],
vec![0.0, 1.0, 0.0],
];
let g = AdjacencyMatrix(&m);
assert_eq!(walk_counts(&g, 2), vec![2.0, 2.0, 2.0]);
assert_eq!(closed_walk_counts(&g, 3), vec![0.0; 3]);
}
}