use genawaiter::sync::{Gen, GenBoxed};
#[inline]
pub const fn stirling2nd(n: usize, k: usize) -> usize {
if k >= n || k <= 1 {
1
} else {
stirling2nd_recur(n, k)
}
}
#[inline]
const fn stirling2nd_recur(n: usize, k: usize) -> usize {
let n = n - 1;
let a = if k == 2 {
1
} else {
stirling2nd_recur(n, k - 1)
};
let b = if k == n { 1 } else { stirling2nd_recur(n, k) };
a + k * b
}
pub fn set_partition_gen(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
if !(k > 1 && k < n) {
return;
}
if k % 2 == 0 {
for (i, j) in gen0_even(n, k) {
co.yield_((i, j)).await;
}
} else {
for (i, j) in gen0_odd(n, k) {
co.yield_((i, j)).await;
}
}
})
}
fn gen0_even(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| {
async move {
if k > 2 {
for (i, j) in gen0_odd(n - 1, k - 1) {
co.yield_((i, j)).await;
} }
co.yield_((n - 1, k - 1)).await;
if k < n - 1 {
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
} co.yield_((n, k - 2)).await;
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
} for i in (1..k - 2).step_by(2).rev() {
co.yield_((n, i)).await;
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
} co.yield_((n, i - 1)).await;
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
} }
} else {
co.yield_((n, k - 2)).await;
for i in (1..k - 2).step_by(2).rev() {
co.yield_((n, i)).await;
co.yield_((n, i - 1)).await;
}
}
}
})
}
fn neg0_even(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| {
async move {
if k < n - 1 {
for i in (1..k - 2).step_by(2) {
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
} co.yield_((n, i)).await;
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
} co.yield_((n, i + 1)).await;
}
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
} co.yield_((n, k - 1)).await;
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
} } else {
for i in (1..k - 2).step_by(2) {
co.yield_((n, i)).await;
co.yield_((n, i + 1)).await;
}
co.yield_((n, k - 1)).await;
}
co.yield_((n - 1, 0)).await;
if k > 3 {
for (i, j) in neg0_odd(n - 1, k - 1) {
co.yield_((i, j)).await;
} }
}
})
}
fn gen1_even(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
if k > 3 {
for (i, j) in gen1_odd(n - 1, k - 1) {
co.yield_((i, j)).await;
}
}
co.yield_((k, k - 1)).await;
if k < n - 1 {
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, k - 2)).await;
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
}
for i in (1..k - 2).step_by(2).rev() {
co.yield_((n, i)).await;
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i - 1)).await;
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
}
}
} else {
co.yield_((n, k - 2)).await;
for i in (1..k - 2).step_by(2).rev() {
co.yield_((n, i)).await;
co.yield_((n, i - 1)).await;
}
}
})
}
fn neg1_even(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
if k < n - 1 {
for i in (1..k - 2).step_by(2) {
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i)).await;
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i + 1)).await;
}
for (i, j) in neg1_even(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, k - 1)).await;
for (i, j) in gen1_even(n - 1, k) {
co.yield_((i, j)).await;
}
} else {
for i in (1..k - 2).step_by(2) {
co.yield_((n, i)).await;
co.yield_((n, i + 1)).await;
}
co.yield_((n, k - 1)).await;
}
co.yield_((k, 0)).await;
if k > 3 {
for (i, j) in neg1_odd(n - 1, k - 1) {
co.yield_((i, j)).await;
}
}
})
}
fn gen0_odd(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
for (i, j) in gen1_even(n - 1, k - 1) {
co.yield_((i, j)).await;
}
co.yield_((k, k - 1)).await;
if k < n - 1 {
for (i, j) in neg1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
for i in (1..k - 1).step_by(2).rev() {
co.yield_((n, i)).await;
for (i, j) in gen1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i - 1)).await;
for (i, j) in neg1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
}
} else {
for i in (1..k - 1).step_by(2).rev() {
co.yield_((n, i)).await;
co.yield_((n, i - 1)).await;
}
}
})
}
fn neg0_odd(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
if k < n - 1 {
for i in (1..k - 1).step_by(2) {
for (i, j) in gen1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i)).await;
for (i, j) in neg1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i + 1)).await;
}
for (i, j) in gen1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
} else {
for i in (1..k - 1).step_by(2) {
co.yield_((n, i)).await;
co.yield_((n, i + 1)).await;
}
}
co.yield_((k, 0)).await;
for (i, j) in neg1_even(n - 1, k - 1) {
co.yield_((i, j)).await;
}
})
}
fn gen1_odd(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
for (i, j) in gen0_even(n - 1, k - 1) {
co.yield_((i, j)).await;
}
co.yield_((n - 1, k - 1)).await;
if k < n - 1 {
for (i, j) in gen1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
for i in (1..k - 1).step_by(2).rev() {
co.yield_((n, i)).await;
for (i, j) in neg1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i - 1)).await;
for (i, j) in gen1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
}
} else {
for i in (1..k - 1).step_by(2).rev() {
co.yield_((n, i)).await;
co.yield_((n, i - 1)).await;
}
}
})
}
fn neg1_odd(n: usize, k: usize) -> GenBoxed<(usize, usize)> {
Gen::new_boxed(|co| async move {
if k < n - 1 {
for i in (1..k - 1).step_by(2) {
for (i, j) in neg1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i)).await;
for (i, j) in gen1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
co.yield_((n, i + 1)).await;
}
for (i, j) in neg1_odd(n - 1, k) {
co.yield_((i, j)).await;
}
} else {
for i in (1..k - 1).step_by(2) {
co.yield_((n, i)).await;
co.yield_((n, i + 1)).await;
}
}
co.yield_((n - 1, 0)).await;
for (i, j) in neg0_even(n - 1, k - 1) {
co.yield_((i, j)).await;
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_set_partition_odd_odd() {
const N: usize = 11;
const K: usize = 5;
let mut b = [0; N + 1];
let offset = N - K + 1;
for i in 1..K {
b[offset + i] = i;
}
let mut cnt = 1;
for (x, y) in set_partition_gen(N, K) {
let old = b[x];
b[x] = y;
println!("Move {x} from Block {old} to Block {y}");
cnt += 1;
}
assert_eq!(cnt, stirling2nd(N, K));
}
#[test]
fn test_set_partition_even_odd() {
const N: usize = 10;
const K: usize = 5;
let mut b = [0; N + 1];
let offset = N - K + 1;
for i in 1..K {
b[offset + i] = i;
}
let mut cnt = 1;
for (x, y) in set_partition_gen(N, K) {
let old = b[x];
b[x] = y;
println!("Move {x} from Block {old} to Block {y}");
cnt += 1;
}
assert_eq!(cnt, stirling2nd(N, K));
}
#[test]
fn test_set_partition_odd_even() {
const N: usize = 11;
const K: usize = 6;
let mut b = [0; N + 1];
let offset = N - K + 1;
for i in 1..K {
b[offset + i] = i;
}
let mut cnt = 1;
for (x, y) in set_partition_gen(N, K) {
let old = b[x];
b[x] = y;
println!("Move {x} from Block {old} to Block {y}");
cnt += 1;
}
assert_eq!(cnt, stirling2nd(N, K));
}
#[test]
fn test_set_partition_even_even() {
const N: usize = 10;
const K: usize = 6;
let mut b = [0; N + 1];
let offset = N - K + 1;
for i in 1..K {
b[offset + i] = i;
}
let mut cnt = 1;
for (x, y) in set_partition_gen(N, K) {
let old = b[x];
b[x] = y;
println!("Move {x} from Block {old} to Block {y}");
cnt += 1;
}
assert_eq!(cnt, stirling2nd(N, K));
}
#[test]
fn test_set_partition_special() {
const N: usize = 6;
const K: usize = 6;
let mut cnt = 1;
for (_x, _y) in set_partition_gen(N, K) {
cnt += 1;
}
assert_eq!(cnt, stirling2nd(N, K));
}
}