use std::collections::BTreeSet;
use crate::graph::topology::{Topology, Transitive};
use crate::graph::Graph;
pub struct CommonAncestors<'a> {
topology: &'a Topology<Transitive>,
ancestors: BTreeSet<usize>,
}
impl<T> Graph<T, Transitive> {
pub fn common_ancestors<N>(&self, nodes: N) -> CommonAncestors<'_>
where
N: AsRef<[usize]>,
{
let nodes = nodes.as_ref();
let mut ancestors = BTreeSet::new();
for ancestor in self {
let mut iter = nodes.iter();
if iter.all(|&node| self.topology.has_path(ancestor, node)) {
ancestors.insert(ancestor);
}
}
CommonAncestors {
topology: &self.topology,
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 {
let mut iter = self.ancestors.iter();
if !iter.any(|&node| {
node != ancestor && self.topology.has_path(ancestor, node)
}) {
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! {
transitive;
"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! {
transitive;
"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]]
);
}
}
}