algebraeon_groups/composition_table/
normal_subgroup.rs1use super::group::FiniteGroupMultiplicationTable;
2use super::partition::Congruence;
3use super::subgroup::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 use crate::composition_table::group::examples;
57
58 #[test]
59 fn normal_subgroup_state() {
60 for mut grp in [
62 examples::symmetric_group_structure(4),
63 examples::dihedral_group_structure(12),
64 examples::cyclic_group_structure(8),
65 ] {
66 grp.cache_conjugacy_classes();
67 let nsgs = grp.normal_subgroups();
68 for (nsg, gens) in nsgs {
69 nsg.check_state().unwrap();
70 gens.check_state().unwrap();
71 }
81 }
82 }
83
84 #[test]
85 fn normal_subgroup_counts() {
86 for (mut grp, num_sgs) in vec![
87 (examples::cyclic_group_structure(12), 6), (examples::cyclic_group_structure(13), 2), (examples::dihedral_group_structure(1), 2), (examples::dihedral_group_structure(12), 9),
91 (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), ] {
98 grp.cache_conjugacy_classes();
99 assert_eq!(grp.normal_subgroups().len(), num_sgs);
100 }
101 }
102
103 #[test]
104 fn normal_subgroup_cosets() {
105 use crate::examples::symmetric::Permutation;
106
107 let (grp, _perms, elems) = Permutation::<3>::symmetric_composition_table();
108 let nsg = NormalSubgroup {
109 subgroup: Subgroup {
110 subset: Subset::new_unchecked(
111 &grp,
112 vec![
113 elems[&Permutation::new([0, 1, 2]).unwrap()],
114 elems[&Permutation::new([1, 2, 0]).unwrap()],
115 elems[&Permutation::new([2, 0, 1]).unwrap()],
116 ]
117 .into_iter()
118 .collect(),
119 ),
120 },
121 };
122 nsg.check_state().unwrap();
123 let left_cosets = nsg.subgroup.left_cosets();
124 let right_cosets = nsg.subgroup.right_cosets();
125 assert!(left_cosets == right_cosets);
126 let cosets = nsg.cosets();
127 cosets.check_state().unwrap();
128 assert!(cosets.partition == left_cosets);
129 assert!(cosets.partition == right_cosets);
130 }
131
132 #[test]
133 fn normal_subgroup_quotient() {
134 use crate::examples::symmetric::Permutation;
135
136 let (mut grp, _perms, _elems) = Permutation::<3>::symmetric_composition_table();
137 grp.cache_conjugacy_classes();
138 for (nsg, _gens) in grp.normal_subgroups() {
139 let qgrp = nsg.quotient_group();
140 qgrp.check_state().unwrap();
141 assert_eq!(qgrp.size() * nsg.size(), grp.size());
142 }
143 }
144}