use crate::{cn, Network};
use std::collections::VecDeque as Queue;
pub const CONTINUE: bool = true;
pub const STOP: bool = false;
pub const TREE_MODEL: &str = "_CN_BFS_TREE";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Path(Option<Vec<(usize, usize)>>);
impl Path {
pub fn visited(&self) -> Option<Vec<usize>> {
let inner = self.0.as_ref()?;
let mut nodes: Vec<usize> = inner.iter().map(|(start, _end)| *start).collect();
if let Some((_prev, last)) = inner.last() {
nodes.push(*last);
}
Some(nodes)
}
pub fn as_vec(&self) -> Option<&Vec<(usize, usize)>> {
self.0.as_ref()
}
pub(crate) fn common_len(&self, other: &Path) -> Option<usize> {
let (longer, shorter) = if self.as_vec()?.len() > other.as_vec()?.len() {
(self.as_vec()?, other.as_vec()?)
} else {
(other.as_vec()?, self.as_vec()?)
};
let mut i = 0;
while longer.len() - i > shorter.len() {
i += 1;
}
for (step, (edge1, edge2)) in longer[i..].iter().zip(shorter.iter()).enumerate() {
if edge1 == edge2 {
return Some(shorter.len() - step);
}
}
Some(0)
}
}
#[test]
fn test_visited() {
let p = Path(Some(vec![(5, 4), (4, 3), (3, 2), (2, 1), (1, 0)]));
assert_eq!(p.visited().unwrap(), vec![5, 4, 3, 2, 1, 0]);
let p = Path(Some(vec![(6, 3)]));
assert_eq!(p.visited().unwrap(), vec![6, 3]);
let p = Path(Some(vec![]));
assert_eq!(p.visited().unwrap(), vec![]);
}
#[test]
fn test_common_len() {
let pa = Path(Some(vec![(5, 4), (4, 3), (3, 2), (2, 1), (1, 0)]));
assert_eq!(pa.common_len(&pa), Some(pa.as_vec().unwrap().len()));
let pb = Path(Some(vec![(6, 3), (3, 2), (2, 1), (1, 0)]));
assert_eq!(pa.common_len(&pb), Some(3));
let pa = Path(Some(vec![(5, 4), (4, 3), (3, 2), (2, 1), (1, 0)]));
let pb = Path(Some(vec![(7, 6), (6, 3), (3, 2), (2, 1), (1, 0)]));
assert_eq!(pa.common_len(&pb), Some(3));
}
#[test]
fn test_flatten() {
let p = Path(Some(vec![(5, 4), (4, 3), (3, 2), (2, 1), (1, 0)]));
assert_eq!(p.visited().unwrap(), vec![5, 4, 3, 2, 1, 0]);
let p = Path(Some(vec![(6, 3)]));
assert_eq!(p.visited().unwrap(), vec![6, 3]);
let p = Path(Some(vec![]));
assert_eq!(p.visited().unwrap(), vec![]);
}
pub fn distance(net: &Network, root: usize, target: usize) -> cn::Result<Option<usize>> {
if !net.exists(target) {
return Err(cn::Err::NoSuchNode(target));
}
let mut distance = None;
traverse(net, root, |current, _, depth, _| {
if current == target {
distance = Some(depth);
STOP
} else {
CONTINUE
}
})?;
Ok(distance)
}
pub fn path(net: &Network, root: usize, target: usize) -> cn::Result<Path> {
Ok(path_many(net, root, &[target])?[target].clone())
}
pub fn distance_many(
net: &Network,
root: usize,
targets: &[usize],
) -> cn::Result<cn::VecMap<usize>> {
if targets.is_empty() {
return Err(cn::Err::NoTarget);
}
let mut target_map: cn::VecSet = cn::VecSet::default();
for &t in targets {
if !net.exists(t) {
return Err(cn::Err::NoSuchNode(t));
}
target_map.insert(t);
}
let mut results: cn::VecMap<usize> = cn::VecMap::default();
traverse(net, root, |current, _, depth, _| {
if target_map.remove(current) {
results.insert(current, depth);
}
if target_map.is_empty() {
STOP
} else {
CONTINUE
}
})?;
Ok(results)
}
pub fn reach(net: &Network, root: usize, target: usize) -> cn::Result<bool> {
if !net.exists(target) {
return Err(cn::Err::NoSuchNode(target));
}
let mut reaches = false;
traverse(net, root, |current, _, _, _| {
if current == target {
reaches = true;
STOP
} else {
CONTINUE
}
})?;
Ok(reaches)
}
pub fn reach_many(net: &Network, root: usize, targets: &[usize]) -> cn::Result<cn::VecSet> {
if targets.is_empty() {
return Err(cn::Err::NoTarget);
}
let mut target_map: cn::VecSet = cn::VecSet::default();
for &t in targets {
if !net.exists(t) {
return Err(cn::Err::NoSuchNode(t));
}
target_map.insert(t);
}
let mut results: cn::VecSet = cn::VecSet::default();
traverse(net, root, |current, _, _, _| {
if target_map.remove(current) {
results.insert(current);
}
if target_map.is_empty() {
STOP
} else {
CONTINUE
}
})?;
Ok(results)
}
pub fn path_many(net: &Network, root: usize, targets: &[usize]) -> cn::Result<cn::VecMap<Path>> {
if targets.is_empty() {
return Err(cn::Err::NoTarget);
}
let mut target_map: cn::VecSet = cn::VecSet::default();
for &t in targets {
if !net.exists(t) {
return Err(cn::Err::NoSuchNode(t));
}
target_map.insert(t);
}
let mut discovered: cn::VecMap<Option<usize>> = cn::VecMap::default();
let mut results: cn::VecMap<Path> = cn::VecMap::default();
traverse(net, root, |current, parent, _, _| {
discovered.insert(current, parent);
if target_map.remove(current) {
let mut path = Vec::new();
let mut up_the_tree = parent;
let mut prev = current;
loop {
match up_the_tree {
Some(p) => {
path.push((prev, p));
prev = p;
up_the_tree = discovered[p];
}
None => {
results.insert(current, Path(Some(path)));
break;
}
}
}
}
if target_map.is_empty() {
STOP
} else {
CONTINUE
}
})?;
for not_found in target_map.indexes() {
results.insert(not_found, Path(None));
}
Ok(results)
}
pub fn traverse<F: FnMut(usize, Option<usize>, usize, &cn::VecMap<()>) -> bool>(
net: &Network,
root: usize,
mut on_step: F,
) -> cn::Result<()> {
if !net.exists(root) {
return Err(cn::Err::NoSuchNode(root));
}
let mut seen: cn::VecMap<()> = cn::VecMap::with_capacity(net.size());
seen.insert(root, ());
let mut to_visit: Queue<(usize, Option<usize>, usize)> = Queue::new();
to_visit.push_back((root, None, 0));
while let Some((current, parent, depth)) = to_visit.pop_front() {
if on_step(current, parent, depth, &seen) == STOP {
break;
}
for &i in net.links_of(current).unwrap().keys() {
if seen.insert(i, ()).is_none() {
to_visit.push_back((i, Some(current), depth + 1));
}
}
}
Ok(())
}
pub fn tree(net: &Network, root: usize) -> cn::Result<Network> {
let mut tree = Network::default();
tree.set_model(TREE_MODEL);
traverse(net, root, |current, parent, _, _| {
tree.attach(current).unwrap();
if let Some(parent) = parent {
tree.link(current, parent).unwrap();
}
CONTINUE
})
.unwrap();
Ok(tree)
}
pub fn tree_active(net: &Network, root: usize, targets: &[usize]) -> cn::Result<Network> {
let paths = path_many(net, root, targets)?;
let mut tree = Network::default();
tree.set_model(TREE_MODEL);
tree.attach(root).unwrap();
for (_target, path) in paths.iter() {
if let Some(path) = path.visited() {
if !path.is_empty() {
tree.attach_skip(&path);
for (&prev, &next) in path.iter().zip(path[1..].iter()) {
tree.link(prev, next).unwrap();
}
}
}
}
Ok(tree)
}
pub fn explore(net: &Network, root: usize) -> cn::Result<(cn::VecSet, cn::VecSet)> {
let mut discovered: cn::VecSet = cn::VecSet::default();
traverse(net, root, |current, _, _, _| {
discovered.insert(current);
CONTINUE
})?;
let undiscovered: cn::VecSet = net
.nodes()
.filter(|index| !discovered.contains(*index))
.collect();
Ok((discovered, undiscovered))
}