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!("The Lehmer encode length is larger than the rank of the permutation."))
238 } else {
239 while lehmer.len() < rank.into() {
240 lehmer.push_front(T::zero());
241 }
242 Self::from_lehmer(lehmer.into_iter().collect::<Vec<_>>())
243 }
244 }
245
246 pub fn rank(&self) -> T {
248 T::try_from(self.image.len()).unwrap_or_else(|_| {
249 panic!(
250 "The rank of `{:?}` is too large to be represented as `u8`.",
251 self.image
252 )
253 })
254 }
255
256 pub fn image(&self) -> &Vec<T> {
259 &self.image
260 }
261
262 pub fn cycles(&self) -> Vec<Vec<T>>
264 where
265 std::ops::Range<T>: Iterator + DoubleEndedIterator,
266 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
267 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
268 {
269 let image = &self.image;
270 let rank = self.rank();
271 let mut remaining_indices = (T::zero()..rank).rev().collect::<IndexSet<T>>();
272 let mut cycles: Vec<Vec<T>> = Vec::with_capacity(rank.into());
273 while !remaining_indices.is_empty() {
274 let start = remaining_indices
275 .pop()
276 .expect("`remaining_indices` should not be empty.");
277 let mut cycle: Vec<T> = Vec::with_capacity(remaining_indices.len());
278 cycle.push(start);
279 let mut idx = start;
280 while image[idx.into()] != start {
281 idx = image[idx.into()];
282 assert!(remaining_indices.shift_remove(&idx));
283 cycle.push(idx);
284 }
285 cycle.shrink_to_fit();
286 cycles.push(cycle);
287 }
288 cycles.shrink_to_fit();
289 cycles.sort_by_key(|cycle| (!cycle.len(), cycle.clone()));
290 cycles
291 }
292
293 pub fn cycle_pattern(&self) -> Vec<T>
295 where
296 <T as TryFrom<usize>>::Error: fmt::Debug,
297 std::ops::Range<T>: Iterator + DoubleEndedIterator,
298 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
299 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
300 {
301 self.cycles()
302 .iter()
303 .map(|cycle| {
304 T::try_from(cycle.len()).expect("Some cycle lengths are too long for `u8`.")
305 })
306 .collect::<Vec<T>>()
307 }
308
309 pub fn is_identity(&self) -> bool
311 where
312 <T as TryFrom<usize>>::Error: fmt::Debug,
313 {
314 self.lehmer_index(None) == 0
315 }
316
317 pub fn lehmer(&self, count_ones_opt: Option<&HashMap<BitVec<T, Lsb0>, T>>) -> Vec<T>
329 where
330 <T as TryFrom<usize>>::Error: fmt::Debug,
331 {
332 let mut bv: BitVec<T, Lsb0> = bitvec![T, Lsb0; 0; self.rank().into()];
333 let n = self.rank();
334 self.image
335 .iter()
336 .enumerate()
337 .map(|(i, &k)| {
338 let flipped_bv_k = !bv[k.into()];
339 bv.set(k.into(), flipped_bv_k);
340 if i == 0 {
341 k
342 } else if i == (n - T::one()).into() {
343 T::zero()
344 } else {
345 let mut bv_k = bv.clone();
346 bv_k.shift_right((n - k).into());
347 k - if let Some(count_ones) = count_ones_opt {
348 *(count_ones.get(&bv_k).unwrap_or_else(|| {
349 panic!("Unable to count the number of ones in `{bv}`.")
350 }))
351 } else {
352 T::try_from(bv_k.count_ones())
353 .expect("Unable to convert the number of ones to `u8`.")
354 }
355 }
356 })
357 .collect::<Vec<T>>()
358 }
359
360 pub fn lehmer_index(&self, count_ones_opt: Option<&HashMap<BitVec<T, Lsb0>, T>>) -> usize
375 where
376 <T as TryFrom<usize>>::Error: fmt::Debug,
377 {
378 let lehmer = self.lehmer(count_ones_opt);
379 let n = self.rank().into() - 1;
380 if n == 0 {
381 0
382 } else {
383 lehmer
384 .into_iter()
385 .enumerate()
386 .map(|(i, l)| {
387 l.into()
388 * (n - i).checked_factorial().unwrap_or_else(|| {
389 panic!("The factorial of `{}` cannot be correctly computed.", n - i)
390 })
391 })
392 .sum()
393 }
394 }
395}
396
397impl<T: PermutationRank + fmt::Display> fmt::Display for Permutation<T> {
405 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406 write!(
407 f,
408 "π({})",
409 self.image
410 .iter()
411 .map(|i| i.to_string())
412 .collect::<Vec<_>>()
413 .join(".")
414 )
415 }
416}
417
418impl<T: PermutationRank> Mul<&'_ Permutation<T>> for &Permutation<T>
422where
423 std::ops::Range<T>: Iterator + DoubleEndedIterator,
424 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
425 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
426 <T as TryFrom<usize>>::Error: fmt::Debug,
427 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
428{
429 type Output = Permutation<T>;
430
431 fn mul(self, rhs: &Permutation<T>) -> Self::Output {
432 assert_eq!(
433 self.rank(),
434 rhs.rank(),
435 "The ranks of two multiplying permutations do not match."
436 );
437 Self::Output::builder()
438 .image(
439 rhs.image
440 .iter()
441 .map(|&ri| self.image[ri.into()])
442 .collect::<Vec<T>>(),
443 )
444 .build()
445 .expect("Unable to construct a product `Permutation`.")
446 }
447}
448
449impl<T: PermutationRank> Mul<&'_ Permutation<T>> for Permutation<T>
450where
451 std::ops::Range<T>: Iterator + DoubleEndedIterator,
452 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
453 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
454 <T as TryFrom<usize>>::Error: fmt::Debug,
455 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
456{
457 type Output = Permutation<T>;
458
459 fn mul(self, rhs: &Permutation<T>) -> Self::Output {
460 &self * rhs
461 }
462}
463
464impl<T: PermutationRank> Mul<Permutation<T>> for Permutation<T>
465where
466 std::ops::Range<T>: Iterator + DoubleEndedIterator,
467 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
468 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
469 <T as TryFrom<usize>>::Error: fmt::Debug,
470 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
471{
472 type Output = Permutation<T>;
473
474 fn mul(self, rhs: Permutation<T>) -> Self::Output {
475 &self * &rhs
476 }
477}
478
479impl<T: PermutationRank> Mul<Permutation<T>> for &Permutation<T>
480where
481 std::ops::Range<T>: Iterator + DoubleEndedIterator,
482 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
483 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
484 <T as TryFrom<usize>>::Error: fmt::Debug,
485 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
486{
487 type Output = Permutation<T>;
488
489 fn mul(self, rhs: Permutation<T>) -> Self::Output {
490 self * &rhs
491 }
492}
493
494impl<T: PermutationRank> Inv for &Permutation<T>
498where
499 std::ops::Range<T>: Iterator + DoubleEndedIterator,
500 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
501 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
502 <T as TryFrom<usize>>::Error: fmt::Debug,
503 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
504{
505 type Output = Permutation<T>;
506
507 fn inv(self) -> Self::Output {
508 let mut image_inv = (T::zero()..self.rank()).collect::<Vec<T>>();
509 image_inv.sort_by_key(|&i| self.image[i.into()]);
510 Self::Output::builder()
511 .image(image_inv)
512 .build()
513 .expect("Unable to construct an inverse `Permutation`.")
514 }
515}
516
517impl<T: PermutationRank> Inv for Permutation<T>
518where
519 std::ops::Range<T>: Iterator + DoubleEndedIterator,
520 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
521 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
522 <T as TryFrom<usize>>::Error: fmt::Debug,
523 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
524{
525 type Output = Permutation<T>;
526
527 fn inv(self) -> Self::Output {
528 (&self).inv()
529 }
530}
531
532impl<T: PermutationRank> Pow<i32> for &Permutation<T>
536where
537 std::ops::Range<T>: Iterator + DoubleEndedIterator,
538 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
539 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
540 <T as TryFrom<usize>>::Error: fmt::Debug,
541 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
542{
543 type Output = Permutation<T>;
544
545 fn pow(self, rhs: i32) -> Self::Output {
546 if rhs == 0 {
547 Self::Output::builder()
548 .image((T::zero()..self.rank()).collect::<Vec<T>>())
549 .build()
550 .expect("Unable to construct an identity `Permutation`.")
551 } else if rhs > 0 {
552 self * self.pow(rhs - 1)
553 } else {
554 let rhs_p = -rhs;
555 (self * self.pow(rhs_p - 1)).inv()
556 }
557 }
558}
559
560impl<T: PermutationRank> Pow<i32> for Permutation<T>
561where
562 std::ops::Range<T>: Iterator + DoubleEndedIterator,
563 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
564 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
565 <T as TryFrom<usize>>::Error: fmt::Debug,
566 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
567{
568 type Output = Permutation<T>;
569
570 fn pow(self, rhs: i32) -> Self::Output {
571 (&self).pow(rhs)
572 }
573}
574
575impl<T: PermutationRank + fmt::Display> FiniteOrder for Permutation<T>
579where
580 u32: From<T>,
581 std::ops::Range<T>: Iterator + DoubleEndedIterator,
582 Vec<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
583 VecDeque<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
584 <T as TryFrom<usize>>::Error: fmt::Debug,
585 IndexSet<T>: FromIterator<<std::ops::Range<T> as Iterator>::Item>,
586{
587 type Int = u32;
588
589 fn order(&self) -> Self::Int {
592 u32::try_from(
593 self.cycle_pattern()
594 .iter()
595 .cloned()
596 .reduce(lcm)
597 .unwrap_or_else(|| {
598 panic!("Unable to determine the permutation order of `{self}`.")
599 }),
600 )
601 .expect("Unable to convert the permutation order to `u32`.")
602 }
603}
604
605pub(crate) fn permute_inplace<T>(vec: &mut Vec<T>, perm: &Permutation<usize>) {
615 assert_eq!(
616 perm.rank(),
617 vec.len(),
618 "The permutation rank does not match the number of items in the vector."
619 );
620 let mut image = perm.image().clone();
621 for idx in 0..vec.len() {
622 if image[idx] != idx {
623 let mut current_idx = idx;
624 loop {
625 let target_idx = image[current_idx];
626 image[current_idx] = current_idx;
627 if image[target_idx] == target_idx {
628 break;
629 }
630 vec.swap(current_idx, target_idx);
631 current_idx = target_idx;
632 }
633 }
634 }
635}