algebraeon_groups/
permutation.rs

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