use crate::flowcutter::separator::*;
use crate::tests::td_fixture::NamedGraph;
use std::time::Duration;
#[test]
fn a_positive_submillisecond_timeout_stays_enabled() {
assert_eq!(super::super::duration_ms(Duration::from_nanos(1)), 1);
}
#[test]
fn separator_on_path() {
let n = 10;
let edges: Vec<(u32, u32)> = (0..9).map(|i| (i, i + 1)).collect();
let sep = compute_vertices(n, &edges, 100_000, 5, 0).expect("path separator");
assert!(!sep.is_empty());
assert!(sep.len() <= 3, "path separator too large: {:?}", sep);
}
#[test]
fn separator_on_cycle() {
let n = 12;
let mut edges: Vec<(u32, u32)> = (0..11).map(|i| (i, i + 1)).collect();
edges.push((11, 0));
let sep = compute_vertices(n, &edges, 100_000, 5, 0).expect("cycle separator");
assert!(!sep.is_empty());
assert!(sep.len() <= 4, "cycle separator too large: {:?}", sep);
}
#[test]
fn separator_on_disconnected_returns_none() {
let n = 6;
let edges = vec![(0, 1), (1, 2), (0, 2), (3, 4), (4, 5), (3, 5)];
let sep = compute_vertices(n, &edges, 10_000, 3, 0);
assert!(
sep.is_none(),
"disconnected graph should report no separator"
);
}
#[test]
fn separator_on_clique_is_large() {
let n = 5;
let mut edges = Vec::new();
for i in 0..5 {
for j in (i + 1)..5 {
edges.push((i, j));
}
}
let sep = compute_vertices(n, &edges, 100_000, 5, 0);
if let Some(sep) = sep {
assert!(
sep.len() >= 4 || sep.is_empty(),
"K5 separator too small: {:?}",
sep
);
}
}
#[test]
fn separator_does_not_panic_on_tree() {
let n = 7;
let edges = vec![(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)];
let sep = compute_vertices(n, &edges, 100_000, 5, 0);
assert!(sep.is_some(), "tree should yield a separator");
}
#[test]
fn separator_finds_articulation_point() {
let n = 5;
let edges = vec![
(0, 1),
(0, 2),
(1, 2), (0, 3),
(0, 4),
(3, 4), ];
let sep = compute_vertices(n, &edges, 100_000, 30, 0).expect("must find sep");
assert_eq!(sep, vec![0], "expected {{0}}, got {:?}", sep);
}
#[test]
fn separator_seed2_articulation_at_16() {
let n = 30;
let edges = vec![
(0, 9),
(1, 2),
(2, 26),
(1, 25),
(26, 27),
(15, 29),
(5, 19),
(23, 29),
(5, 9),
(10, 16),
(22, 25),
(7, 15),
(6, 25),
(9, 15),
(12, 16),
(15, 21),
(3, 4),
(4, 16),
(9, 11),
(3, 11),
(3, 14),
(16, 24),
(0, 13),
(9, 14),
(7, 24),
(5, 8),
(13, 29),
(13, 21),
(2, 11),
(9, 20),
(6, 29),
(24, 27),
(21, 25),
(11, 22),
(10, 18),
(10, 15),
(20, 28),
(10, 17),
(16, 23),
(3, 18),
(1, 29),
(0, 15),
(3, 19),
(20, 23),
(6, 19),
(11, 20),
(17, 26),
(10, 28),
(2, 18),
(9, 26),
(2, 27),
(4, 23),
(19, 21),
(3, 24),
];
let sep = compute_vertices(n, &edges, 500_000, 200, 0).expect("must find sep");
assert!(sep.len() <= 3, "seed=2 sep too big: {:?}", sep);
}
#[test]
fn separator_finds_articulation_in_larger() {
let n = 13;
let mut edges = Vec::new();
for i in 0..4u32 {
for j in (i + 1)..4u32 {
edges.push((i, j));
}
}
for i in [0u32, 4, 5, 6] {
for j in [0u32, 4, 5, 6].iter().filter(|&&x| x > i).copied() {
edges.push((i, j));
}
}
for i in [0u32, 7, 8, 9] {
for j in [0u32, 7, 8, 9].iter().filter(|&&x| x > i).copied() {
edges.push((i, j));
}
}
for i in [0u32, 10, 11, 12] {
for j in [0u32, 10, 11, 12].iter().filter(|&&x| x > i).copied() {
edges.push((i, j));
}
}
let sep = compute_vertices(n, &edges, 200_000, 30, 0).expect("must find sep");
assert_eq!(sep, vec![0], "expected {{0}}, got {:?}", sep);
}
#[test]
fn a_separator_leaves_no_edge_between_its_two_sides() {
let shapes: &[NamedGraph] = &[
(
"a path",
10,
&[
(0, 1),
(1, 2),
(2, 3),
(3, 4),
(4, 5),
(5, 6),
(6, 7),
(7, 8),
(8, 9),
],
),
(
"a cycle",
8,
&[
(0, 1),
(1, 2),
(2, 3),
(3, 4),
(4, 5),
(5, 6),
(6, 7),
(7, 0),
],
),
(
"a grid",
9,
&[
(0, 1),
(1, 2),
(3, 4),
(4, 5),
(6, 7),
(7, 8),
(0, 3),
(3, 6),
(1, 4),
(4, 7),
(2, 5),
(5, 8),
],
),
];
for &(shape, n, edges) in shapes {
let n = n as usize;
let graph = crate::Graph::new(n as u32, edges.iter().copied());
let result = find(&graph, Budget::new(10_000, 3))
.unwrap_or_else(|error| panic!("{shape}: {error}"))
.unwrap_or_else(|| panic!("{shape} must have a separator"));
let mut side = vec![u8::MAX; n];
for &v in result.side_a() {
assert_eq!(
side[v as usize],
u8::MAX,
"{shape}: vertex {v} placed twice"
);
side[v as usize] = 0;
}
for &v in result.side_b() {
assert_eq!(
side[v as usize],
u8::MAX,
"{shape}: vertex {v} placed twice"
);
side[v as usize] = 1;
}
for &v in result.vertices() {
assert_eq!(
side[v as usize],
u8::MAX,
"{shape}: vertex {v} placed twice"
);
side[v as usize] = 2;
}
assert!(
side.iter().all(|&s| s != u8::MAX),
"{shape}: the two sides and the separator must cover every vertex",
);
for &(u, v) in edges {
let (a, b) = (side[u as usize], side[v as usize]);
assert!(
!(a < 2 && b < 2 && a != b),
"{shape}: edge ({u}, {v}) crosses from one side to the other",
);
}
}
}