#[must_use]
pub fn reduction_count(n: u64, k: u64) -> u32 {
assert!(k >= 2, "log arity k must be >= 2");
let mut count = 0;
let mut m = (n as u128) + 1; let k_u128 = k as u128;
while m % k_u128 == 0 {
count += 1;
m /= k_u128;
}
count
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reduction_count_k2() {
let expected = vec![
0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0,
1, 0, 5,
];
for (n, &exp) in expected.iter().enumerate() {
assert_eq!(reduction_count(n as u64, 2), exp, "failed for k=2, n={}", n);
}
}
#[test]
fn test_reduction_count_k3() {
let expected = vec![
0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 1, 0, 0, 1, 0, 0, 2, 0, 0, 1, 0, 0, 1, 0, 0, 3, 0, 0,
1, 0, 0,
];
for (n, &exp) in expected.iter().enumerate() {
assert_eq!(reduction_count(n as u64, 3), exp, "failed for k=3, n={}", n);
}
}
#[test]
fn test_reduction_count_k4() {
let expected = vec![
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 2,
];
for (n, &exp) in expected.iter().enumerate() {
assert_eq!(reduction_count(n as u64, 4), exp, "failed for k=4, n={}", n);
}
}
#[test]
#[should_panic(expected = "log arity k must be >= 2")]
fn test_reduction_count_invalid_k() {
let _ = reduction_count(0, 1);
}
#[test]
fn lean_guard_parity() {
use spine::{SkeletonStep, frontier_for_size};
use crate::mountain::mountain_skeleton;
let step = |position: usize, sibling_count: usize| SkeletonStep {
position,
sibling_count,
};
assert_eq!(frontier_for_size(5, 2), vec![(0u64, 2u32), (4, 0)]);
assert_eq!(frontier_for_size(5, 3), vec![(0, 1), (3, 0), (4, 0)]);
assert_eq!(frontier_for_size(0, 2), Vec::<(u64, u32)>::new());
let rc2: Vec<u32> = (0..8).map(|n| reduction_count(n, 2)).collect();
assert_eq!(rc2, vec![0, 1, 0, 2, 0, 1, 0, 3]);
let rc3: Vec<u32> = (0..9).map(|n| reduction_count(n, 3)).collect();
assert_eq!(rc3, vec![0, 0, 1, 0, 0, 1, 0, 0, 2]);
assert_eq!(mountain_skeleton(2, 1, 0), Some(vec![]));
assert_eq!(mountain_skeleton(2, 5, 4), Some(vec![step(1, 1)]));
assert_eq!(
mountain_skeleton(2, 4, 1),
Some(vec![step(1, 1), step(0, 1)])
);
assert_eq!(mountain_skeleton(3, 4, 3), Some(vec![step(1, 1)]));
assert_eq!(mountain_skeleton(2, 4, 4), None); assert_eq!(mountain_skeleton(1, 4, 0), None); }
}