rusty_perm/
perm_trait.rs

1/// An abstract representation of permutation data structure.
2pub trait Permutation {
3    /// Gets the size of permutation.
4    fn len(&self) -> usize;
5
6    /// Builds the inverse of permutation.
7    fn inverse(&self) -> Self;
8
9    /// Gets the reference to the internal permuted indices.
10    fn indices(&self) -> &[usize];
11
12    fn pow(&self, exp: u32) -> Self;
13}
14
15mod without_std {
16    use super::*;
17    use crate::perm_type::PermS;
18
19    impl<const SIZE: usize> Permutation for PermS<SIZE> {
20        fn indices(&self) -> &[usize] {
21            self.indices.as_ref()
22        }
23
24        fn len(&self) -> usize {
25            SIZE
26        }
27
28        fn inverse(&self) -> Self {
29            let mut inversed = [0; SIZE];
30            inverse_indices(self.indices.as_ref(), &mut inversed);
31            Self { indices: inversed }
32        }
33
34        fn pow(&self, exp: u32) -> Self {
35            let mut mask = u32_leading_bit(exp);
36            let mut pow = Self::identity();
37
38            // power by squaring
39            loop {
40                if exp & mask != 0 {
41                    pow = &pow * self;
42                }
43
44                mask >>= 1;
45
46                if mask == 0 {
47                    break;
48                } else {
49                    pow = &pow * &pow;
50                }
51            }
52
53            pow
54        }
55    }
56
57    #[cfg(test)]
58    mod tests {
59        use super::*;
60        use crate::apply::PermApply;
61        use rand::prelude::*;
62
63        #[test]
64        fn static_inverse() {
65            const SIZE: usize = 1024;
66            {
67                let mut rng = rand::thread_rng();
68
69                let mut perm = PermS::<SIZE>::identity();
70                perm.indices.shuffle(&mut rng);
71                let inverse = perm.inverse();
72
73                let mut orig = [0usize; SIZE];
74                rng.fill(&mut orig);
75
76                let mut new = orig.clone();
77                perm.apply(&mut new);
78                inverse.apply(&mut new);
79
80                assert_eq!(orig, new);
81            }
82
83            {
84                assert_eq!(
85                    PermS::<SIZE>::cycle().inverse(),
86                    PermS::<SIZE>::reverse_cycle()
87                );
88            }
89        }
90    }
91}
92
93#[cfg(feature = "std")]
94mod with_std {
95    use super::*;
96    use crate::perm_type::PermD;
97
98    impl Permutation for PermD {
99        fn indices(&self) -> &[usize] {
100            self.indices.as_ref()
101        }
102
103        fn len(&self) -> usize {
104            self.indices.len()
105        }
106
107        fn inverse(&self) -> Self {
108            let mut inversed = vec![0; self.indices.len()];
109            inverse_indices(self.indices.as_slice(), &mut inversed);
110            Self { indices: inversed }
111        }
112
113        fn pow(&self, exp: u32) -> Self {
114            let mut mask = u32_leading_bit(exp);
115            let mut pow = Self::identity(self.indices.len());
116
117            // power by squaring
118            loop {
119                if exp & mask != 0 {
120                    pow = &pow * self;
121                }
122
123                mask >>= 1;
124
125                if mask == 0 {
126                    break;
127                } else {
128                    pow = &pow * &pow;
129                }
130            }
131
132            pow
133        }
134    }
135
136    #[cfg(test)]
137    mod tests {
138        use super::*;
139        use crate::{apply::PermApply, perm_type::PermS};
140        use rand::prelude::*;
141        use std::collections::HashSet;
142
143        #[test]
144        fn dynamic_inverse() {
145            const SIZE: usize = 1024;
146            {
147                let mut rng = rand::thread_rng();
148
149                let mut perm = PermD::identity(SIZE);
150                perm.indices.shuffle(&mut rng);
151                let inverse = perm.inverse();
152
153                let mut orig = [0usize; SIZE];
154                rng.fill(&mut orig);
155
156                let mut new = orig.clone();
157                perm.apply(&mut new).unwrap();
158                inverse.apply(&mut new).unwrap();
159
160                assert_eq!(orig, new);
161            }
162
163            {
164                assert_eq!(PermD::cycle(SIZE).inverse(), PermD::reverse_cycle(SIZE));
165            }
166        }
167
168        #[test]
169        fn dynamic_pow() {
170            let cycle = PermD::cycle(6);
171            assert_eq!(cycle.pow(5), PermD::reverse_cycle(6));
172            assert_eq!(cycle.pow(6), PermD::identity(6));
173
174            let set: HashSet<_> = (0..6).map(|exp| cycle.pow(exp)).collect();
175            assert_eq!(set.len(), 6);
176        }
177
178        #[test]
179        fn static_pow() {
180            let cycle = PermS::<6>::cycle();
181            assert_eq!(cycle.pow(5), PermS::<6>::reverse_cycle());
182            assert_eq!(cycle.pow(6), PermS::<6>::identity());
183
184            let set: HashSet<_> = (0..6).map(|exp| cycle.pow(exp)).collect();
185            assert_eq!(set.len(), 6);
186        }
187    }
188}
189
190fn inverse_indices(indices: &[usize], inverse_indices: &mut [usize]) {
191    indices.iter().enumerate().for_each(|(dst, &src)| {
192        inverse_indices[src] = dst;
193    });
194}
195
196fn u32_leading_bit(n: u32) -> u32 {
197    let n = n as u64;
198    let n = n | (n >> 1);
199    let n = n | (n >> 2);
200    let n = n | (n >> 4);
201    let n = n | (n >> 8);
202    let n = n | (n >> 16);
203    ((n + 1) >> 1) as u32
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209
210    #[test]
211    fn u32_leading_bit_test() {
212        assert_eq!(u32_leading_bit(0b1), 0b1);
213        assert_eq!(u32_leading_bit(0b10), 0b10);
214        assert_eq!(u32_leading_bit(0b11), 0b10);
215        assert_eq!(u32_leading_bit(0b100111), 0b100000);
216        assert_eq!(
217            u32_leading_bit(0b_11111111_11111111_11111111_11111111),
218            0b_10000000_00000000_00000000_00000000
219        );
220    }
221}