algebraeon_groups/composition_table/
iso_rep.rs1use super::group::*;
2use super::homomorphism::*;
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: &Group) -> IsomorphismClass {
20 IsomorphismClass::from_group(group)
21}
22
23impl IsomorphismClass {
24 fn check_state(&self) -> Result<(), &'static str> {
25 match self {
26 Self::Trivial => {}
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::Quaternion => {}
38 Self::Alternating(_n) => {}
39 Self::Symmetric(_n) => {}
40 Self::DirectProduct(_factors) => {
41 todo!();
42 }
43 Self::Unknown(n) => {
44 if *n == 0 {
45 return Err("Unknown group with 0 elements is not valid");
46 }
47 }
48 }
49
50 Ok(())
51 }
52
53 pub fn from_group(group: &Group) -> Self {
54 let n = group.size();
55
56 if n == 1 {
58 return Self::Trivial;
59 }
60
61 match find_isomorphism(group, &examples::cyclic_group_structure(n)) {
63 Some(_f) => {
64 return Self::Cyclic(n);
65 }
66 None => {}
67 }
68
69 let mut nsgs = group.normal_subgroups();
71 nsgs.sort_by_key(|(nsg, _gens)| nsg.size());
72 for (nsg, _gens) in &nsgs {
73 nsg.check_state().unwrap();
74 if nsg.size() != 1 && nsg.size() != group.size() {
75 let nsg_group = nsg.subgroup().to_group();
77 let quo_group = nsg.quotient_group();
78 let prod_group = direct_product_structure(&nsg_group, &quo_group);
79 nsg_group.check_state().unwrap();
80 quo_group.check_state().unwrap();
81 let isom_result = find_isomorphism(&prod_group, &group);
82 match isom_result {
83 Some(_f) => {
84 return IsomorphismClass::from_group(&nsg_group)
85 * IsomorphismClass::from_group(&quo_group);
86 }
87 None => {}
88 }
89 }
90 }
91
92 debug_assert_eq!(false, group.is_abelian());
93
94 match find_isomorphism(group, &examples::quaternion_group_structure()) {
96 Some(_f) => {
97 return Self::Quaternion;
98 }
99 None => {}
100 }
101
102 let mut k = 0;
104 let mut k_fact = 1;
105 while k_fact < n {
106 k += 1;
107 k_fact *= k;
108 }
109 if n == k_fact {
110 match find_isomorphism(group, &examples::symmetric_group_structure(k)) {
111 Some(_f) => {
112 return Self::Symmetric(k);
113 }
114 None => {}
115 }
116 }
117
118 let mut k = 2;
120 let mut half_k_fact = 1;
121 while half_k_fact < n {
122 k += 1;
123 half_k_fact *= k;
124 }
125 if n == half_k_fact {
126 match find_isomorphism(group, &examples::alternating_group_structure(k)) {
127 Some(_f) => {
128 return Self::Alternating(k);
129 }
130 None => {}
131 }
132 }
133
134 if n % 2 == 0 {
136 match find_isomorphism(group, &examples::dihedral_group_structure(n / 2)) {
137 Some(_f) => {
138 return Self::Dihedral(n / 2);
139 }
140 None => {}
141 }
142 }
143
144 IsomorphismClass::Unknown(n)
145 }
146
147 pub fn to_group(&self) -> Result<Group, ()> {
148 match self {
149 Self::Trivial => Ok(examples::cyclic_group_structure(1)),
150 Self::Cyclic(n) => Ok(examples::cyclic_group_structure(*n)),
151 Self::Dihedral(n) => Ok(examples::dihedral_group_structure(*n)),
152 Self::Quaternion => Ok(examples::quaternion_group_structure()),
153 Self::Alternating(n) => Ok(examples::alternating_group_structure(*n)),
154 Self::Symmetric(n) => Ok(examples::symmetric_group_structure(*n)),
155 Self::DirectProduct(factors) => {
156 let mut factors_list = vec![];
157 for (factor, power) in factors.iter() {
158 for _i in 0..*power {
159 factors_list.push(factor);
160 }
161 }
162 let mut prod_group = examples::trivial_group_structure();
163 for factor in factors_list {
164 match factor.to_group() {
165 Ok(factor_group) => {
166 prod_group = direct_product_structure(&factor_group, &prod_group);
167 }
168 Err(()) => {
169 return Err(());
170 }
171 }
172 }
173 Ok(prod_group)
174 }
175 Self::Unknown(_n) => Err(()),
176 }
177 }
178
179 pub fn to_string(&self) -> String {
180 match self {
181 Self::Trivial => "T".to_owned(),
182 Self::Cyclic(n) => "C".to_owned() + &n.to_string(),
183 Self::Dihedral(n) => "D".to_owned() + &n.to_string(),
184 Self::Quaternion => "Q8".to_owned(),
185 Self::Alternating(n) => "A".to_owned() + &n.to_string(),
186 Self::Symmetric(n) => "S".to_owned() + &n.to_string(),
187 Self::DirectProduct(factors) => {
188 let mut ans = "".to_owned();
189 let mut first = true;
190 for (factor, power) in factors.iter() {
191 for _i in 0..*power {
192 if !first {
193 ans += "x";
194 }
195 ans += &factor.to_string();
196 first = false;
197 }
198 }
199 ans
200 }
201 Self::Unknown(n) => "Unknown".to_owned() + &n.to_string(),
202 }
203 }
204}
205
206impl std::ops::Mul<IsomorphismClass> for IsomorphismClass {
207 type Output = IsomorphismClass;
208
209 fn mul(self, other: IsomorphismClass) -> Self::Output {
210 match self {
211 IsomorphismClass::Trivial => {
212 return self;
213 }
214 _ => {}
215 }
216 match other {
217 IsomorphismClass::Trivial => {
218 return other;
219 }
220 _ => {}
221 }
222
223 let mut factors: BTreeMap<IsomorphismClass, usize> = BTreeMap::new();
224
225 match self {
226 IsomorphismClass::DirectProduct(fs) => {
227 for (f, p) in fs.iter() {
228 *factors.entry(f.clone()).or_insert(0) += p;
229 }
230 }
231 _ => {
232 *factors.entry(self).or_insert(0) += 1;
233 }
234 }
235
236 match other {
237 IsomorphismClass::DirectProduct(fs) => {
238 for (f, p) in fs.iter() {
239 *factors.entry(f.clone()).or_insert(0) += p;
240 }
241 }
242 _ => {
243 *factors.entry(other).or_insert(0) += 1;
244 }
245 }
246
247 IsomorphismClass::DirectProduct(Box::new(factors))
248 }
249}
250
251#[cfg(test)]
252mod isom_class_tests {
253 use super::*;
254
255 #[test]
256 fn test() {
257 let g = examples::klein_four_structure();
258 let i = IsomorphismClass::from_group(&g);
259 println!("{:?}", i.to_string());
260 assert_eq!(
261 i,
262 IsomorphismClass::DirectProduct(Box::new(BTreeMap::from([(
263 IsomorphismClass::Cyclic(2),
264 2
265 )])))
266 )
267 }
268}