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