algebraeon_groups/examples/
symmetric.rs

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