use std::collections::BTreeSet;
use crate::graph::topology::Distance;
use crate::graph::Graph;
pub struct CommonAncestors<'a> {
distance: &'a Distance,
ancestors: BTreeSet<usize>,
}
impl<T> Graph<T> {
pub fn common_ancestors<N>(&self, nodes: N) -> CommonAncestors<'_>
where
N: AsRef<[usize]>,
{
let distance = self.topology.distance();
let nodes = nodes.as_ref();
let mut ancestors = BTreeSet::default();
for ancestor in self {
if nodes.iter().all(|&node| {
node != ancestor && distance[ancestor][node] != u8::MAX
}) {
ancestors.insert(ancestor);
}
}
CommonAncestors {
distance: self.topology.distance(),
ancestors,
}
}
}
impl Iterator for CommonAncestors<'_> {
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.ancestors.is_empty() {
return None;
}
let mut layer = Vec::new();
for &ancestor in &self.ancestors {
if !self.ancestors.iter().any(|&node| {
ancestor != node && self.distance[ancestor][node] != u8::MAX
}) {
layer.push(ancestor);
}
}
self.ancestors.retain(|node| !layer.contains(node));
(!layer.is_empty()).then_some(layer)
}
}
#[cfg(test)]
mod tests {
mod common_ancestors {
use crate::graph;
#[test]
fn handles_graph() {
let graph = graph! {
"a" => "d",
"b" => "d", "b" => "e",
"c" => "f", "c" => "g",
"d" => "f", "d" => "g",
"e" => "g",
};
assert_eq!(
graph.common_ancestors([5, 6]).collect::<Vec<_>>(),
vec![vec![1, 4], vec![0, 2]]
);
}
#[test]
fn handles_multi_graph() {
let graph = graph! {
"a" => "d",
"b" => "d", "b" => "e", "b" => "e",
"c" => "f", "c" => "g",
"d" => "f", "d" => "g",
"e" => "g",
};
assert_eq!(
graph.common_ancestors([5, 6]).collect::<Vec<_>>(),
vec![vec![1, 4], vec![0, 2]]
);
}
}
}