algebraeon_groups/composition_table/
normal_subgroup.rs

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