algebraeon_groups/composition_table/
normal_subgroup.rs1use super::group::*;
2use super::partition::*;
3use super::subgroup::*;
4
5pub struct NormalSubgroup<'a> {
6 subgroup: Subgroup<'a>,
7}
8
9impl<'a> NormalSubgroup<'a> {
10 pub fn check_state(&self) -> Result<(), &'static str> {
11 match self.subgroup.check_state() {
12 Ok(_) => {}
13 Err(msg) => {
14 return Err(msg);
15 }
16 }
17
18 if !(self.subgroup.is_normal_subgroup()) {
19 return Err("normal subgroup is not norpppmal");
20 }
21
22 Ok(())
23 }
24
25 pub fn new_unchecked(subgroup: Subgroup<'a>) -> Self {
26 Self { subgroup }
27 }
28
29 pub fn size(&self) -> usize {
30 self.subgroup.size()
31 }
32
33 pub fn subgroup(&self) -> &Subgroup<'a> {
34 &self.subgroup
35 }
36
37 pub fn to_subgroup(self) -> Subgroup<'a> {
38 self.subgroup
39 }
40
41 pub fn cosets(&self) -> Congruence {
42 Congruence {
43 partition: self.subgroup.left_cosets(),
44 } }
46
47 pub fn quotient_group(&self) -> FiniteGroupMultiplicationTable {
48 self.cosets().quotient_group()
49 }
50}
51
52#[cfg(test)]
53mod normal_subgroup_tests {
54 use super::super::subset::*;
55 use super::*;
56
57 #[test]
58 fn normal_subgroup_state() {
59 for mut grp in vec![
61 examples::symmetric_group_structure(4),
62 examples::dihedral_group_structure(12),
63 examples::cyclic_group_structure(8),
64 ] {
65 grp.cache_conjugacy_classes();
66 let nsgs = grp.normal_subgroups();
67 for (nsg, gens) in nsgs {
68 nsg.check_state().unwrap();
69 gens.check_state().unwrap();
70 }
80 }
81 }
82
83 #[test]
84 fn normal_subgroup_counts() {
85 for (mut grp, num_sgs) in vec![
86 (examples::cyclic_group_structure(12), 6), (examples::cyclic_group_structure(13), 2), (examples::dihedral_group_structure(1), 2), (examples::dihedral_group_structure(12), 9),
90 (examples::dihedral_group_structure(13), 3), (examples::symmetric_group_structure(1), 1), (examples::symmetric_group_structure(2), 2), (examples::symmetric_group_structure(3), 3), (examples::symmetric_group_structure(4), 4), (examples::symmetric_group_structure(5), 3), ] {
97 grp.cache_conjugacy_classes();
98 assert_eq!(grp.normal_subgroups().len(), num_sgs);
99 }
100 }
101
102 #[test]
103 fn normal_subgroup_cosets() {
104 use crate::examples::symmetric::Permutation;
105
106 let (grp, _perms, elems) = Permutation::<3>::symmetric_composition_table();
107 let nsg = NormalSubgroup {
108 subgroup: Subgroup {
109 subset: Subset::new_unchecked(
110 &grp,
111 vec![
112 elems[&Permutation::new([0, 1, 2]).unwrap()],
113 elems[&Permutation::new([1, 2, 0]).unwrap()],
114 elems[&Permutation::new([2, 0, 1]).unwrap()],
115 ]
116 .into_iter()
117 .collect(),
118 ),
119 },
120 };
121 nsg.check_state().unwrap();
122 let left_cosets = nsg.subgroup.left_cosets();
123 let right_cosets = nsg.subgroup.right_cosets();
124 assert!(left_cosets == right_cosets);
125 let cosets = nsg.cosets();
126 cosets.check_state().unwrap();
127 assert!(cosets.partition == left_cosets);
128 assert!(cosets.partition == right_cosets);
129 }
130
131 #[test]
132 fn normal_subgroup_quotient() {
133 use crate::examples::symmetric::Permutation;
134
135 let (mut grp, _perms, _elems) = Permutation::<3>::symmetric_composition_table();
136 grp.cache_conjugacy_classes();
137 for (nsg, _gens) in grp.normal_subgroups() {
138 let qgrp = nsg.quotient_group();
139 qgrp.check_state().unwrap();
140 assert_eq!(qgrp.size() * nsg.size(), grp.size());
141 }
142 }
143}