1use super::examples::c2::C2;
2use crate::structure::{
3 AssociativeCompositionSignature, CompositionSignature, GroupSignature, IdentitySignature,
4 LeftCancellativeCompositionSignature, MetaCompositionSignature, MetaGroupSignature,
5 MetaIdentitySignature, MonoidSignature, RightCancellativeCompositionSignature,
6 TryInverseSignature, TryLeftInverseSignature, TryRightInverseSignature,
7};
8use algebraeon_macros::CanonicalStructure;
9use algebraeon_sets::structure::{EqSignature, MetaType, SetSignature, Signature};
10use itertools::Itertools;
11use std::collections::{HashMap, HashSet};
12use std::hash::Hash;
13
14#[derive(Debug, Clone)]
15pub struct Cycle {
16 cyc: Vec<usize>,
17}
18
19impl Cycle {
20 pub fn new(cyc: Vec<usize>) -> Result<Self, &'static str> {
21 let mut present = HashSet::new();
22 for i in &cyc {
23 if present.contains(i) {
24 return Err("Duplicate element in cycle");
25 }
26 present.insert(i);
27 }
28 Ok(Self { cyc })
29 }
30
31 fn new_unchecked(cyc: Vec<usize>) -> Self {
32 Self { cyc }
33 }
34
35 pub fn len(&self) -> usize {
36 self.cyc.len()
37 }
38
39 pub fn is_empty(&self) -> bool {
40 self.cyc.is_empty()
41 }
42}
43
44impl std::convert::From<Cycle> for Permutation {
45 fn from(cyc: Cycle) -> Self {
46 let n = *cyc.cyc.iter().max().unwrap_or(&0);
47 let mut perm = vec![0; n];
48 #[allow(clippy::needless_range_loop)]
49 for i in 0..n {
50 perm[i] = i;
51 }
52 for i in 0..cyc.cyc.len() {
53 perm[cyc.cyc[i]] = cyc.cyc[(i + 1) % n];
54 }
55 Self::new_unchecked(perm)
56 }
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Hash, CanonicalStructure)]
60#[canonical_structure(eq)]
61pub struct Permutation {
62 perm: Vec<usize>,
63}
64
65impl<const N: usize> From<super::examples::symmetric::Permutation<N>> for Permutation {
66 fn from(value: super::examples::symmetric::Permutation<N>) -> Self {
67 Self::new_unchecked((0..N).map(|i| value.call(i).unwrap()).collect())
68 }
69}
70
71fn reduced(mut perm: Vec<usize>) -> Vec<usize> {
72 while !perm.is_empty() {
73 if *perm.last().unwrap() + 1 == perm.len() {
74 perm.pop().unwrap();
75 } else {
76 break;
77 }
78 }
79 perm
80}
81
82impl Permutation {
83 pub fn new(perm: Vec<usize>) -> Result<Self, &'static str> {
84 let n = perm.len();
85 let mut present = (0..n).map(|_| false).collect_vec();
87 for i in &perm {
88 if *i >= n {
89 return Err("Permutation value out of range");
90 }
91 present[*i] = true;
92 }
93 for is_present in present {
94 if !is_present {
95 return Err("Not a valid permutation");
96 }
97 }
98
99 Ok(Self::new_unchecked(perm))
100 }
101
102 pub fn new_unchecked(perm: Vec<usize>) -> Self {
103 Self {
104 perm: reduced(perm),
105 }
106 }
107
108 pub fn n(&self) -> usize {
109 self.perm.len()
110 }
111
112 pub fn call(&self, x: usize) -> usize {
113 match self.perm.get(x) {
114 Some(y) => *y,
115 None => x,
116 }
117 }
118
119 pub fn sign(&self) -> C2 {
120 let mut s = C2::identity();
121 for i in 0..self.perm.len() {
122 for j in 0..i {
123 if (i < j) != (self.call(i) < self.call(j)) {
124 s.compose_mut(&C2::Flip);
125 }
126 }
127 }
128 s
129 }
130
131 pub fn disjoint_cycles(&self) -> Vec<Cycle> {
132 let n = self.perm.len();
133 let mut missing: std::collections::HashSet<usize> = (0..n).collect();
134 let mut cycles = vec![];
135 while !missing.is_empty() {
136 let mut cycle = vec![];
137 let x = *missing.iter().min().unwrap();
138 let mut i = x;
139 loop {
140 cycle.push(i);
141 missing.remove(&i);
142 i = self.perm[i];
143 if i == x {
144 break;
145 }
146 }
147 if cycle.len() >= 2 {
148 cycles.push(Cycle { cyc: cycle });
149 }
150 }
151 cycles
152 }
153
154 pub fn cycle_shape(&self) -> Vec<usize> {
155 let mut shape = self.disjoint_cycles().iter().map(Cycle::len).collect_vec();
156 shape.sort_unstable();
157 shape
158 }
159
160 pub fn all_permutations(n: usize) -> impl Iterator<Item = Self> {
161 (0..n).permutations(n).map(Self::new_unchecked)
162 }
163
164 pub fn symmetric_composition_table(
165 n: usize,
166 ) -> (
167 crate::composition_table::group::FiniteGroupMultiplicationTable,
168 Vec<Self>,
169 HashMap<Self, usize>,
170 ) {
171 Self::generated_finite_subgroup_table(
172 Self::all_permutations(n)
173 .filter(|p| p.cycle_shape() == vec![2])
174 .collect(),
175 )
176 }
177
178 pub fn alternating_composition_table(
179 n: usize,
180 ) -> (
181 crate::composition_table::group::FiniteGroupMultiplicationTable,
182 Vec<Self>,
183 HashMap<Self, usize>,
184 ) {
185 Self::generated_finite_subgroup_table(
186 Self::all_permutations(n)
187 .filter(|p| p.sign() == C2::Identity)
188 .collect(),
189 )
190 }
191}
192
193impl CompositionSignature for PermutationCanonicalStructure {
211 fn compose(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
212 let n = std::cmp::max(a.perm.len(), b.perm.len());
213 Permutation::new_unchecked((0..n).map(|i| a.call(b.call(i))).collect())
214 }
215}
216
217impl AssociativeCompositionSignature for PermutationCanonicalStructure {}
218
219impl LeftCancellativeCompositionSignature for PermutationCanonicalStructure {
220 fn try_left_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
221 Some(self.compose(&self.inverse(b), a))
222 }
223}
224
225impl RightCancellativeCompositionSignature for PermutationCanonicalStructure {
226 fn try_right_difference(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
227 Some(self.compose(a, &self.inverse(b)))
228 }
229}
230
231impl IdentitySignature for PermutationCanonicalStructure {
232 fn identity(&self) -> Self::Set {
233 Permutation { perm: vec![] }
234 }
235}
236
237impl MonoidSignature for PermutationCanonicalStructure {}
238
239impl TryLeftInverseSignature for PermutationCanonicalStructure {
240 fn try_left_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
241 Some(self.inverse(a))
242 }
243}
244
245impl TryRightInverseSignature for PermutationCanonicalStructure {
246 fn try_right_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
247 Some(self.inverse(a))
248 }
249}
250
251impl TryInverseSignature for PermutationCanonicalStructure {
252 fn try_inverse(&self, a: &Self::Set) -> Option<Self::Set> {
253 Some(self.inverse(a))
254 }
255}
256
257impl GroupSignature for PermutationCanonicalStructure {
258 fn inverse(&self, a: &Self::Set) -> Self::Set {
259 let mut inv_perm = vec![0; a.perm.len()];
260 for (i, j) in a.perm.iter().enumerate() {
261 inv_perm[*j] = i;
262 }
263 Permutation::new_unchecked(inv_perm)
264 }
265}
266
267impl std::fmt::Display for Permutation {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 let mut cycles = self.disjoint_cycles();
270 cycles.retain(|cycle| cycle.len() != 1);
271
272 if cycles.is_empty() {
273 f.write_str("()")?;
274 }
275
276 #[allow(clippy::redundant_closure_for_method_calls)]
277 let string = cycles
278 .iter()
279 .map(|cycle| {
280 "(".to_owned()
281 + &cycle
282 .cyc
283 .iter()
284 .map(|x| x.to_string())
285 .collect::<Vec<String>>()
286 .join(" ")
287 + ")"
288 })
289 .collect::<Vec<String>>()
290 .join(" ");
291
292 f.write_str(string.as_str())
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use crate::structure::MetaCompositionSignature;
299
300 use super::*;
301
302 #[test]
303 fn test_composition() {
304 let a = Permutation::new(vec![0, 2, 1, 3]).unwrap();
305 let b = Permutation::new(vec![1, 2, 0, 3]).unwrap();
306 let c = Permutation::new(vec![2, 1, 0]).unwrap();
307
308 println!("a = {}", a);
309 println!("b = {}", b);
310 println!("ab = {}", Permutation::compose(&a, &b));
311 println!("c = {}", c);
312
313 assert_eq!(Permutation::compose(&a, &b), c);
314 }
315
316 #[test]
326 fn test_sign() {
327 let a = Permutation::new(vec![0, 2, 1]).unwrap();
328 let b = Permutation::new(vec![1, 2, 0]).unwrap();
329 let c = Permutation::new(vec![2, 1, 0]).unwrap();
330
331 println!("a = {}", a);
332 println!("b = {}", b);
333 println!("c = {}", c);
334
335 assert_eq!(a.sign(), C2::Flip);
336 assert_eq!(b.sign(), C2::Identity);
337 assert_eq!(c.sign(), C2::Flip);
338 }
339
340 #[test]
341 fn test_all_permutations() {
342 assert_eq!(Permutation::all_permutations(0).collect_vec().len(), 1);
343 assert_eq!(Permutation::all_permutations(1).collect_vec().len(), 1);
344 assert_eq!(Permutation::all_permutations(2).collect_vec().len(), 2);
345 assert_eq!(Permutation::all_permutations(3).collect_vec().len(), 6);
346 assert_eq!(Permutation::all_permutations(4).collect_vec().len(), 24);
347 assert_eq!(Permutation::all_permutations(5).collect_vec().len(), 120);
348 }
349}