use {
crate::{
Order,
OutNeighbors,
PredecessorTree,
},
std::collections::VecDeque,
};
type Step = (Option<usize>, usize);
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BfsPred<'a, D> {
digraph: &'a D,
queue: VecDeque<Step>,
visited: Vec<bool>,
}
impl<'a, D> BfsPred<'a, D> {
#[must_use]
pub fn new<T>(digraph: &'a D, sources: T) -> Self
where
D: Order,
T: Iterator<Item = usize> + Clone,
{
let order = digraph.order();
let mut queue = VecDeque::with_capacity(order);
let mut visited = vec![false; order];
let visited_ptr = visited.as_mut_ptr();
for u in sources {
queue.push_back((None, u));
unsafe {
*visited_ptr.add(u) = true;
}
}
Self {
digraph,
queue,
visited,
}
}
#[must_use]
pub fn cycles(&mut self) -> Vec<Vec<usize>>
where
D: Order + OutNeighbors,
{
let order = self.digraph.order();
let mut pred = PredecessorTree::new(order);
let mut cycles = Vec::new();
let pred_ptr = pred.pred.as_mut_ptr();
while let Some((u, v)) = self.next() {
unsafe {
*pred_ptr.add(v) = u;
}
for x in self.digraph.out_neighbors(v) {
if let Some(mut path) = pred.search(v, x) {
path.reverse();
cycles.push(path);
}
}
}
cycles
}
#[must_use]
pub fn predecessors(&mut self) -> PredecessorTree
where
D: Order + OutNeighbors,
{
let order = self.digraph.order();
let mut pred = PredecessorTree::new(order);
let pred_ptr = pred.pred.as_mut_ptr();
for (u, v) in self.by_ref() {
unsafe {
*pred_ptr.add(v) = u;
}
}
pred
}
#[must_use]
pub fn shortest_path<P>(&mut self, is_target: P) -> Option<Vec<usize>>
where
D: Order + OutNeighbors,
P: Fn(usize) -> bool,
{
let order = self.digraph.order();
let mut pred = PredecessorTree::new(order);
let pred_ptr = pred.pred.as_mut_ptr();
for (u, v) in self.by_ref() {
unsafe {
*pred_ptr.add(v) = u;
}
if is_target(v) {
return pred.search_by(v, |_, b| b.is_none()).map(
|mut path| {
path.reverse();
path
},
);
}
}
None
}
}
impl<D> Iterator for BfsPred<'_, D>
where
D: OutNeighbors,
{
type Item = Step;
fn next(&mut self) -> Option<Self::Item> {
let step @ (_, v) = self.queue.pop_front()?;
let visited_ptr = self.visited.as_mut_ptr();
for u in self.digraph.out_neighbors(v) {
let visited_u = unsafe { visited_ptr.add(u) };
unsafe {
if !*visited_u {
*visited_u = true;
self.queue.push_back((Some(v), u));
}
}
}
Some(step)
}
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::repr::adjacency_list::fixture::{
bang_jensen_34,
bang_jensen_94,
bang_jensen_196,
kattis_builddeps,
kattis_cantinaofbabel_1,
kattis_cantinaofbabel_2,
kattis_escapewallmaria_1,
kattis_escapewallmaria_2,
kattis_escapewallmaria_3,
},
std::iter::once,
};
#[test]
fn cycles_bang_jensen_196() {
let digraph = bang_jensen_196();
assert!(BfsPred::new(&digraph, once(0)).cycles().iter().eq(&[
vec![0, 1],
vec![2, 3],
vec![7, 5, 6]
]));
}
#[test]
fn cycles_bang_jensen_34() {
let digraph = bang_jensen_34();
assert!(BfsPred::new(&digraph, once(0)).cycles().iter().eq::<&[Vec<
usize,
>]>(
&[]
));
}
#[test]
fn cycles_bang_jensen_94() {
let digraph = bang_jensen_94();
assert!(BfsPred::new(&digraph, once(0)).cycles().iter().eq::<&[Vec<
usize,
>]>(
&[]
));
}
#[test]
fn cycles_kattis_builddeps() {
let digraph = kattis_builddeps();
assert!(BfsPred::new(&digraph, once(0)).cycles().iter().eq::<&[Vec<
usize,
>]>(
&[]
));
}
#[test]
fn cycles_kattis_cantinaofbabel_1() {
let digraph = kattis_cantinaofbabel_1();
assert!(BfsPred::new(&digraph, once(0)).cycles().iter().eq(&[
vec![0, 1],
vec![1, 2],
vec![4, 3],
vec![3, 7],
vec![5, 6],
vec![11, 9]
]));
}
#[test]
fn cycles_kattis_cantinaofbabel_2() {
let digraph = kattis_cantinaofbabel_2();
assert!(BfsPred::new(&digraph, once(0)).cycles().iter().eq(&[
vec![0, 1],
vec![0, 1, 7, 2],
vec![7, 2],
vec![5, 6],
vec![3, 4]
]));
}
#[test]
fn cycles_kattis_escapewallmaria_1() {
let digraph = kattis_escapewallmaria_1();
assert!(BfsPred::new(&digraph, once(5)).cycles().iter().eq(&[
vec![5, 6],
vec![5, 9],
vec![9, 13]
]));
}
#[test]
fn cycles_kattis_escapewallmaria_2() {
let digraph = kattis_escapewallmaria_2();
assert!(
BfsPred::new(&digraph, once(5))
.cycles()
.iter()
.eq(&[vec![5, 6], vec![5, 9]])
);
}
#[test]
fn cycles_kattis_escapewallmaria_3() {
let digraph = kattis_escapewallmaria_3();
assert!(BfsPred::new(&digraph, once(5)).cycles().iter().eq(&[
vec![5, 1],
vec![5, 6],
vec![5, 9],
vec![1, 2],
vec![9, 13],
vec![13, 12]
]));
}
#[test]
fn iter_bang_jensen_196() {
let digraph = bang_jensen_196();
assert!(BfsPred::new(&digraph, once(0)).eq([
(None, 0),
(Some(0), 1),
(Some(0), 4),
(Some(0), 7),
(Some(1), 2),
(Some(7), 5),
(Some(2), 3),
(Some(5), 6),
]));
}
#[test]
fn iter_bang_jensen_34() {
let digraph = bang_jensen_34();
assert!(BfsPred::new(&digraph, once(0)).eq([(None, 0), (Some(0), 4)]));
}
#[test]
fn iter_bang_jensen_94() {
let digraph = bang_jensen_94();
assert!(BfsPred::new(&digraph, once(0)).eq([
(None, 0),
(Some(0), 1),
(Some(0), 2),
(Some(1), 3),
(Some(2), 4),
(Some(2), 5),
(Some(4), 6)
]));
}
#[test]
fn iter_kattis_builddeps() {
let digraph = kattis_builddeps();
assert!(BfsPred::new(&digraph, once(0)).eq([
(None, 0),
(Some(0), 3),
(Some(0), 4),
(Some(3), 1)
]));
}
#[test]
fn iter_kattis_cantinaofbabel_1() {
let digraph = kattis_cantinaofbabel_1();
assert!(BfsPred::new(&digraph, once(0)).eq([
(None, 0),
(Some(0), 1),
(Some(1), 2),
(Some(1), 4),
(Some(4), 3),
(Some(3), 5),
(Some(3), 7),
(Some(3), 10),
(Some(3), 11),
(Some(5), 6),
(Some(11), 9)
]));
}
#[test]
fn iter_kattis_cantinaofbabel_2() {
let digraph = kattis_cantinaofbabel_2();
assert!(BfsPred::new(&digraph, once(0)).eq([
(None, 0),
(Some(0), 1),
(Some(1), 7),
(Some(7), 2),
(Some(2), 5),
(Some(5), 3),
(Some(5), 6),
(Some(3), 4)
]));
}
#[test]
fn iter_kattis_escapewallmaria_1() {
let digraph = kattis_escapewallmaria_1();
assert!(BfsPred::new(&digraph, once(5)).eq([
(None, 5),
(Some(5), 6),
(Some(5), 9),
(Some(9), 13),
(Some(13), 12)
]));
}
#[test]
fn iter_kattis_escapewallmaria_2() {
let digraph = kattis_escapewallmaria_2();
assert!(BfsPred::new(&digraph, once(5)).eq([
(None, 5),
(Some(5), 6),
(Some(5), 9)
]));
}
#[test]
fn iter_kattis_escapewallmaria_3() {
let digraph = kattis_escapewallmaria_3();
assert!(BfsPred::new(&digraph, once(5)).eq([
(None, 5),
(Some(5), 1),
(Some(5), 6),
(Some(5), 9),
(Some(1), 2),
(Some(9), 13),
(Some(13), 12)
]));
}
#[test]
fn predecessors_bang_jensen_196() {
let digraph = bang_jensen_196();
assert!(
BfsPred::new(&digraph, once(0))
.predecessors()
.into_iter()
.eq([
None,
Some(0),
Some(1),
Some(2),
Some(0),
Some(7),
Some(5),
Some(0)
])
);
}
#[test]
fn predecessors_bang_jensen_34() {
let digraph = bang_jensen_34();
assert!(
BfsPred::new(&digraph, once(0))
.predecessors()
.into_iter()
.eq([None, None, None, None, Some(0), None])
);
}
#[test]
fn predecessors_bang_jensen_94() {
let digraph = bang_jensen_94();
assert!(
BfsPred::new(&digraph, once(0))
.predecessors()
.into_iter()
.eq([
None,
Some(0),
Some(0),
Some(1),
Some(2),
Some(2),
Some(4)
])
);
}
#[test]
fn predecessors_kattis_builddeps() {
let digraph = kattis_builddeps();
assert!(
BfsPred::new(&digraph, once(0))
.predecessors()
.into_iter()
.eq([None, Some(3), None, Some(0), Some(0), None])
);
}
#[test]
fn predecessors_kattis_cantinaofbabel_1() {
let digraph = kattis_cantinaofbabel_1();
assert!(
BfsPred::new(&digraph, once(0))
.predecessors()
.into_iter()
.eq([
None,
Some(0),
Some(1),
Some(4),
Some(1),
Some(3),
Some(5),
Some(3),
None,
Some(11),
Some(3),
Some(3)
])
);
}
#[test]
fn predecessors_kattis_cantinaofbabel_2() {
let digraph = kattis_cantinaofbabel_2();
assert!(
BfsPred::new(&digraph, once(0))
.predecessors()
.into_iter()
.eq([
None,
Some(0),
Some(7),
Some(5),
Some(3),
Some(2),
Some(5),
Some(1),
None,
None,
None,
None
])
);
}
#[test]
fn predecessors_kattis_escapewallmaria_1() {
let digraph = kattis_escapewallmaria_1();
assert!(
BfsPred::new(&digraph, once(5))
.predecessors()
.into_iter()
.eq([
None,
None,
None,
None,
None,
None,
Some(5),
None,
None,
Some(5),
None,
None,
Some(13),
Some(9),
None,
None
])
);
}
#[test]
fn predecessors_kattis_escapewallmaria_2() {
let digraph = kattis_escapewallmaria_2();
assert!(
BfsPred::new(&digraph, once(5))
.predecessors()
.into_iter()
.eq([
None,
None,
None,
None,
None,
None,
Some(5),
None,
None,
Some(5),
None,
None,
None,
None,
None,
None
])
);
}
#[test]
fn predecessors_kattis_escapewallmaria_3() {
let digraph = kattis_escapewallmaria_3();
assert!(
BfsPred::new(&digraph, once(5))
.predecessors()
.into_iter()
.eq([
None,
Some(5),
Some(1),
None,
None,
None,
Some(5),
None,
None,
Some(5),
None,
None,
Some(13),
Some(9),
None,
None
])
);
}
#[test]
fn shortest_path_bang_jensen_196() {
let digraph = bang_jensen_196();
assert!(
BfsPred::new(&digraph, once(0))
.shortest_path(|v| v == 6)
.unwrap()
.eq(&[0, 7, 5, 6])
);
}
#[test]
fn shortest_path_bang_jensen_34() {
let digraph = bang_jensen_34();
assert!(
BfsPred::new(&digraph, once(0))
.shortest_path(|v| v == 4)
.unwrap()
.eq(&[0, 4])
);
}
#[test]
fn shortest_path_bang_jensen_94() {
let digraph = bang_jensen_94();
assert!(
BfsPred::new(&digraph, once(0))
.shortest_path(|v| v == 6)
.unwrap()
.eq(&[0, 2, 4, 6])
);
}
#[test]
fn shortest_path_kattis_builddeps() {
let digraph = kattis_builddeps();
assert!(
BfsPred::new(&digraph, once(0))
.shortest_path(|v| v == 1)
.unwrap()
.eq(&[0, 3, 1])
);
}
#[test]
fn shortest_path_kattis_cantinaofbabel_1() {
let digraph = kattis_cantinaofbabel_1();
assert!(
BfsPred::new(&digraph, once(0))
.shortest_path(|v| v == 9)
.unwrap()
.eq(&[0, 1, 4, 3, 11, 9])
);
}
#[test]
fn shortest_path_kattis_cantinaofbabel_2() {
let digraph = kattis_cantinaofbabel_2();
assert!(
BfsPred::new(&digraph, once(0))
.shortest_path(|v| v == 7)
.unwrap()
.eq(&[0, 1, 7])
);
}
#[test]
fn shortest_path_kattis_escapewallmaria_1() {
let digraph = kattis_escapewallmaria_1();
assert!(
BfsPred::new(&digraph, once(5))
.shortest_path(
|v| [0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15].contains(&v)
)
.unwrap()
.eq(&[5, 9, 13])
);
}
#[test]
fn shortest_path_kattis_escapewallmaria_2() {
let digraph = kattis_escapewallmaria_2();
assert!(
BfsPred::new(&digraph, once(5))
.shortest_path(
|v| [0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15].contains(&v)
)
.is_none()
);
}
#[test]
fn shortest_path_kattis_escapewallmaria_3() {
let digraph = kattis_escapewallmaria_3();
assert!(
BfsPred::new(&digraph, once(5))
.shortest_path(
|v| [0, 1, 2, 3, 4, 7, 8, 11, 12, 13, 14, 15].contains(&v)
)
.unwrap()
.eq(&[5, 1])
);
}
}