algebraeon_groups/composition_table/
iso_rep.rs1use super::group::{FiniteGroupMultiplicationTable, direct_product_structure, examples};
2use super::homomorphism::find_isomorphism;
3use std::collections::BTreeMap;
4use std::fmt::Debug;
5use std::hash::Hash;
6
7#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Ord, Clone)]
8pub enum IsomorphismClass {
9 Trivial,
10 Cyclic(usize),
11 Dihedral(usize),
12 Quaternion,
13 Alternating(usize),
14 Symmetric(usize),
15 DirectProduct(Box<BTreeMap<IsomorphismClass, usize>>), Unknown(usize),
17}
18
19pub fn isomorphism_class(group: &FiniteGroupMultiplicationTable) -> IsomorphismClass {
20 IsomorphismClass::from_group(group)
21}
22
23impl IsomorphismClass {
24 fn check_state(&self) -> Result<(), &'static str> {
25 match self {
26 Self::Trivial | Self::Quaternion => {}
27 Self::Cyclic(n) => {
28 if *n == 0 {
29 return Err("C0 is not a group");
30 }
31 }
32 Self::Dihedral(n) => {
33 if *n == 0 {
34 return Err("D0 is not a group");
35 }
36 }
37 Self::Symmetric(_n) | Self::Alternating(_n) => {}
38 Self::DirectProduct(_factors) => {
39 todo!();
40 }
41 Self::Unknown(n) => {
42 if *n == 0 {
43 return Err("Unknown group with 0 elements is not valid");
44 }
45 }
46 }
47
48 Ok(())
49 }
50
51 pub fn from_group(group: &FiniteGroupMultiplicationTable) -> Self {
52 let n = group.size();
53
54 if n == 1 {
56 return Self::Trivial;
57 }
58
59 if let Some(_f) = find_isomorphism(group, &examples::cyclic_group_structure(n)) {
61 return Self::Cyclic(n);
62 }
63
64 let mut nsgs = group.normal_subgroups();
66 nsgs.sort_by_key(|(nsg, _gens)| nsg.size());
67 for (nsg, _gens) in &nsgs {
68 nsg.check_state().unwrap();
69 if nsg.size() != 1 && nsg.size() != group.size() {
70 let nsg_group = nsg.subgroup().to_group();
72 let quo_group = nsg.quotient_group();
73 let prod_group = direct_product_structure(&nsg_group, &quo_group);
74 nsg_group.check_state().unwrap();
75 quo_group.check_state().unwrap();
76 let isom_result = find_isomorphism(&prod_group, group);
77 if let Some(_f) = isom_result {
78 return IsomorphismClass::from_group(&nsg_group)
79 * IsomorphismClass::from_group(&quo_group);
80 }
81 }
82 }
83
84 debug_assert!(!group.is_abelian());
85
86 if let Some(_f) = find_isomorphism(group, &examples::quaternion_group_structure()) {
88 return Self::Quaternion;
89 }
90
91 let mut k = 0;
93 let mut k_fact = 1;
94 while k_fact < n {
95 k += 1;
96 k_fact *= k;
97 }
98 if n == k_fact
99 && let Some(_f) = find_isomorphism(group, &examples::symmetric_group_structure(k))
100 {
101 return Self::Symmetric(k);
102 }
103
104 let mut k = 2;
106 let mut half_k_fact = 1;
107 while half_k_fact < n {
108 k += 1;
109 half_k_fact *= k;
110 }
111 if n == half_k_fact
112 && let Some(_f) = find_isomorphism(group, &examples::alternating_group_structure(k))
113 {
114 return Self::Alternating(k);
115 }
116
117 if n.is_multiple_of(2)
119 && let Some(_f) = find_isomorphism(group, &examples::dihedral_group_structure(n / 2))
120 {
121 return Self::Dihedral(n / 2);
122 }
123
124 IsomorphismClass::Unknown(n)
125 }
126
127 pub fn to_group(&self) -> Result<FiniteGroupMultiplicationTable, ()> {
128 match self {
129 Self::Trivial => Ok(examples::cyclic_group_structure(1)),
130 Self::Cyclic(n) => Ok(examples::cyclic_group_structure(*n)),
131 Self::Dihedral(n) => Ok(examples::dihedral_group_structure(*n)),
132 Self::Quaternion => Ok(examples::quaternion_group_structure()),
133 Self::Alternating(n) => Ok(examples::alternating_group_structure(*n)),
134 Self::Symmetric(n) => Ok(examples::symmetric_group_structure(*n)),
135 Self::DirectProduct(factors) => {
136 let mut factors_list = vec![];
137 for (factor, power) in factors.iter() {
138 for _i in 0..*power {
139 factors_list.push(factor);
140 }
141 }
142 let mut prod_group = examples::trivial_group_structure();
143 for factor in factors_list {
144 match factor.to_group() {
145 Ok(factor_group) => {
146 prod_group = direct_product_structure(&factor_group, &prod_group);
147 }
148 Err(()) => {
149 return Err(());
150 }
151 }
152 }
153 Ok(prod_group)
154 }
155 Self::Unknown(_n) => Err(()),
156 }
157 }
158
159 #[allow(clippy::inherent_to_string)]
160 pub fn to_string(&self) -> String {
161 match self {
162 Self::Trivial => "T".to_owned(),
163 Self::Cyclic(n) => "C".to_owned() + &n.to_string(),
164 Self::Dihedral(n) => "D".to_owned() + &n.to_string(),
165 Self::Quaternion => "Q8".to_owned(),
166 Self::Alternating(n) => "A".to_owned() + &n.to_string(),
167 Self::Symmetric(n) => "S".to_owned() + &n.to_string(),
168 Self::DirectProduct(factors) => {
169 let mut ans = String::new();
170 let mut first = true;
171 for (factor, power) in factors.iter() {
172 for _i in 0..*power {
173 if !first {
174 ans += "x";
175 }
176 ans += &factor.to_string();
177 first = false;
178 }
179 }
180 ans
181 }
182 Self::Unknown(n) => "Unknown".to_owned() + &n.to_string(),
183 }
184 }
185}
186
187impl std::ops::Mul<IsomorphismClass> for IsomorphismClass {
188 type Output = IsomorphismClass;
189
190 fn mul(self, other: IsomorphismClass) -> Self::Output {
191 if self == IsomorphismClass::Trivial {
192 return other;
193 }
194 if other == IsomorphismClass::Trivial {
195 return other;
196 }
197
198 let mut factors: BTreeMap<IsomorphismClass, usize> = BTreeMap::new();
199
200 match self {
201 IsomorphismClass::DirectProduct(fs) => {
202 for (f, p) in fs.iter() {
203 *factors.entry(f.clone()).or_insert(0) += p;
204 }
205 }
206 _ => {
207 *factors.entry(self).or_insert(0) += 1;
208 }
209 }
210
211 match other {
212 IsomorphismClass::DirectProduct(fs) => {
213 for (f, p) in fs.iter() {
214 *factors.entry(f.clone()).or_insert(0) += p;
215 }
216 }
217 _ => {
218 *factors.entry(other).or_insert(0) += 1;
219 }
220 }
221
222 IsomorphismClass::DirectProduct(Box::new(factors))
223 }
224}
225
226#[cfg(test)]
227mod isom_class_tests {
228 use super::*;
229
230 #[test]
231 fn test() {
232 let g = examples::klein_four_structure();
233 let i = IsomorphismClass::from_group(&g);
234 println!("{:?}", i.to_string());
235 assert_eq!(
236 i,
237 IsomorphismClass::DirectProduct(Box::new(BTreeMap::from([(
238 IsomorphismClass::Cyclic(2),
239 2
240 )])))
241 );
242 }
243}