1use std::collections::HashSet;
4use std::fmt;
5use std::hash::Hash;
6use std::ops::Mul;
7
8use anyhow::{self, ensure, format_err};
9use derive_builder::Builder;
10use indexmap::IndexMap;
11use itertools::Itertools;
12use ndarray::{s, Array2};
13use num_traits::Inv;
14use serde::{de::DeserializeOwned, Deserialize, Serialize};
15
16use crate::chartab::chartab_group::CharacterProperties;
17use crate::chartab::chartab_symbols::{
18 CollectionSymbol, LinearSpaceSymbol, ReducibleLinearSpaceSymbol,
19};
20use crate::group::{
21 FiniteOrder, GroupProperties, HasUnitarySubgroup, MagneticRepresentedGroup,
22 UnitaryRepresentedGroup,
23};
24
25pub trait ClassProperties: GroupProperties
31where
32 Self::ClassSymbol: CollectionSymbol<CollectionElement = Self::GroupElement>,
33 <Self as GroupProperties>::GroupElement: Inv<Output = <Self as GroupProperties>::GroupElement>,
34{
35 type ClassSymbol;
37
38 fn compute_class_structure(&mut self) -> Result<(), anyhow::Error>;
44
45 #[must_use]
57 fn get_cc_index(&self, cc_idx: usize) -> Option<&HashSet<usize>>;
58
59 #[must_use]
71 fn get_cc_of_element_index(&self, e_idx: usize) -> Option<usize>;
72
73 #[must_use]
84 fn get_cc_transversal(&self, cc_idx: usize) -> Option<Self::GroupElement>;
85
86 #[must_use]
97 fn get_index_of_cc_symbol(&self, cc_sym: &Self::ClassSymbol) -> Option<usize>;
98
99 #[must_use]
110 fn get_cc_symbol_of_index(&self, cc_idx: usize) -> Option<Self::ClassSymbol>;
111
112 #[must_use]
123 fn filter_cc_symbols<P: FnMut(&Self::ClassSymbol) -> bool>(
124 &self,
125 predicate: P,
126 ) -> Vec<Self::ClassSymbol>;
127
128 fn set_class_symbols(&mut self, cc_symbols: &[Self::ClassSymbol]);
134
135 #[must_use]
147 fn get_inverse_cc(&self, cc_idx: usize) -> Option<usize>;
148
149 #[must_use]
151 fn class_number(&self) -> usize;
152
153 #[must_use]
163 fn class_size(&self, cc_idx: usize) -> Option<usize>;
164
165 #[must_use]
189 fn class_matrix(&self, ctb_opt: Option<&Array2<usize>>, r: usize) -> Array2<usize> {
190 let class_number = self.class_number();
191 let mut nmat_r = Array2::<usize>::zeros((class_number, class_number));
192 let class_r = &self
193 .get_cc_index(r)
194 .unwrap_or_else(|| panic!("Conjugacy class index `{r}` not found."));
195
196 if let Some(ctb) = ctb_opt {
197 log::debug!("Computing class matrix N{r} using the Cayley table...");
198 (0..class_number).for_each(|t| {
199 let class_t = self
200 .get_cc_index(t)
201 .unwrap_or_else(|| panic!("Conjugacy class index `{t}` not found."));
202 let rep_z_idx = *class_t
203 .iter()
204 .next()
205 .expect("No conjugacy classes can be empty.");
206 for &x_idx in class_r.iter() {
207 let x_inv_idx = ctb
208 .slice(s![.., x_idx])
209 .iter()
210 .position(|&x| x == 0)
211 .unwrap_or_else(|| {
212 panic!("The inverse of element index `{x_idx}` cannot be found.")
213 });
214 let y_idx = ctb[[x_inv_idx, rep_z_idx]];
215 let s = self.get_cc_of_element_index(y_idx).unwrap_or_else(|| {
216 panic!("Conjugacy class of element index `{y_idx}` not found.")
217 });
218 nmat_r[[s, t]] += 1;
219 }
220 });
221 } else {
222 log::debug!("Computing class matrix N{r} without the Cayley table...");
223 (0..class_number).for_each(|t| {
224 let class_t = self
225 .get_cc_index(t)
226 .unwrap_or_else(|| panic!("Conjugacy class index `{t}` not found."));
227 let rep_z_idx = *class_t
228 .iter()
229 .next()
230 .expect("No conjugacy classes can be empty.");
231 let z = self
232 .get_index(rep_z_idx)
233 .unwrap_or_else(|| panic!("No element with index `{rep_z_idx}` found."));
234 for &x_idx in class_r.iter() {
235 let x = self
236 .get_index(x_idx)
237 .unwrap_or_else(|| panic!("No element with index `{x_idx}` found."));
238 let y = x.clone().inv() * z.clone();
239 let y_idx = self
240 .get_index_of(&y)
241 .unwrap_or_else(|| panic!("Element `{y:?}` not found in this group."));
242 let s = self
243 .get_cc_of_element_index(y_idx)
244 .unwrap_or_else(|| panic!("Conjugacy class of element `{y:?}` not found."));
245 nmat_r[[s, t]] += 1;
246 }
247 });
248 };
249
250 log::debug!("Computing class matrix N{r}... Done.");
251 nmat_r
252 }
253}
254
255pub trait ClassPropertiesSummary: ClassProperties
257where
258 <Self as GroupProperties>::GroupElement: fmt::Display,
259{
260 fn class_transversal_to_string(&self) -> String {
262 let cc_transversal = (0..self.class_number())
263 .filter_map(|i| {
264 let cc_opt = self.get_cc_symbol_of_index(i);
265 let op_opt = self.get_cc_transversal(i);
266 match (cc_opt, op_opt) {
267 (Some(cc), Some(op)) => Some((cc.to_string(), op.to_string())),
268 _ => None,
269 }
270 })
271 .collect::<Vec<_>>();
272 let cc_width = cc_transversal
273 .iter()
274 .map(|(cc, _)| cc.chars().count())
275 .max()
276 .unwrap_or(5)
277 .max(5);
278 let op_width = cc_transversal
279 .iter()
280 .map(|(_, op)| op.chars().count())
281 .max()
282 .unwrap_or(14)
283 .max(14);
284
285 let divider = "┈".repeat(cc_width + op_width + 4);
286 let header = format!(" {:<cc_width$} {:<}", "Class", "Representative");
287 let body = Itertools::intersperse(
288 cc_transversal
289 .iter()
290 .map(|(cc, op)| format!(" {:<cc_width$} {:<}", cc, op)),
291 "\n".to_string(),
292 )
293 .collect::<String>();
294
295 Itertools::intersperse(
296 [divider.clone(), header, divider.clone(), body, divider].into_iter(),
297 "\n".to_string(),
298 )
299 .collect::<String>()
300 }
301}
302
303impl<G> ClassPropertiesSummary for G
305where
306 G: ClassProperties,
307 G::GroupElement: fmt::Display,
308{
309}
310
311#[derive(Builder, Clone, Serialize, Deserialize)]
318pub(super) struct EagerClassStructure<T, ClassSymbol>
319where
320 T: Mul<Output = T> + Inv<Output = T> + Hash + Eq + Clone + Sync + fmt::Debug + FiniteOrder,
321 ClassSymbol: CollectionSymbol<CollectionElement = T>,
322{
323 conjugacy_classes: Vec<HashSet<usize>>,
330
331 element_to_conjugacy_classes: Vec<Option<usize>>,
337
338 #[builder(setter(custom))]
343 conjugacy_class_transversal: Vec<usize>,
344
345 #[builder(setter(custom))]
350 conjugacy_class_symbols: IndexMap<ClassSymbol, usize>,
351
352 #[builder(setter(custom))]
357 inverse_conjugacy_classes: Vec<usize>,
358}
359
360impl<T, ClassSymbol> EagerClassStructureBuilder<T, ClassSymbol>
361where
362 T: Mul<Output = T> + Inv<Output = T> + Hash + Eq + Clone + Sync + fmt::Debug + FiniteOrder,
363 ClassSymbol: CollectionSymbol<CollectionElement = T>,
364{
365 fn conjugacy_class_transversal(&mut self) -> &mut Self {
366 self.conjugacy_class_transversal = Some(
367 self.conjugacy_classes
368 .as_ref()
369 .expect("Conjugacy classes have not been found.")
370 .iter()
371 .map(|cc| *cc.iter().min().expect("No conjugacy classes can be empty."))
372 .collect::<Vec<usize>>(),
373 );
374 self
375 }
376
377 fn conjugacy_class_symbols(
378 &mut self,
379 group: &impl GroupProperties<GroupElement = T>,
380 ) -> &mut Self {
381 log::debug!("Assigning generic class symbols...");
382 let class_sizes: Vec<_> = self
383 .conjugacy_classes
384 .as_ref()
385 .expect("Conjugacy classes have not been found.")
386 .iter()
387 .map(HashSet::len)
388 .collect();
389 let class_symbols_iter = self
390 .conjugacy_class_transversal
391 .as_ref()
392 .expect("A conjugacy class transversal has not been found.")
393 .iter()
394 .enumerate()
395 .map(|(i, &rep_ele_index)| {
396 let rep_ele = group.get_index(rep_ele_index).unwrap_or_else(|| {
397 panic!("Element with index {rep_ele_index} cannot be retrieved.")
398 });
399 (
400 ClassSymbol::from_reps(
401 format!("{}||K{i}||", class_sizes[i]).as_str(),
402 Some(vec![rep_ele]),
403 )
404 .unwrap_or_else(|_| {
405 panic!(
406 "Unable to construct a class symbol from `{}||K{i}||`.",
407 class_sizes[i]
408 )
409 }),
410 i,
411 )
412 });
413 self.conjugacy_class_symbols = Some(class_symbols_iter.collect::<IndexMap<_, _>>());
414 log::debug!("Assigning generic class symbols... Done.");
415 self
416 }
417
418 fn inverse_conjugacy_classes(&mut self, ctb: &Array2<usize>) -> &mut Self {
419 log::debug!("Finding inverse conjugacy classes...");
420 let mut iccs: Vec<_> = self
421 .conjugacy_classes
422 .as_ref()
423 .expect("Conjugacy classes have not been found.")
424 .iter()
425 .map(|_| 0usize)
426 .collect();
427 let class_number = self
428 .conjugacy_classes
429 .as_ref()
430 .expect("Conjugacy classes have not been found.")
431 .len();
432 let mut remaining_classes: HashSet<_> = (1..class_number).collect();
433 while !remaining_classes.is_empty() {
434 let class_index = *remaining_classes
435 .iter()
436 .next()
437 .expect("Unexpected empty `remaining_classes`.");
438 remaining_classes.remove(&class_index);
439 let g = *self
440 .conjugacy_classes
441 .as_ref()
442 .expect("Conjugacy classes have not been found.")[class_index]
443 .iter()
444 .next()
445 .expect("No conjugacy classes can be empty.");
446 let g_inv = ctb
447 .slice(s![g, ..])
448 .iter()
449 .position(|&x| x == 0)
450 .unwrap_or_else(|| {
451 panic!("No identity element can be found in row `{g}` of Cayley table.")
452 });
453 let inv_class_index = self
454 .element_to_conjugacy_classes
455 .as_ref()
456 .expect("Map from element to conjugacy class has not been found.")[g_inv]
457 .unwrap_or_else(|| {
458 panic!("Element index `{g_inv}` does not have a conjugacy class.",)
459 });
460 iccs[class_index] = inv_class_index;
461 if remaining_classes.contains(&inv_class_index) {
462 remaining_classes.remove(&inv_class_index);
463 iccs[inv_class_index] = class_index;
464 }
465 }
466 assert!(iccs.iter().skip(1).all(|&x| x > 0));
467 self.inverse_conjugacy_classes = Some(iccs);
468 log::debug!("Finding inverse conjugacy classes... Done.");
469 self
470 }
471
472 fn custom_inverse_conjugacy_classes(&mut self, iccs: Vec<usize>) -> &mut Self {
473 log::debug!("Setting custom inverse conjugacy classes...");
474 assert_eq!(
475 iccs.len(),
476 self.conjugacy_classes
477 .as_ref()
478 .expect("Conjugacy classes have not been set.")
479 .len(),
480 "The provided inverse conjugacy class structure does not have the correct class number."
481 );
482 self.inverse_conjugacy_classes = Some(iccs);
483 log::debug!("Setting custom inverse conjugacy classes... Done.");
484 self
485 }
486}
487
488impl<T, ClassSymbol> EagerClassStructure<T, ClassSymbol>
489where
490 T: Mul<Output = T> + Inv<Output = T> + Hash + Eq + Clone + Sync + fmt::Debug + FiniteOrder,
491 ClassSymbol: CollectionSymbol<CollectionElement = T>,
492{
493 fn builder() -> EagerClassStructureBuilder<T, ClassSymbol> {
495 EagerClassStructureBuilder::<T, ClassSymbol>::default()
496 }
497
498 fn new(
513 group: &impl GroupProperties<GroupElement = T>,
514 conjugacy_classes: Vec<HashSet<usize>>,
515 element_to_conjugacy_classes: Vec<Option<usize>>,
516 ) -> Self {
517 let ctb_opt = group.cayley_table();
518 let ctb = ctb_opt
519 .as_ref()
520 .expect("Cayley table not found for this group.");
521 Self::builder()
522 .conjugacy_classes(conjugacy_classes)
523 .element_to_conjugacy_classes(element_to_conjugacy_classes)
524 .conjugacy_class_transversal()
525 .conjugacy_class_symbols(group)
526 .inverse_conjugacy_classes(ctb)
527 .build()
528 .expect("Unable to construct a `EagerClassStructure`.")
529 }
530
531 fn new_no_ctb(
545 group: &impl GroupProperties<GroupElement = T>,
546 conjugacy_classes: Vec<HashSet<usize>>,
547 element_to_conjugacy_classes: Vec<Option<usize>>,
548 inverse_conjugacy_classes: Vec<usize>,
549 ) -> Self {
550 Self::builder()
551 .conjugacy_classes(conjugacy_classes)
552 .element_to_conjugacy_classes(element_to_conjugacy_classes)
553 .conjugacy_class_transversal()
554 .conjugacy_class_symbols(group)
555 .custom_inverse_conjugacy_classes(inverse_conjugacy_classes)
556 .build()
557 .expect("Unable to construct a `EagerClassStructure`.")
558 }
559
560 #[must_use]
562 fn class_number(&self) -> usize {
563 self.conjugacy_classes.len()
564 }
565
566 fn set_class_symbols(&mut self, csyms: &[ClassSymbol]) {
576 assert_eq!(csyms.len(), self.conjugacy_classes.len());
577 self.conjugacy_class_symbols = csyms
578 .iter()
579 .enumerate()
580 .map(|(i, cc)| (cc.clone(), i))
581 .collect::<IndexMap<_, _>>();
582 }
583}
584
585impl<T, RowSymbol, ColSymbol> ClassProperties for UnitaryRepresentedGroup<T, RowSymbol, ColSymbol>
594where
595 T: Mul<Output = T> + Inv<Output = T> + Hash + Eq + Clone + Sync + fmt::Debug + FiniteOrder,
596 for<'a, 'b> &'b T: Mul<&'a T, Output = T>,
597 <Self as GroupProperties>::GroupElement: Inv,
598 RowSymbol: LinearSpaceSymbol,
599 ColSymbol: CollectionSymbol<CollectionElement = T>,
600{
601 type ClassSymbol = ColSymbol;
602
603 fn compute_class_structure(&mut self) -> Result<(), anyhow::Error> {
610 log::debug!("Finding unitary conjugacy classes...");
611 let order = self.abstract_group.order();
612 let (ccs, e2ccs) = if self.abstract_group.is_abelian() {
613 log::debug!("Abelian group found.");
614 (
616 (0usize..order)
617 .map(|i| HashSet::from([i]))
618 .collect::<Vec<_>>(),
619 (0usize..order).map(Some).collect::<Vec<_>>(),
620 )
621 } else {
622 log::debug!("Non-Abelian group found.");
624 let mut ccs: Vec<HashSet<usize>> = vec![HashSet::from([0usize])];
625 let mut e2ccs = vec![0usize; order];
626 let mut remaining_elements: HashSet<usize> = (1usize..order).collect();
627 let ctb = self.abstract_group.cayley_table.as_ref().expect(
628 "Cayley table required for computing unitary class structure, but not found.",
629 );
630
631 while !remaining_elements.is_empty() {
632 let g = *remaining_elements
634 .iter()
635 .next()
636 .expect("Unexpected empty `remaining_elements`.");
637 let mut cur_cc = HashSet::from([g]);
638 for s in 0usize..order {
639 let sg = ctb[[s, g]];
640 let ctb_xs = ctb.slice(s![.., s]);
641 let h = ctb_xs.iter().position(|&x| x == sg).ok_or_else(|| {
642 format_err!(
643 "No element `{sg}` can be found in column `{s}` of Cayley table."
644 )
645 })?;
646 if remaining_elements.contains(&h) {
647 remaining_elements.remove(&h);
648 cur_cc.insert(h);
649 }
650 }
651 ccs.push(cur_cc);
652 }
653 ccs.sort_by_key(|cc| {
654 *cc.iter()
655 .min()
656 .expect("Unable to find the minimum element index in one conjugacy class.")
657 });
658 ccs.iter().enumerate().for_each(|(i, cc)| {
659 cc.iter().for_each(|&j| e2ccs[j] = i);
660 });
661 assert!(e2ccs.iter().skip(1).all(|&x| x > 0));
662 (ccs, e2ccs.iter().map(|&i| Some(i)).collect::<Vec<_>>())
663 };
664
665 let class_structure =
666 EagerClassStructure::<T, Self::ClassSymbol>::new(&self.abstract_group, ccs, e2ccs);
667 self.class_structure = Some(class_structure);
668 log::debug!("Finding unitary conjugacy classes... Done.");
669 Ok(())
670 }
671
672 fn get_cc_index(&self, cc_idx: usize) -> Option<&HashSet<usize>> {
673 self.class_structure
674 .as_ref()
675 .expect("No class structure found.")
676 .conjugacy_classes
677 .get(cc_idx)
678 }
679
680 fn get_cc_of_element_index(&self, e_idx: usize) -> Option<usize> {
681 self.class_structure
682 .as_ref()
683 .expect("No class structure found.")
684 .element_to_conjugacy_classes[e_idx]
685 }
686
687 fn get_cc_transversal(&self, cc_idx: usize) -> Option<Self::GroupElement> {
688 self.class_structure
689 .as_ref()
690 .expect("No class structure found.")
691 .conjugacy_class_transversal
692 .get(cc_idx)
693 .and_then(|&i| self.get_index(i))
694 }
695
696 fn get_index_of_cc_symbol(&self, cc_sym: &Self::ClassSymbol) -> Option<usize> {
697 self.class_structure
698 .as_ref()
699 .expect("No class structure found.")
700 .conjugacy_class_symbols
701 .get_index_of(cc_sym)
702 }
703
704 fn get_cc_symbol_of_index(&self, cc_idx: usize) -> Option<Self::ClassSymbol> {
705 self.class_structure
706 .as_ref()
707 .expect("No class structure found.")
708 .conjugacy_class_symbols
709 .get_index(cc_idx)
710 .map(|(cc_sym, _)| cc_sym.clone())
711 }
712
713 fn filter_cc_symbols<P: FnMut(&Self::ClassSymbol) -> bool>(
714 &self,
715 predicate: P,
716 ) -> Vec<Self::ClassSymbol> {
717 self.class_structure
718 .as_ref()
719 .expect("No class structure found.")
720 .conjugacy_class_symbols
721 .keys()
722 .cloned()
723 .filter(predicate)
724 .collect::<Vec<_>>()
725 }
726
727 fn set_class_symbols(&mut self, cc_symbols: &[Self::ClassSymbol]) {
728 self.class_structure
729 .as_mut()
730 .unwrap()
731 .set_class_symbols(cc_symbols);
732 }
733
734 fn get_inverse_cc(&self, cc_idx: usize) -> Option<usize> {
735 self.class_structure
736 .as_ref()
737 .expect("No class structure found.")
738 .inverse_conjugacy_classes
739 .get(cc_idx)
740 .cloned()
741 }
742
743 fn class_number(&self) -> usize {
744 self.class_structure
745 .as_ref()
746 .expect("No class structure found.")
747 .class_number()
748 }
749
750 fn class_size(&self, cc_idx: usize) -> Option<usize> {
751 self.class_structure
752 .as_ref()
753 .expect("No class structure found.")
754 .conjugacy_classes
755 .get(cc_idx)
756 .map(|cc| cc.len())
757 }
758}
759
760impl<T, UG, RowSymbol> ClassProperties for MagneticRepresentedGroup<T, UG, RowSymbol>
765where
766 T: Mul<Output = T> + Inv<Output = T> + Hash + Eq + Clone + Sync + fmt::Debug + FiniteOrder,
767 for<'a, 'b> &'b T: Mul<&'a T, Output = T>,
768 <Self as GroupProperties>::GroupElement: Inv,
769 UG: Clone + GroupProperties<GroupElement = T> + CharacterProperties,
770 RowSymbol: ReducibleLinearSpaceSymbol<Subspace = UG::RowSymbol> + Serialize + DeserializeOwned,
771 <UG as ClassProperties>::ClassSymbol: Serialize + DeserializeOwned,
772 <UG as CharacterProperties>::CharTab: Serialize + DeserializeOwned,
773{
774 type ClassSymbol = UG::ClassSymbol;
775
776 fn compute_class_structure(&mut self) -> Result<(), anyhow::Error> {
788 log::debug!("Finding magnetic conjugacy classes...");
789 let order = self.abstract_group.order();
790 let mut ccs: Vec<HashSet<usize>> = vec![HashSet::from([0usize])];
791 let mut e2ccs = vec![None; order];
792 let mut remaining_unitary_elements = self
793 .elements()
794 .iter()
795 .enumerate()
796 .skip(1)
797 .filter_map(|(i, op)| {
798 if self.check_elem_antiunitary(op) {
799 None
800 } else {
801 Some(i)
802 }
803 })
804 .collect::<HashSet<usize>>();
805 let ctb =
806 self.abstract_group.cayley_table.as_ref().expect(
807 "Cayley table required for computing magnetic class structure, but not found.",
808 );
809
810 while !remaining_unitary_elements.is_empty() {
811 let g = *remaining_unitary_elements
815 .iter()
816 .next()
817 .expect("Unexpected empty `remaining_elements`.");
818 let ctb_xg = ctb.slice(s![.., g]);
819 let ginv = ctb_xg
820 .iter()
821 .position(|&x| x == 0)
822 .unwrap_or_else(|| panic!("The inverse of `{g}` cannot be found."));
823 let mut cur_cc = HashSet::from([g]);
824 for (s, op) in self.elements().iter().enumerate() {
825 let h = if self.check_elem_antiunitary(op) {
826 let sginv = ctb[[s, ginv]];
828 let ctb_xs = ctb.slice(s![.., s]);
829 ctb_xs.iter().position(|&x| x == sginv).ok_or_else(|| {
830 format_err!("No element `{sginv}` can be found in column `{s}` of Cayley table.")
831 })?
832 } else {
833 let sg = ctb[[s, g]];
835 let ctb_xs = ctb.slice(s![.., s]);
836 ctb_xs.iter().position(|&x| x == sg).ok_or_else(|| {
837 format_err!("No element `{sg}` can be found in column `{s}` of Cayley table.")
838 })?
839 };
840 if remaining_unitary_elements.contains(&h) {
841 remaining_unitary_elements.remove(&h);
842 cur_cc.insert(h);
843 }
844 }
845 ccs.push(cur_cc);
846 }
847 ccs.sort_by_key(|cc| {
848 *cc.iter()
849 .min()
850 .expect("Unable to find the minimum element index in one conjugacy class.")
851 });
852 ccs.iter().enumerate().for_each(|(i, cc)| {
853 cc.iter().for_each(|&j| e2ccs[j] = Some(i));
854 });
855 ensure!(e2ccs
856 .iter()
857 .skip(1)
858 .all(|x_opt| if let Some(x) = x_opt { *x > 0 } else { true }));
859
860 let class_structure =
861 EagerClassStructure::<T, Self::ClassSymbol>::new(&self.abstract_group, ccs, e2ccs);
862 self.class_structure = Some(class_structure);
863 log::debug!("Finding magnetic conjugacy classes... Done.");
864 Ok(())
865 }
866
867 fn get_cc_index(&self, cc_idx: usize) -> Option<&HashSet<usize>> {
868 self.class_structure
869 .as_ref()
870 .expect("No class structure found.")
871 .conjugacy_classes
872 .get(cc_idx)
873 }
874
875 fn get_cc_of_element_index(&self, e_idx: usize) -> Option<usize> {
876 self.class_structure
877 .as_ref()
878 .expect("No class structure found.")
879 .element_to_conjugacy_classes[e_idx]
880 }
881
882 fn get_cc_transversal(&self, cc_idx: usize) -> Option<Self::GroupElement> {
883 self.class_structure
884 .as_ref()
885 .expect("No class structure found.")
886 .conjugacy_class_transversal
887 .get(cc_idx)
888 .and_then(|&i| self.get_index(i))
889 }
890
891 fn get_index_of_cc_symbol(&self, cc_sym: &Self::ClassSymbol) -> Option<usize> {
892 self.class_structure
893 .as_ref()
894 .expect("No class structure found.")
895 .conjugacy_class_symbols
896 .get_index_of(cc_sym)
897 }
898
899 fn get_cc_symbol_of_index(&self, cc_idx: usize) -> Option<Self::ClassSymbol> {
900 self.class_structure
901 .as_ref()
902 .expect("No class structure found.")
903 .conjugacy_class_symbols
904 .get_index(cc_idx)
905 .map(|(cc_sym, _)| cc_sym.clone())
906 }
907
908 fn filter_cc_symbols<P: FnMut(&Self::ClassSymbol) -> bool>(
909 &self,
910 predicate: P,
911 ) -> Vec<Self::ClassSymbol> {
912 self.class_structure
913 .as_ref()
914 .expect("No class structure found.")
915 .conjugacy_class_symbols
916 .keys()
917 .cloned()
918 .filter(predicate)
919 .collect::<Vec<_>>()
920 }
921
922 fn set_class_symbols(&mut self, cc_symbols: &[Self::ClassSymbol]) {
923 self.class_structure
924 .as_mut()
925 .unwrap()
926 .set_class_symbols(cc_symbols);
927 }
928
929 fn get_inverse_cc(&self, cc_idx: usize) -> Option<usize> {
930 self.class_structure
931 .as_ref()
932 .expect("No class structure found.")
933 .inverse_conjugacy_classes
934 .get(cc_idx)
935 .cloned()
936 }
937
938 fn class_number(&self) -> usize {
939 self.class_structure
940 .as_ref()
941 .expect("No class structure found.")
942 .class_number()
943 }
944
945 fn class_size(&self, cc_idx: usize) -> Option<usize> {
946 self.class_structure
947 .as_ref()
948 .expect("No class structure found.")
949 .conjugacy_classes
950 .get(cc_idx)
951 .map(|cc| cc.len())
952 }
953}