1use std::collections::{HashMap, HashSet, VecDeque};
4use std::fmt;
5use std::hash::Hash;
6use std::ops::Mul;
7
8use anyhow::{self, format_err};
9use bitvec::prelude::*;
10use derive_builder::Builder;
11use factorial::Factorial;
12use indexmap::IndexSet;
13use num::{integer::lcm, Integer, Unsigned};
14use num_traits::{Inv, Pow, PrimInt};
15use serde::{Deserialize, Serialize};
16
17use crate::group::FiniteOrder;
18
19mod permutation_group;
20mod permutation_symbols;
21
22#[cfg(test)]
23mod permutation_tests;
24
25pub trait PermutableCollection
32where
33 Self: Sized,
34 Self::Rank: PermutationRank,
35{
36 type Rank;
38
39 fn get_perm_of(&self, other: &Self) -> Option<Permutation<Self::Rank>>;
41
42 fn permute(&self, perm: &Permutation<Self::Rank>) -> Result<Self, anyhow::Error>;
45
46 fn permute_mut(&mut self, perm: &Permutation<Self::Rank>) -> Result<(), anyhow::Error>;
48}
49
50pub trait IntoPermutation<C: PermutableCollection> {
53 fn act_permute(&self, rhs: &C) -> Option<Permutation<C::Rank>>;
57}
58
59pub trait PermutationRank:
61 Integer + Unsigned + BitStore + PrimInt + Hash + TryFrom<usize> + Into<usize> + Serialize
62{
63}
64
65impl<T> PermutationRank for T
67where
68 T: Integer + Unsigned + BitStore + PrimInt + Hash + TryFrom<usize> + Into<usize> + Serialize,
69 <T as TryFrom<usize>>::Error: fmt::Debug,
70 std::ops::Range<T>: Iterator + DoubleEndedIterator,
71 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
72 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
73 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
74{
75}
76
77#[derive(Builder, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
83pub struct Permutation<T: PermutationRank> {
84 #[builder(setter(custom))]
87 image: Vec<T>,
88}
89
90impl<T: PermutationRank> PermutationBuilder<T> {
91 pub fn image(&mut self, perm: Vec<T>) -> &mut Self {
94 let mut uniq = HashSet::<T>::new();
95 if perm.iter().all(move |x| uniq.insert(*x)) {
100 self.image = Some(perm);
102 }
103 self
104 }
105}
106
107impl<T: PermutationRank> Permutation<T> {
108 #[must_use]
110 fn builder() -> PermutationBuilder<T> {
111 PermutationBuilder::default()
112 }
113
114 pub fn from_image(image: Vec<T>) -> Result<Self, anyhow::Error> {
130 Self::builder()
131 .image(image.clone())
132 .build()
133 .map_err(|err| format_err!(err))
134 }
135
136 pub fn from_cycles(cycles: &[Vec<T>]) -> Result<Self, anyhow::Error> {
150 let mut uniq = HashSet::<T>::new();
151 assert!(
152 cycles.iter().flatten().all(move |x| uniq.insert(*x)),
153 "The permutation cycles `{cycles:?}` contains repeated elements."
154 );
155 let mut image_map = cycles
156 .iter()
157 .flat_map(|cycle| {
158 let start = *cycle.first().expect("Empty cycles are not permitted.");
159 let end = *cycle.last().expect("Empty cycles are not permitted.");
160 cycle
161 .windows(2)
162 .map(|pair| {
163 let idx = pair[0];
164 let img = pair[1];
165 (idx, img)
166 })
167 .chain([(end, start)])
168 })
169 .collect::<Vec<(T, T)>>();
170 image_map.sort();
171 let image = image_map
172 .into_iter()
173 .map(|(_, img)| img)
174 .collect::<Vec<T>>();
175 Self::from_image(image)
176 }
177
178 pub fn from_lehmer(lehmer: Vec<T>) -> Result<Self, anyhow::Error>
182 where
183 <T as TryFrom<usize>>::Error: fmt::Debug,
184 std::ops::Range<T>: Iterator,
185 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
186 {
187 let n = T::try_from(lehmer.len()).expect("Unable to convert the `lehmer` length to `u8`.");
188 let mut remaining = (T::zero()..n).collect::<VecDeque<T>>();
189 let image = lehmer
190 .iter()
191 .map(|&k| {
192 remaining.remove(k.into()).unwrap_or_else(|| {
193 panic!("Unable to retrieve element index `{k:?}` from `{remaining:?}`.")
194 })
195 })
196 .collect::<Vec<_>>();
197 Self::from_image(image)
198 }
199
200 pub fn from_lehmer_index(index: usize, rank: T) -> Result<Self, anyhow::Error>
219 where
220 <T as TryFrom<usize>>::Error: fmt::Debug,
221 std::ops::Range<T>: Iterator,
222 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
223 {
224 let mut quotient = index;
225 let mut lehmer: VecDeque<T> = VecDeque::new();
226 let mut i = 1usize;
227 while quotient != 0 {
228 if i == 1 {
229 lehmer.push_front(T::zero());
230 } else {
231 lehmer.push_front(T::try_from(quotient.rem_euclid(i)).unwrap());
232 quotient = quotient.div_euclid(i);
233 }
234 i += 1;
235 }
236 if lehmer.len() > rank.into() {
237 Err(format_err!(
238 "The Lehmer encode length is larger than the rank of the permutation."
239 ))
240 } else {
241 while lehmer.len() < rank.into() {
242 lehmer.push_front(T::zero());
243 }
244 Self::from_lehmer(lehmer.into_iter().collect::<Vec<_>>())
245 }
246 }
247
248 pub fn rank(&self) -> T {
250 T::try_from(self.image.len()).unwrap_or_else(|_| {
251 panic!(
252 "The rank of `{:?}` is too large to be represented as `u8`.",
253 self.image
254 )
255 })
256 }
257
258 pub fn image(&self) -> &Vec<T> {
261 &self.image
262 }
263
264 pub fn cycles(&self) -> Vec<Vec<T>>
266 where
267 std::ops::Range<T>: Iterator + DoubleEndedIterator,
268 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
269 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
270 {
271 let image = &self.image;
272 let rank = self.rank();
273 let mut remaining_indices = (T::zero()..rank).rev().collect::<IndexSet<T>>();
274 let mut cycles: Vec<Vec<T>> = Vec::with_capacity(rank.into());
275 while !remaining_indices.is_empty() {
276 let start = remaining_indices
277 .pop()
278 .expect("`remaining_indices` should not be empty.");
279 let mut cycle: Vec<T> = Vec::with_capacity(remaining_indices.len());
280 cycle.push(start);
281 let mut idx = start;
282 while image[idx.into()] != start {
283 idx = image[idx.into()];
284 assert!(remaining_indices.shift_remove(&idx));
285 cycle.push(idx);
286 }
287 cycle.shrink_to_fit();
288 cycles.push(cycle);
289 }
290 cycles.shrink_to_fit();
291 cycles.sort_by_key(|cycle| (!cycle.len(), cycle.clone()));
292 cycles
293 }
294
295 pub fn cycle_pattern(&self) -> Vec<T>
297 where
298 <T as TryFrom<usize>>::Error: fmt::Debug,
299 std::ops::Range<T>: Iterator + DoubleEndedIterator,
300 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
301 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
302 {
303 self.cycles()
304 .iter()
305 .map(|cycle| {
306 T::try_from(cycle.len()).expect("Some cycle lengths are too long for `u8`.")
307 })
308 .collect::<Vec<T>>()
309 }
310
311 pub fn is_identity(&self) -> bool
313 where
314 <T as TryFrom<usize>>::Error: fmt::Debug,
315 {
316 self.lehmer_index(None) == 0
317 }
318
319 pub fn lehmer(&self, count_ones_opt: Option<&HashMap<BitVec<T, Lsb0>, T>>) -> Vec<T>
331 where
332 <T as TryFrom<usize>>::Error: fmt::Debug,
333 {
334 let mut bv: BitVec<T, Lsb0> = bitvec![T, Lsb0; 0; self.rank().into()];
335 let n = self.rank();
336 self.image
337 .iter()
338 .enumerate()
339 .map(|(i, &k)| {
340 let flipped_bv_k = !bv[k.into()];
341 bv.set(k.into(), flipped_bv_k);
342 if i == 0 {
343 k
344 } else if i == (n - T::one()).into() {
345 T::zero()
346 } else {
347 let mut bv_k = bv.clone();
348 bv_k.shift_right((n - k).into());
349 k - if let Some(count_ones) = count_ones_opt {
350 *(count_ones.get(&bv_k).unwrap_or_else(|| {
351 panic!("Unable to count the number of ones in `{bv}`.")
352 }))
353 } else {
354 T::try_from(bv_k.count_ones())
355 .expect("Unable to convert the number of ones to `u8`.")
356 }
357 }
358 })
359 .collect::<Vec<T>>()
360 }
361
362 pub fn lehmer_index(&self, count_ones_opt: Option<&HashMap<BitVec<T, Lsb0>, T>>) -> usize
377 where
378 <T as TryFrom<usize>>::Error: fmt::Debug,
379 {
380 let lehmer = self.lehmer(count_ones_opt);
381 let n = self.rank().into() - 1;
382 if n == 0 {
383 0
384 } else {
385 lehmer
386 .into_iter()
387 .enumerate()
388 .map(|(i, l)| {
389 l.into()
390 * (n - i).checked_factorial().unwrap_or_else(|| {
391 panic!("The factorial of `{}` cannot be correctly computed.", n - i)
392 })
393 })
394 .sum()
395 }
396 }
397}
398
399impl<T: PermutationRank + fmt::Display> fmt::Display for Permutation<T> {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 write!(
409 f,
410 "π({})",
411 self.image
412 .iter()
413 .map(|i| i.to_string())
414 .collect::<Vec<_>>()
415 .join(".")
416 )
417 }
418}
419
420impl<T: PermutationRank> Mul<&'_ Permutation<T>> for &Permutation<T>
424where
425 std::ops::Range<T>: Iterator + DoubleEndedIterator,
426 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
427 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
428 <T as TryFrom<usize>>::Error: fmt::Debug,
429 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
430{
431 type Output = Permutation<T>;
432
433 fn mul(self, rhs: &Permutation<T>) -> Self::Output {
434 assert_eq!(
435 self.rank(),
436 rhs.rank(),
437 "The ranks of two multiplying permutations do not match."
438 );
439 Self::Output::builder()
440 .image(
441 rhs.image
442 .iter()
443 .map(|&ri| self.image[ri.into()])
444 .collect::<Vec<T>>(),
445 )
446 .build()
447 .expect("Unable to construct a product `Permutation`.")
448 }
449}
450
451impl<T: PermutationRank> Mul<&'_ Permutation<T>> for Permutation<T>
452where
453 std::ops::Range<T>: Iterator + DoubleEndedIterator,
454 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
455 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
456 <T as TryFrom<usize>>::Error: fmt::Debug,
457 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
458{
459 type Output = Permutation<T>;
460
461 fn mul(self, rhs: &Permutation<T>) -> Self::Output {
462 &self * rhs
463 }
464}
465
466impl<T: PermutationRank> Mul<Permutation<T>> for Permutation<T>
467where
468 std::ops::Range<T>: Iterator + DoubleEndedIterator,
469 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
470 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
471 <T as TryFrom<usize>>::Error: fmt::Debug,
472 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
473{
474 type Output = Permutation<T>;
475
476 fn mul(self, rhs: Permutation<T>) -> Self::Output {
477 &self * &rhs
478 }
479}
480
481impl<T: PermutationRank> Mul<Permutation<T>> for &Permutation<T>
482where
483 std::ops::Range<T>: Iterator + DoubleEndedIterator,
484 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
485 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
486 <T as TryFrom<usize>>::Error: fmt::Debug,
487 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
488{
489 type Output = Permutation<T>;
490
491 fn mul(self, rhs: Permutation<T>) -> Self::Output {
492 self * &rhs
493 }
494}
495
496impl<T: PermutationRank> Inv for &Permutation<T>
500where
501 std::ops::Range<T>: Iterator + DoubleEndedIterator,
502 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
503 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
504 <T as TryFrom<usize>>::Error: fmt::Debug,
505 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
506{
507 type Output = Permutation<T>;
508
509 fn inv(self) -> Self::Output {
510 let mut image_inv = (T::zero()..self.rank()).collect::<Vec<T>>();
511 image_inv.sort_by_key(|&i| self.image[i.into()]);
512 Self::Output::builder()
513 .image(image_inv)
514 .build()
515 .expect("Unable to construct an inverse `Permutation`.")
516 }
517}
518
519impl<T: PermutationRank> Inv for Permutation<T>
520where
521 std::ops::Range<T>: Iterator + DoubleEndedIterator,
522 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
523 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
524 <T as TryFrom<usize>>::Error: fmt::Debug,
525 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
526{
527 type Output = Permutation<T>;
528
529 fn inv(self) -> Self::Output {
530 (&self).inv()
531 }
532}
533
534impl<T: PermutationRank> Pow<i32> for &Permutation<T>
538where
539 std::ops::Range<T>: Iterator + DoubleEndedIterator,
540 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
541 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
542 <T as TryFrom<usize>>::Error: fmt::Debug,
543 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
544{
545 type Output = Permutation<T>;
546
547 fn pow(self, rhs: i32) -> Self::Output {
548 if rhs == 0 {
549 Self::Output::builder()
550 .image((T::zero()..self.rank()).collect::<Vec<T>>())
551 .build()
552 .expect("Unable to construct an identity `Permutation`.")
553 } else if rhs > 0 {
554 self * self.pow(rhs - 1)
555 } else {
556 let rhs_p = -rhs;
557 (self * self.pow(rhs_p - 1)).inv()
558 }
559 }
560}
561
562impl<T: PermutationRank> Pow<i32> for Permutation<T>
563where
564 std::ops::Range<T>: Iterator + DoubleEndedIterator,
565 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
566 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
567 <T as TryFrom<usize>>::Error: fmt::Debug,
568 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
569{
570 type Output = Permutation<T>;
571
572 fn pow(self, rhs: i32) -> Self::Output {
573 (&self).pow(rhs)
574 }
575}
576
577impl<T: PermutationRank + fmt::Display> FiniteOrder for Permutation<T>
581where
582 u32: From<T>,
583 std::ops::Range<T>: Iterator + DoubleEndedIterator,
584 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
585 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
586 <T as TryFrom<usize>>::Error: fmt::Debug,
587 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
588{
589 type Int = u32;
590
591 fn order(&self) -> Self::Int {
594 u32::try_from(
595 self.cycle_pattern()
596 .iter()
597 .cloned()
598 .reduce(lcm)
599 .unwrap_or_else(|| {
600 panic!("Unable to determine the permutation order of `{self}`.")
601 }),
602 )
603 .expect("Unable to convert the permutation order to `u32`.")
604 }
605}
606
607pub(crate) fn permute_inplace<T>(vec: &mut Vec<T>, perm: &Permutation<usize>) {
617 assert_eq!(
618 perm.rank(),
619 vec.len(),
620 "The permutation rank does not match the number of items in the vector."
621 );
622 let mut image = perm.image().clone();
623 for idx in 0..vec.len() {
624 if image[idx] != idx {
625 let mut current_idx = idx;
626 loop {
627 let target_idx = image[current_idx];
628 image[current_idx] = current_idx;
629 if image[target_idx] == target_idx {
630 break;
631 }
632 vec.swap(current_idx, target_idx);
633 current_idx = target_idx;
634 }
635 }
636 }
637}