use std::collections::BTreeSet;
use crate::graph::topology::Distance;
use crate::graph::Graph;
pub struct CommonDescendants<'a> {
distance: &'a Distance,
descendants: BTreeSet<usize>,
}
impl<T> Graph<T> {
pub fn common_descendants<N>(&self, nodes: N) -> CommonDescendants<'_>
where
N: AsRef<[usize]>,
{
let distance = self.topology.distance();
let nodes = nodes.as_ref();
let mut descendants = BTreeSet::default();
for descendant in self {
if nodes.iter().all(|&node| {
node != descendant && distance[node][descendant] != u8::MAX
}) {
descendants.insert(descendant);
}
}
CommonDescendants {
distance: self.topology.distance(),
descendants,
}
}
}
impl Iterator for CommonDescendants<'_> {
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
if self.descendants.is_empty() {
return None;
}
let mut layer = Vec::new();
for &descendant in &self.descendants {
if !self.descendants.iter().any(|&node| {
descendant != node && self.distance[node][descendant] != u8::MAX
}) {
layer.push(descendant);
}
}
self.descendants.retain(|node| !layer.contains(node));
(!layer.is_empty()).then_some(layer)
}
}
#[cfg(test)]
mod tests {
mod common_descendants {
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_descendants([0, 2]).collect::<Vec<_>>(),
vec![vec![1], vec![5, 6]]
);
}
#[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_descendants([0, 2]).collect::<Vec<_>>(),
vec![vec![1], vec![5, 6]]
);
}
}
}