algebraeon_groups/
permutation.rs

1use super::examples::c2::C2;
2use crate::structure::{
3    AssociativeCompositionSignature, CompositionSignature, GroupSignature, IdentitySignature,
4    LeftCancellativeCompositionSignature, MetaCompositionSignature, MetaGroupSignature,
5    MetaIdentitySignature, MonoidSignature, RightCancellativeCompositionSignature,
6    TryInverseSignature, TryLeftInverseSignature, TryRightInverseSignature,
7};
8use algebraeon_macros::CanonicalStructure;
9use algebraeon_sets::structure::{EqSignature, MetaType, SetSignature, Signature};
10use itertools::Itertools;
11use std::collections::{HashMap, HashSet};
12use std::hash::Hash;
13
14#[derive(Debug, Clone)]
15pub struct Cycle {
16    cyc: Vec<usize>,
17}
18
19impl Cycle {
20    pub fn new(cyc: Vec<usize>) -> Result<Self, &'static str> {
21        let mut present = HashSet::new();
22        for i in &cyc {
23            if present.contains(i) {
24                return Err("Duplicate element in cycle");
25            }
26            present.insert(i);
27        }
28        Ok(Self { cyc })
29    }
30
31    fn new_unchecked(cyc: Vec<usize>) -> Self {
32        Self { cyc }
33    }
34
35    pub fn len(&self) -> usize {
36        self.cyc.len()
37    }
38
39    pub fn is_empty(&self) -> bool {
40        self.cyc.is_empty()
41    }
42}
43
44impl std::convert::From<Cycle> for Permutation {
45    fn from(cyc: Cycle) -> Self {
46        let n = *cyc.cyc.iter().max().unwrap_or(&0);
47        let mut perm = vec![0; n];
48        #[allow(clippy::needless_range_loop)]
49        for i in 0..n {
50            perm[i] = i;
51        }
52        for i in 0..cyc.cyc.len() {
53            perm[cyc.cyc[i]] = cyc.cyc[(i + 1) % n];
54        }
55        Self::new_unchecked(perm)
56    }
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Hash, CanonicalStructure)]
60#[canonical_structure(eq)]
61pub struct Permutation {
62    perm: Vec<usize>,
63}
64
65impl<const N: usize> From<super::examples::symmetric::Permutation<N>> for Permutation {
66    fn from(value: super::examples::symmetric::Permutation<N>) -> Self {
67        Self::new_unchecked((0..N).map(|i| value.call(i).unwrap()).collect())
68    }
69}
70
71fn reduced(mut perm: Vec<usize>) -> Vec<usize> {
72    while !perm.is_empty() {
73        if *perm.last().unwrap() + 1 == perm.len() {
74            perm.pop().unwrap();
75        } else {
76            break;
77        }
78    }
79    perm
80}
81
82impl Permutation {
83    pub fn new(perm: Vec<usize>) -> Result<Self, &'static str> {
84        let n = perm.len();
85        //check that the numbers in forward are 0, 1, ..., n-1 in some order
86        let mut present = (0..n).map(|_| false).collect_vec();
87        for i in &perm {
88            if *i >= n {
89                return Err("Permutation value out of range");
90            }
91            present[*i] = true;
92        }
93        for is_present in present {
94            if !is_present {
95                return Err("Not a valid permutation");
96            }
97        }
98
99        Ok(Self::new_unchecked(perm))
100    }
101
102    pub fn new_unchecked(perm: Vec<usize>) -> Self {
103        Self {
104            perm: reduced(perm),
105        }
106    }
107
108    pub fn n(&self) -> usize {
109        self.perm.len()
110    }
111
112    pub fn call(&self, x: usize) -> usize {
113        match self.perm.get(x) {
114            Some(y) => *y,
115            None => x,
116        }
117    }
118
119    pub fn sign(&self) -> C2 {
120        let mut s = C2::identity();
121        for i in 0..self.perm.len() {
122            for j in 0..i {
123                if (i < j) != (self.call(i) < self.call(j)) {
124                    s.compose_mut(&C2::Flip);
125                }
126            }
127        }
128        s
129    }
130
131    pub fn disjoint_cycles(&self) -> Vec<Cycle> {
132        let n = self.perm.len();
133        let mut missing: std::collections::HashSet<usize> = (0..n).collect();
134        let mut cycles = vec![];
135        while !missing.is_empty() {
136            let mut cycle = vec![];
137            let x = *missing.iter().min().unwrap();
138            let mut i = x;
139            loop {
140                cycle.push(i);
141                missing.remove(&i);
142                i = self.perm[i];
143                if i == x {
144                    break;
145                }
146            }
147            if cycle.len() >= 2 {
148                cycles.push(Cycle { cyc: cycle });
149            }
150        }
151        cycles
152    }
153
154    pub fn cycle_shape(&self) -> Vec<usize> {
155        let mut shape = self.disjoint_cycles().iter().map(Cycle::len).collect_vec();
156        shape.sort_unstable();
157        shape
158    }
159
160    pub fn all_permutations(n: usize) -> impl Iterator<Item = Self> {
161        (0..n).permutations(n).map(Self::new_unchecked)
162    }
163
164    pub fn symmetric_composition_table(
165        n: usize,
166    ) -> (
167        crate::composition_table::group::FiniteGroupMultiplicationTable,
168        Vec<Self>,
169        HashMap<Self, usize>,
170    ) {
171        Self::generated_finite_subgroup_table(
172            Self::all_permutations(n)
173                .filter(|p| p.cycle_shape() == vec![2])
174                .collect(),
175        )
176    }
177
178    pub fn alternating_composition_table(
179        n: usize,
180    ) -> (
181        crate::composition_table::group::FiniteGroupMultiplicationTable,
182        Vec<Self>,
183        HashMap<Self, usize>,
184    ) {
185        Self::generated_finite_subgroup_table(
186            Self::all_permutations(n)
187                .filter(|p| p.sign() == C2::Identity)
188                .collect(),
189        )
190    }
191}
192
193// impl PartialEq for Permutation {
194//     fn eq(&self, other: &Self) -> bool {
195//         let n = std::cmp::max(self.perm.len(), other.perm.len());
196//         (0..n).all(|i| self.call(i) == other.call(i))
197//     }
198// }
199
200// impl Eq for Permutation {}
201
202// impl Hash for Permutation {
203//     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
204//         let mut self_reduced = self.clone();
205//         self_reduced.reduce();
206//         self_reduced.perm.hash(state);
207//     }
208// }
209
210impl CompositionSignature for PermutationCanonicalStructure {
211    fn compose(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
212        let n = std::cmp::max(a.perm.len(), b.perm.len());
213        Permutation::new_unchecked((0..n).map(|i| a.call(b.call(i))).collect())
214    }
215}
216
217impl AssociativeCompositionSignature for PermutationCanonicalStructure {}
218
219impl LeftCancellativeCompositionSignature for PermutationCanonicalStructure {
220    fn try_left_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
221        Some(self.compose(&self.inverse(b), a))
222    }
223}
224
225impl RightCancellativeCompositionSignature for PermutationCanonicalStructure {
226    fn try_right_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
227        Some(self.compose(a, &self.inverse(b)))
228    }
229}
230
231impl IdentitySignature for PermutationCanonicalStructure {
232    fn identity(&self) -> Self::Set {
233        Permutation { perm: vec![] }
234    }
235}
236
237impl MonoidSignature for PermutationCanonicalStructure {}
238
239impl TryLeftInverseSignature for PermutationCanonicalStructure {
240    fn try_left_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
241        Some(self.inverse(a))
242    }
243}
244
245impl TryRightInverseSignature for PermutationCanonicalStructure {
246    fn try_right_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
247        Some(self.inverse(a))
248    }
249}
250
251impl TryInverseSignature for PermutationCanonicalStructure {
252    fn try_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
253        Some(self.inverse(a))
254    }
255}
256
257impl GroupSignature for PermutationCanonicalStructure {
258    fn inverse(&self, a: &Self::Set) -> Self::Set {
259        let mut inv_perm = vec![0; a.perm.len()];
260        for (i, j) in a.perm.iter().enumerate() {
261            inv_perm[*j] = i;
262        }
263        Permutation::new_unchecked(inv_perm)
264    }
265}
266
267impl std::fmt::Display for Permutation {
268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269        let mut cycles = self.disjoint_cycles();
270        cycles.retain(|cycle| cycle.len() != 1);
271
272        if cycles.is_empty() {
273            f.write_str("()")?;
274        }
275
276        #[allow(clippy::redundant_closure_for_method_calls)]
277        let string = cycles
278            .iter()
279            .map(|cycle| {
280                "(".to_owned()
281                    + &cycle
282                        .cyc
283                        .iter()
284                        .map(|x| x.to_string())
285                        .collect::<Vec<String>>()
286                        .join(" ")
287                    + ")"
288            })
289            .collect::<Vec<String>>()
290            .join(" ");
291
292        f.write_str(string.as_str())
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use crate::structure::MetaCompositionSignature;
299
300    use super::*;
301
302    #[test]
303    fn test_composition() {
304        let a = Permutation::new(vec![0, 2, 1, 3]).unwrap();
305        let b = Permutation::new(vec![1, 2, 0, 3]).unwrap();
306        let c = Permutation::new(vec![2, 1, 0]).unwrap();
307
308        println!("a = {}", a);
309        println!("b = {}", b);
310        println!("ab = {}", Permutation::compose(&a, &b));
311        println!("c = {}", c);
312
313        assert_eq!(Permutation::compose(&a, &b), c);
314    }
315
316    // #[test]
317    // fn test_dcn() {
318    //     let a = Permutation::new(vec![0, 2, 1, 5, 3, 4]).unwrap();
319    //     assert_eq!(
320    //         a.disjoint_cycles(),
321    //         vec![Cycle::new(vec![1, 2]), Cycle::new(vec![3, 4, 5])]
322    //     );
323    // }
324
325    #[test]
326    fn test_sign() {
327        let a = Permutation::new(vec![0, 2, 1]).unwrap();
328        let b = Permutation::new(vec![1, 2, 0]).unwrap();
329        let c = Permutation::new(vec![2, 1, 0]).unwrap();
330
331        println!("a = {}", a);
332        println!("b = {}", b);
333        println!("c = {}", c);
334
335        assert_eq!(a.sign(), C2::Flip);
336        assert_eq!(b.sign(), C2::Identity);
337        assert_eq!(c.sign(), C2::Flip);
338    }
339
340    #[test]
341    fn test_all_permutations() {
342        assert_eq!(Permutation::all_permutations(0).collect_vec().len(), 1);
343        assert_eq!(Permutation::all_permutations(1).collect_vec().len(), 1);
344        assert_eq!(Permutation::all_permutations(2).collect_vec().len(), 2);
345        assert_eq!(Permutation::all_permutations(3).collect_vec().len(), 6);
346        assert_eq!(Permutation::all_permutations(4).collect_vec().len(), 24);
347        assert_eq!(Permutation::all_permutations(5).collect_vec().len(), 120);
348    }
349}