use faer::perm::Perm;
use crate::error::SparseError;
use crate::validate;
pub fn perm_from_forward(fwd: Vec<usize>) -> Result<Perm<usize>, SparseError> {
let n = fwd.len();
validate::validate_permutation(&fwd, n)?;
let mut inv = vec![0usize; n];
for (i, &f) in fwd.iter().enumerate() {
inv[f] = i;
}
let fwd_box = fwd.into_boxed_slice();
let inv_box = inv.into_boxed_slice();
Ok(Perm::new_checked(fwd_box, inv_box, n))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn identity_permutation() {
let fwd = vec![0, 1, 2, 3, 4];
let perm = perm_from_forward(fwd).unwrap();
let (fwd_arr, inv_arr) = perm.as_ref().arrays();
assert_eq!(fwd_arr, &[0, 1, 2, 3, 4]);
assert_eq!(inv_arr, &[0, 1, 2, 3, 4]);
}
#[test]
fn nontrivial_permutation_round_trip() {
let fwd = vec![3, 1, 4, 0, 2];
let perm = perm_from_forward(fwd).unwrap();
let (fwd_arr, inv_arr) = perm.as_ref().arrays();
for i in 0..5 {
assert_eq!(inv_arr[fwd_arr[i]], i);
}
for i in 0..5 {
assert_eq!(fwd_arr[inv_arr[i]], i);
}
}
#[test]
fn composition_of_two_permutations() {
let p1 = perm_from_forward(vec![1, 0, 2]).unwrap();
let p2 = perm_from_forward(vec![2, 1, 0]).unwrap();
let (p1_fwd, _) = p1.as_ref().arrays();
let (p2_fwd, _) = p2.as_ref().arrays();
let composed: Vec<usize> = (0..3).map(|i| p2_fwd[p1_fwd[i]]).collect();
let composed_perm = perm_from_forward(composed).unwrap();
let (comp_fwd, comp_inv) = composed_perm.as_ref().arrays();
assert_eq!(comp_fwd, &[1, 2, 0]);
for i in 0..3 {
assert_eq!(comp_inv[comp_fwd[i]], i);
}
}
#[test]
fn empty_array_dimension_0() {
let perm = perm_from_forward(vec![]).unwrap();
let (fwd_arr, inv_arr) = perm.as_ref().arrays();
assert!(fwd_arr.is_empty());
assert!(inv_arr.is_empty());
}
#[test]
fn single_element() {
let perm = perm_from_forward(vec![0]).unwrap();
let (fwd_arr, inv_arr) = perm.as_ref().arrays();
assert_eq!(fwd_arr, &[0]);
assert_eq!(inv_arr, &[0]);
}
#[test]
fn error_on_duplicate_indices() {
let result = perm_from_forward(vec![0, 1, 1]);
assert!(result.is_err());
}
#[test]
fn error_on_out_of_bounds() {
let result = perm_from_forward(vec![0, 5, 2]);
assert!(result.is_err());
}
#[test]
fn forward_inverse_relationship() {
let fwd = vec![4, 2, 0, 3, 1];
let perm = perm_from_forward(fwd).unwrap();
let (fwd_arr, inv_arr) = perm.as_ref().arrays();
for i in 0..5 {
assert_eq!(inv_arr[fwd_arr[i]], i, "inv[fwd[{}]] != {}", i, i);
assert_eq!(fwd_arr[inv_arr[i]], i, "fwd[inv[{}]] != {}", i, i);
}
}
#[test]
fn scale_test_n_10000() {
let n = 10_000;
let fwd: Vec<usize> = (0..n).map(|i| (i + 1) % n).collect();
let perm = perm_from_forward(fwd).unwrap();
let (fwd_arr, inv_arr) = perm.as_ref().arrays();
for i in 0..n {
assert_eq!(inv_arr[fwd_arr[i]], i);
assert_eq!(fwd_arr[inv_arr[i]], i);
}
}
}