algebraeon_groups/
permutation.rs

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