#[derive(Debug, Clone)]
pub struct SuccinctPermutation {
n: usize,
forward: Vec<u32>,
inverse: Vec<u32>,
}
impl SuccinctPermutation {
#[must_use]
pub fn new(permutation: &[usize]) -> Self {
let n = permutation.len();
if n == 0 {
return Self {
n: 0,
forward: Vec::new(),
inverse: Vec::new(),
};
}
let forward: Vec<u32> = permutation.iter().map(|&x| x as u32).collect();
let mut inverse = vec![0u32; n];
for (i, &target) in permutation.iter().enumerate() {
inverse[target] = i as u32;
}
Self {
n,
forward,
inverse,
}
}
#[must_use]
pub fn len(&self) -> usize {
self.n
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.n == 0
}
#[must_use]
pub fn apply(&self, index: usize) -> Option<usize> {
if index >= self.n {
return None;
}
Some(self.forward[index] as usize)
}
#[must_use]
pub fn apply_inverse(&self, target: usize) -> Option<usize> {
if target >= self.n {
return None;
}
Some(self.inverse[target] as usize)
}
#[must_use]
pub fn size_bytes(&self) -> usize {
let base = std::mem::size_of::<Self>();
let forward_bytes = self.forward.capacity() * std::mem::size_of::<u32>();
let inverse_bytes = self.inverse.capacity() * std::mem::size_of::<u32>();
base + forward_bytes + inverse_bytes
}
}
impl Default for SuccinctPermutation {
fn default() -> Self {
Self {
n: 0,
forward: Vec::new(),
inverse: Vec::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty() {
let perm = SuccinctPermutation::new(&[]);
assert!(perm.is_empty());
assert_eq!(perm.apply(0), None);
assert_eq!(perm.apply_inverse(0), None);
}
#[test]
fn test_single() {
let perm = SuccinctPermutation::new(&[0]);
assert_eq!(perm.len(), 1);
assert_eq!(perm.apply(0), Some(0));
assert_eq!(perm.apply_inverse(0), Some(0));
}
#[test]
fn test_identity() {
let perm = SuccinctPermutation::new(&[0, 1, 2, 3, 4]);
for i in 0..5 {
assert_eq!(perm.apply(i), Some(i));
assert_eq!(perm.apply_inverse(i), Some(i));
}
}
#[test]
fn test_reverse() {
let perm = SuccinctPermutation::new(&[4, 3, 2, 1, 0]);
assert_eq!(perm.apply(0), Some(4));
assert_eq!(perm.apply(1), Some(3));
assert_eq!(perm.apply(2), Some(2));
assert_eq!(perm.apply(3), Some(1));
assert_eq!(perm.apply(4), Some(0));
assert_eq!(perm.apply_inverse(4), Some(0));
assert_eq!(perm.apply_inverse(3), Some(1));
assert_eq!(perm.apply_inverse(2), Some(2));
assert_eq!(perm.apply_inverse(1), Some(3));
assert_eq!(perm.apply_inverse(0), Some(4));
}
#[test]
fn test_cyclic() {
let perm = SuccinctPermutation::new(&[1, 2, 3, 0]);
assert_eq!(perm.apply(0), Some(1));
assert_eq!(perm.apply(1), Some(2));
assert_eq!(perm.apply(2), Some(3));
assert_eq!(perm.apply(3), Some(0));
assert_eq!(perm.apply_inverse(1), Some(0));
assert_eq!(perm.apply_inverse(2), Some(1));
assert_eq!(perm.apply_inverse(3), Some(2));
assert_eq!(perm.apply_inverse(0), Some(3));
}
#[test]
fn test_random_permutation() {
let perm_array = [3, 0, 5, 2, 7, 1, 4, 6];
let perm = SuccinctPermutation::new(&perm_array);
for (i, &expected) in perm_array.iter().enumerate() {
assert_eq!(perm.apply(i), Some(expected), "apply({}) failed", i);
}
for target in 0..8 {
let source = perm.apply_inverse(target);
assert!(source.is_some(), "apply_inverse({}) failed", target);
assert_eq!(
perm.apply(source.unwrap()),
Some(target),
"roundtrip failed for target {}",
target
);
}
}
#[test]
fn test_large_permutation() {
let n = 1000;
let mut perm_array: Vec<usize> = (0..n).collect();
for chunk in perm_array.chunks_mut(10) {
chunk.reverse();
}
let perm = SuccinctPermutation::new(&perm_array);
for (i, &expected) in perm_array.iter().enumerate() {
assert_eq!(perm.apply(i), Some(expected));
}
for target in (0..n).step_by(37) {
let source = perm.apply_inverse(target).unwrap();
assert_eq!(perm.apply(source), Some(target));
}
}
#[test]
fn test_out_of_bounds() {
let perm = SuccinctPermutation::new(&[2, 0, 1]);
assert_eq!(perm.apply(3), None);
assert_eq!(perm.apply(100), None);
assert_eq!(perm.apply_inverse(3), None);
assert_eq!(perm.apply_inverse(100), None);
}
#[test]
fn test_size_bytes() {
let perm = SuccinctPermutation::new(&[0, 1, 2, 3, 4, 5, 6, 7]);
let size = perm.size_bytes();
assert!(size < 1000);
}
}