From 61c4729667cd441605d486b5e79b95388aa53330 Mon Sep 17 00:00:00 2001 From: ia7ck <23146842+ia7ck@users.noreply.github.com> Date: Sat, 7 Feb 2026 23:55:38 +0900 Subject: [PATCH] union_find proptest --- libs/union_find/Cargo.toml | 1 + libs/union_find/src/lib.rs | 82 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/libs/union_find/Cargo.toml b/libs/union_find/Cargo.toml index eabb0166..5997e263 100644 --- a/libs/union_find/Cargo.toml +++ b/libs/union_find/Cargo.toml @@ -11,3 +11,4 @@ license = "CC0-1.0" [dev-dependencies] proconio = {version = "0.4.5", features = ["derive"] } +proptest = "1.9.0" diff --git a/libs/union_find/src/lib.rs b/libs/union_find/src/lib.rs index fad25e8c..03123508 100644 --- a/libs/union_find/src/lib.rs +++ b/libs/union_find/src/lib.rs @@ -186,3 +186,85 @@ impl UnionFind { self.groups } } + +#[cfg(test)] +mod tests { + use ::proptest::{collection, prelude::*}; + + use super::*; + + #[test] + fn test_basic() { + // 0 -- 1 -- 2 + // 3 -- 4 + let mut uf = UnionFind::new(6); + assert!(uf.unite(0, 1).is_some()); + assert!(uf.unite(1, 2).is_some()); + assert!(uf.unite(3, 4).is_some()); + + assert!(uf.same(0, 1)); + assert!(uf.same(1, 2)); + assert!(uf.same(0, 2)); + assert!(uf.same(3, 4)); + assert!(!uf.same(0, 3)); + + assert_eq!(uf.size(0), 3); + assert_eq!(uf.size(3), 2); + assert_eq!(uf.size(5), 1); + assert_eq!(uf.count_groups(), 3); + } + + prop_compose! { + fn uf_operations()(n in 1_usize..=20) + (n in Just(n), + operations in collection::vec((0..n, 0..n), 0..=50)) + -> (usize, Vec<(usize, usize)>) { + (n, operations) + } + } + + proptest! { + #[test] + fn unite_makes_same((n, operations) in uf_operations()) { + let mut uf = UnionFind::new(n); + for (i, j) in operations { + uf.unite(i, j); + prop_assert!(uf.same(i, j)); + } + } + + #[test] + fn same_is_transitive((n, operations) in uf_operations()) { + let mut uf = UnionFind::new(n); + for (i, j) in operations { + uf.unite(i, j); + } + + for i in 0..n { + for j in 0..n { + for k in 0..n { + if uf.same(i, j) && uf.same(j, k) { + prop_assert!(uf.same(i, k)); + } + } + } + } + } + + #[test] + fn size_sum_equals_n((n, operations) in uf_operations()) { + let mut uf = UnionFind::new(n); + for (i, j) in operations { + uf.unite(i, j); + } + + let mut roots = std::collections::HashSet::new(); + for i in 0..n { + roots.insert(uf.find(i)); + } + + let total_size: usize = roots.iter().map(|&r| uf.size(r)).sum(); + prop_assert_eq!(total_size, n); + } + } +}