algebraeon_groups/composition_table/
normal_subgroup.rs

1use 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        } //should be the same as right cosets
45    }
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        //are the states of subgroups, normal subgroups, and generating sets correct when produced by grp.subgroups() and grp.normal_subgroups()?
61        for mut grp in vec![
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                // let left_cosets = nsg.left_cosets().unwrap();
72                // match left_cosets.is_right_cosets {
73                //     Some(flag) => {
74                //         assert!(flag)
75                //     }
76                //     None => {
77                //         assert!(false)
78                //     }
79                // }
80            }
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), //Abelian so same as # of subgroups
88            (examples::cyclic_group_structure(13), 2), //Abelian so same as # of subgroups
89            (examples::dihedral_group_structure(1), 2), //Abelian so same as # of subgroups
90            (examples::dihedral_group_structure(12), 9),
91            (examples::dihedral_group_structure(13), 3), //{e}, C13, D13
92            (examples::symmetric_group_structure(1), 1), //trivial group
93            (examples::symmetric_group_structure(2), 2), //cyclic of order 2
94            (examples::symmetric_group_structure(3), 3), //{e}, C3, S3
95            (examples::symmetric_group_structure(4), 4), //{e}, V4, A4, S4
96            (examples::symmetric_group_structure(5), 3), //{e}, A5, S5
97        ] {
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}