algebraeon_groups/
permutation.rs1use 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 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
181impl 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]
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}