rivrs_sparse/ordering/
perm.rs1use faer::perm::Perm;
12
13use crate::error::SparseError;
14use crate::validate;
15
16pub fn perm_from_forward(fwd: Vec<usize>) -> Result<Perm<usize>, SparseError> {
39 let n = fwd.len();
40 validate::validate_permutation(&fwd, n)?;
41
42 let mut inv = vec![0usize; n];
44 for (i, &f) in fwd.iter().enumerate() {
45 inv[f] = i;
46 }
47
48 let fwd_box = fwd.into_boxed_slice();
49 let inv_box = inv.into_boxed_slice();
50 Ok(Perm::new_checked(fwd_box, inv_box, n))
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
60 fn identity_permutation() {
61 let fwd = vec![0, 1, 2, 3, 4];
62 let perm = perm_from_forward(fwd).unwrap();
63 let (fwd_arr, inv_arr) = perm.as_ref().arrays();
64 assert_eq!(fwd_arr, &[0, 1, 2, 3, 4]);
65 assert_eq!(inv_arr, &[0, 1, 2, 3, 4]);
66 }
67
68 #[test]
69 fn nontrivial_permutation_round_trip() {
70 let fwd = vec![3, 1, 4, 0, 2];
71 let perm = perm_from_forward(fwd).unwrap();
72 let (fwd_arr, inv_arr) = perm.as_ref().arrays();
73
74 for i in 0..5 {
76 assert_eq!(inv_arr[fwd_arr[i]], i);
77 }
78 for i in 0..5 {
80 assert_eq!(fwd_arr[inv_arr[i]], i);
81 }
82 }
83
84 #[test]
85 fn composition_of_two_permutations() {
86 let p1 = perm_from_forward(vec![1, 0, 2]).unwrap();
87 let p2 = perm_from_forward(vec![2, 1, 0]).unwrap();
88 let (p1_fwd, _) = p1.as_ref().arrays();
89 let (p2_fwd, _) = p2.as_ref().arrays();
90
91 let composed: Vec<usize> = (0..3).map(|i| p2_fwd[p1_fwd[i]]).collect();
93 let composed_perm = perm_from_forward(composed).unwrap();
94 let (comp_fwd, comp_inv) = composed_perm.as_ref().arrays();
95
96 assert_eq!(comp_fwd, &[1, 2, 0]);
103
104 for i in 0..3 {
106 assert_eq!(comp_inv[comp_fwd[i]], i);
107 }
108 }
109
110 #[test]
111 fn empty_array_dimension_0() {
112 let perm = perm_from_forward(vec![]).unwrap();
113 let (fwd_arr, inv_arr) = perm.as_ref().arrays();
114 assert!(fwd_arr.is_empty());
115 assert!(inv_arr.is_empty());
116 }
117
118 #[test]
119 fn single_element() {
120 let perm = perm_from_forward(vec![0]).unwrap();
121 let (fwd_arr, inv_arr) = perm.as_ref().arrays();
122 assert_eq!(fwd_arr, &[0]);
123 assert_eq!(inv_arr, &[0]);
124 }
125
126 #[test]
127 fn error_on_duplicate_indices() {
128 let result = perm_from_forward(vec![0, 1, 1]);
129 assert!(result.is_err());
130 }
131
132 #[test]
133 fn error_on_out_of_bounds() {
134 let result = perm_from_forward(vec![0, 5, 2]);
135 assert!(result.is_err());
136 }
137
138 #[test]
139 fn forward_inverse_relationship() {
140 let fwd = vec![4, 2, 0, 3, 1];
141 let perm = perm_from_forward(fwd).unwrap();
142 let (fwd_arr, inv_arr) = perm.as_ref().arrays();
143
144 for i in 0..5 {
145 assert_eq!(inv_arr[fwd_arr[i]], i, "inv[fwd[{}]] != {}", i, i);
146 assert_eq!(fwd_arr[inv_arr[i]], i, "fwd[inv[{}]] != {}", i, i);
147 }
148 }
149
150 #[test]
151 fn scale_test_n_10000() {
152 let n = 10_000;
154 let fwd: Vec<usize> = (0..n).map(|i| (i + 1) % n).collect();
156 let perm = perm_from_forward(fwd).unwrap();
157 let (fwd_arr, inv_arr) = perm.as_ref().arrays();
158
159 for i in 0..n {
161 assert_eq!(inv_arr[fwd_arr[i]], i);
162 assert_eq!(fwd_arr[inv_arr[i]], i);
163 }
164 }
165}