use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PermutationError {
InvalidPermutation(String),
LengthMismatch { expected: usize, got: usize },
}
impl fmt::Display for PermutationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidPermutation(msg) => write!(f, "invalid permutation: {msg}"),
Self::LengthMismatch { expected, got } => {
write!(f, "length mismatch: expected {expected}, got {got}")
}
}
}
}
impl std::error::Error for PermutationError {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Permutation {
perm: Vec<usize>,
}
impl Permutation {
pub fn new(perm: Vec<usize>) -> Result<Self, PermutationError> {
let n = perm.len();
let mut seen = vec![false; n];
for &v in &perm {
if v >= n {
return Err(PermutationError::InvalidPermutation(format!(
"element {v} is out of range for permutation of length {n}"
)));
}
if seen[v] {
return Err(PermutationError::InvalidPermutation(format!(
"element {v} appears more than once"
)));
}
seen[v] = true;
}
Ok(Self { perm })
}
#[inline]
pub fn len(&self) -> usize {
self.perm.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.perm.is_empty()
}
#[inline]
pub fn as_slice(&self) -> &[usize] {
&self.perm
}
#[inline]
pub fn into_vec(self) -> Vec<usize> {
self.perm
}
#[inline]
pub fn image_of(&self, i: usize) -> Option<usize> {
self.perm.get(i).copied()
}
pub fn apply_to<T: Clone>(&self, slice: &[T]) -> Result<Vec<T>, PermutationError> {
let n = self.perm.len();
if slice.len() != n {
return Err(PermutationError::LengthMismatch {
expected: n,
got: slice.len(),
});
}
let mut out = slice.to_vec();
for (i, &dest) in self.perm.iter().enumerate() {
out[dest] = slice[i].clone();
}
Ok(out)
}
pub fn apply_inplace<T: Clone>(&self, slice: &mut Vec<T>) -> Result<(), PermutationError> {
let new_vec = self.apply_to(slice.as_slice())?;
*slice = new_vec;
Ok(())
}
pub fn inverse(&self) -> Self {
let n = self.perm.len();
let mut inv = vec![0usize; n];
for (i, &dest) in self.perm.iter().enumerate() {
inv[dest] = i;
}
Self { perm: inv }
}
pub fn parity(&self) -> i64 {
let n = self.perm.len();
let mut visited = vec![false; n];
let mut parity = 1i64;
for start in 0..n {
if visited[start] {
continue;
}
let mut cycle_len = 0usize;
let mut cur = start;
while !visited[cur] {
visited[cur] = true;
cur = self.perm[cur];
cycle_len += 1;
}
if cycle_len % 2 == 0 {
parity = -parity;
}
}
parity
}
pub fn compose(&self, other: &Permutation) -> Result<Permutation, PermutationError> {
let n = self.perm.len();
if other.perm.len() != n {
return Err(PermutationError::LengthMismatch {
expected: n,
got: other.perm.len(),
});
}
let perm: Vec<usize> = self.perm.iter().map(|&i| other.perm[i]).collect();
Ok(Permutation { perm })
}
pub fn next_permutation(&mut self) -> bool {
next_permutation_slice(&mut self.perm)
}
pub fn inversion_count(&self) -> usize {
let n = self.perm.len();
let mut count = 0usize;
for i in 0..n {
for j in (i + 1)..n {
if self.perm[i] > self.perm[j] {
count += 1;
}
}
}
count
}
pub fn cycle_decomposition(&self) -> Vec<Vec<usize>> {
let n = self.perm.len();
let mut visited = vec![false; n];
let mut cycles = Vec::new();
for start in 0..n {
if visited[start] {
continue;
}
let mut cycle = Vec::new();
let mut cur = start;
while !visited[cur] {
visited[cur] = true;
cycle.push(cur);
cur = self.perm[cur];
}
cycles.push(cycle);
}
cycles
}
}
impl fmt::Display for Permutation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
for (i, v) in self.perm.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{v}")?;
}
write!(f, "]")
}
}
pub fn identity_permutation(n: usize) -> Permutation {
Permutation {
perm: (0..n).collect(),
}
}
pub fn random_permutation<R: rand::Rng>(n: usize, rng: &mut R) -> Permutation {
let mut perm: Vec<usize> = (0..n).collect();
for i in (1..n).rev() {
let j = rng.gen_range(0..=i);
perm.swap(i, j);
}
Permutation { perm }
}
pub fn apply_permutation<T: Clone>(
data: &[T],
perm: &[usize],
) -> Result<Vec<T>, PermutationError> {
let n = perm.len();
if data.len() != n {
return Err(PermutationError::LengthMismatch {
expected: n,
got: data.len(),
});
}
let mut out = data.to_vec();
for (i, &dest) in perm.iter().enumerate() {
out[dest] = data[i].clone();
}
Ok(out)
}
pub fn inverse_permutation(perm: &[usize]) -> Result<Vec<usize>, PermutationError> {
let n = perm.len();
let mut inv = vec![0usize; n];
let mut seen = vec![false; n];
for (i, &v) in perm.iter().enumerate() {
if v >= n {
return Err(PermutationError::InvalidPermutation(format!(
"element {v} is out of range for length {n}"
)));
}
if seen[v] {
return Err(PermutationError::InvalidPermutation(format!(
"element {v} appears more than once"
)));
}
seen[v] = true;
inv[v] = i;
}
Ok(inv)
}
pub fn permutation_parity(perm: &[usize]) -> Result<i64, PermutationError> {
let p = Permutation::new(perm.to_vec())?;
Ok(p.parity())
}
pub fn next_permutation_slice(perm: &mut [usize]) -> bool {
let n = perm.len();
if n < 2 {
return false;
}
let mut i = n - 1;
loop {
if i == 0 {
perm.reverse();
return false;
}
i -= 1;
if perm[i] < perm[i + 1] {
break;
}
}
let mut j = n - 1;
while perm[j] <= perm[i] {
j -= 1;
}
perm.swap(i, j);
perm[i + 1..].reverse();
true
}
pub struct PermutationIterator {
current: Vec<usize>,
first: bool,
done: bool,
}
impl PermutationIterator {
pub fn new(n: usize) -> Self {
Self {
current: (0..n).collect(),
first: true,
done: n == 0,
}
}
}
impl Iterator for PermutationIterator {
type Item = Permutation;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
if self.first {
self.first = false;
return Some(Permutation {
perm: self.current.clone(),
});
}
let advanced = next_permutation_slice(&mut self.current);
if !advanced {
self.done = true;
return None;
}
Some(Permutation {
perm: self.current.clone(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_identity_permutation() {
let p = identity_permutation(4);
assert_eq!(p.as_slice(), &[0, 1, 2, 3]);
}
#[test]
fn test_apply_permutation() {
let perm = [1usize, 2, 0];
let data = [10, 20, 30];
let out = apply_permutation(&data, &perm).expect("apply should succeed");
assert_eq!(out, vec![30, 10, 20]);
}
#[test]
fn test_inverse_permutation() {
let perm = vec![1usize, 2, 0, 3];
let inv = inverse_permutation(&perm).expect("inverse should succeed");
let data = vec![5usize, 6, 7, 8];
let out1 = apply_permutation(&data, &perm).expect("apply");
let out2 = apply_permutation(&out1, &inv).expect("apply inv");
assert_eq!(out2, data);
}
#[test]
fn test_parity_identity() {
let parity = permutation_parity(&[0usize, 1, 2, 3]).expect("parity");
assert_eq!(parity, 1);
}
#[test]
fn test_parity_transposition() {
let parity = permutation_parity(&[1usize, 0, 2, 3]).expect("parity");
assert_eq!(parity, -1);
}
#[test]
fn test_parity_three_cycle() {
let parity = permutation_parity(&[1usize, 2, 0]).expect("parity");
assert_eq!(parity, 1);
}
#[test]
fn test_next_permutation() {
let mut perm = vec![0usize, 1, 2];
let advanced = next_permutation_slice(&mut perm);
assert!(advanced);
assert_eq!(perm, vec![0, 2, 1]);
}
#[test]
fn test_permutation_iterator_count() {
let count = PermutationIterator::new(4).count();
assert_eq!(count, 24); }
#[test]
fn test_permutation_iterator_order() {
let perms: Vec<Vec<usize>> = PermutationIterator::new(3)
.map(|p| p.into_vec())
.collect();
assert_eq!(perms[0], vec![0, 1, 2]);
assert_eq!(perms[1], vec![0, 2, 1]);
assert_eq!(perms[2], vec![1, 0, 2]);
assert_eq!(perms[5], vec![2, 1, 0]);
}
#[test]
fn test_cycle_decomposition() {
let p = Permutation::new(vec![1, 2, 0, 3]).expect("valid");
let cycles = p.cycle_decomposition();
assert_eq!(cycles.len(), 2);
}
#[test]
fn test_invalid_permutation() {
let result = Permutation::new(vec![0, 0, 2]);
assert!(result.is_err());
}
#[test]
fn test_random_permutation() {
use rand::SeedableRng;
let mut rng = rand::rngs::SmallRng::seed_from_u64(42);
let p = random_permutation(8, &mut rng);
assert_eq!(p.len(), 8);
let mut sorted = p.into_vec();
sorted.sort_unstable();
assert_eq!(sorted, (0..8).collect::<Vec<_>>());
}
#[test]
fn test_compose() {
let a = Permutation::new(vec![1, 0, 2]).expect("valid");
let b = Permutation::new(vec![2, 1, 0]).expect("valid");
let ab = a.compose(&b).expect("compose");
assert_eq!(ab.as_slice(), &[1, 2, 0]);
}
}