1use std::borrow::Borrow;
2use std::collections::BTreeSet;
3use std::collections::HashMap;
4
5use super::generating_set::*;
6use super::group::*;
7
8#[derive(Clone)]
9pub struct Homomorphism<
10 DomainT: Borrow<FiniteGroupMultiplicationTable> + Clone,
11 RangeT: Borrow<FiniteGroupMultiplicationTable> + Clone,
12> {
13 domain: DomainT,
14 range: RangeT,
15 func: Vec<usize>, }
17
18impl<
19 DomainT: Borrow<FiniteGroupMultiplicationTable> + Clone,
20 RangeT: Borrow<FiniteGroupMultiplicationTable> + Clone,
21> Homomorphism<DomainT, RangeT>
22{
23 pub fn check_state(&self) -> Result<(), &'static str> {
24 if self.func.len() != self.domain.borrow().size() {
26 return Err("func size does not match domain size");
27 }
28
29 for x in self.domain.borrow().elems() {
30 if !(self.func[x] < self.range.borrow().size()) {
31 return Err("func image is too big for an element of the range");
32 }
33 }
34
35 for x in self.domain.borrow().elems() {
37 for y in self.domain.borrow().elems() {
38 if self.func[self.domain.borrow().mul(x, y)]
39 != self.range.borrow().mul(self.func[x], self.func[y])
40 {
41 return Err("homomorphism does not respect composition");
42 }
43 }
44 }
45
46 Ok(())
47 }
48
49 pub fn new_unchecked(domain: DomainT, range: RangeT, func: Vec<usize>) -> Self {
50 Self {
51 domain,
52 range,
53 func,
54 }
55 }
56
57 pub fn to_isomorphism(self) -> Option<Isomorphism<DomainT, RangeT>> {
58 let n = self.domain.borrow().size();
59 if n != self.range.borrow().size() {
60 return None;
61 }
62
63 let mut inv = vec![None; n];
64 for x in 0..n {
65 match inv[self.func[x]] {
66 Some(_y) => {
67 return None;
69 }
70 None => inv[self.func[x]] = Some(x),
71 }
72 }
73
74 let inv = inv
75 .into_iter()
76 .map(|x| match x {
77 Some(x_val) => x_val,
78 None => panic!(),
79 })
80 .collect::<Vec<usize>>();
81
82 Some(Isomorphism {
83 left_group: self.domain,
84 right_group: self.range,
85 left_func: self.func.clone(),
86 right_func: inv,
87 })
88 }
89}
90
91#[derive(Clone)]
92pub struct Isomorphism<
93 LeftGrpT: Borrow<FiniteGroupMultiplicationTable> + Clone,
94 RightGrpT: Borrow<FiniteGroupMultiplicationTable> + Clone,
95> {
96 left_group: LeftGrpT,
97 right_group: RightGrpT,
98 left_func: Vec<usize>,
99 right_func: Vec<usize>,
100}
101
102impl<
103 LeftGrpT: Borrow<FiniteGroupMultiplicationTable> + Clone,
104 RightGrpT: Borrow<FiniteGroupMultiplicationTable> + Clone,
105> Isomorphism<LeftGrpT, RightGrpT>
106{
107 pub fn check_state(&self) -> Result<(), &'static str> {
108 let left_hom = Homomorphism {
109 domain: self.left_group.borrow(),
110 range: self.right_group.borrow(),
111 func: self.left_func.clone(),
112 };
113 match left_hom.check_state() {
114 Ok(()) => {}
115 Err(msg) => {
116 return Err(msg);
117 }
118 }
119
120 let right_hom = Homomorphism {
121 domain: self.right_group.borrow(),
122 range: self.left_group.borrow(),
123 func: self.right_func.clone(),
124 };
125 match right_hom.check_state() {
126 Ok(()) => {}
127 Err(msg) => {
128 return Err(msg);
129 }
130 }
131
132 if self.left_group.borrow().size() != self.right_group.borrow().size() {
133 return Err("isomorphism group sizes dont match");
134 }
135
136 for x in self.left_group.borrow().elems() {
139 if x != self.right_func[self.left_func[x]] {
140 return Err("isomorphism not inv");
141 }
142 }
143
144 Ok(())
145 }
146}
147
148pub fn find_isomorphism<'a, 'b>(
151 domain: &'a FiniteGroupMultiplicationTable,
152 range: &'b FiniteGroupMultiplicationTable,
153) -> Option<Isomorphism<&'a FiniteGroupMultiplicationTable, &'b FiniteGroupMultiplicationTable>> {
154 let group_size = domain.size();
155 if group_size != range.size() {
156 return None;
157 }
158
159 #[derive(Debug, PartialEq, Eq, Hash)]
163 struct ElementProfile {
164 order: usize,
165 mul_order: BTreeSet<usize>, }
167
168 impl ElementProfile {
169 fn new(x: usize, group: &FiniteGroupMultiplicationTable) -> Self {
170 debug_assert!(x < group.size());
171 ElementProfile {
172 order: group.order(x).unwrap(),
173 mul_order: group
174 .elems()
175 .map(|y| group.order(group.mul(x, y)).unwrap())
176 .collect(),
177 }
178 }
179 }
180
181 let domain_elem_profiles: Vec<ElementProfile> = domain
183 .elems()
184 .map(|x| ElementProfile::new(x, domain))
185 .collect();
186
187 let mut range_elem_profiles: HashMap<ElementProfile, Vec<usize>> = HashMap::new();
191 for x in range.elems() {
192 let p = ElementProfile::new(x, range);
193 match range_elem_profiles.get_mut(&p) {
194 Some(elems) => {
195 elems.push(x);
196 }
197 None => {
198 range_elem_profiles.insert(p, vec![x]);
199 }
200 };
201 }
202
203 struct GenInfo<'c> {
206 gen_list: Vec<usize>,
207 gen_set: GeneratingSet<'c>,
208 image_options: Vec<Vec<usize>>,
209 quant_to_check: usize,
210 }
211
212 fn find_new_gen_info<'c>(
213 domain: &'c FiniteGroupMultiplicationTable,
214 domain_elem_profiles: &Vec<ElementProfile>,
215 range_elem_profiles: &HashMap<ElementProfile, Vec<usize>>,
216 ) -> Result<GenInfo<'c>, ()> {
217 let domain_gen_set = domain.generating_set();
218 let domain_gens = domain_gen_set.gens();
219
220 let mut gen_image_options: Vec<Vec<usize>> = vec![];
223 for g in domain_gens {
224 match range_elem_profiles.get(&domain_elem_profiles[*g]) {
225 Some(r_elems) => gen_image_options.push(r_elems.clone()),
226 None => {
227 return Err(()); }
229 }
230 }
231
232 let mut num_to_check: usize = 1;
233 for gen_image_option in &gen_image_options {
234 num_to_check = match num_to_check.checked_mul(gen_image_option.len()) {
235 Some(prod) => prod,
236 None => usize::MAX,
237 };
238 }
239
240 Ok(GenInfo {
241 gen_list: domain_gens.clone(),
242 gen_set: domain_gen_set,
243 image_options: gen_image_options,
244 quant_to_check: num_to_check,
245 })
246 }
247
248 let mut current_gen_info;
249 match find_new_gen_info(domain, &domain_elem_profiles, &range_elem_profiles) {
250 Ok(gen_info) => current_gen_info = gen_info,
251 Err(_) => {
252 return None;
253 }
254 }
255
256 'outer_loop: loop {
260 let mut image_option_counter = vec![0; current_gen_info.gen_list.len()];
262 let mut already_checked: usize = 0;
263 'loop_label: loop {
264 if already_checked % 128 == 127 {
267 match find_new_gen_info(domain, &domain_elem_profiles, &range_elem_profiles) {
269 Ok(gen_info) => {
270 if gen_info.quant_to_check
271 < current_gen_info.quant_to_check - already_checked
272 {
273 current_gen_info = gen_info;
275 continue 'outer_loop;
276 }
277 }
278 Err(_) => {
279 return None;
280 }
281 }
282 }
283
284 match current_gen_info
286 .gen_set
287 .generated_homomorphism(
288 &image_option_counter
289 .iter()
290 .enumerate()
291 .map(|(i, j)| current_gen_info.image_options[i][*j])
292 .collect(),
293 range,
294 )
295 .unwrap()
296 {
297 Some(f) => match f.to_isomorphism() {
298 Some(f_iso) => {
299 return Some(f_iso);
300 }
301 None => {}
302 },
303 None => {}
304 }
305 already_checked += 1;
306
307 'for_label: {
309 for i in 0..current_gen_info.gen_list.len() {
310 image_option_counter[i] += 1;
311 if image_option_counter[i] == current_gen_info.image_options[i].len() {
312 image_option_counter[i] = 0;
313 } else {
314 break 'for_label;
315 }
316 }
317 break 'loop_label;
318 }
319 }
320 return None;
321 }
322}
323
324#[cfg(test)]
325mod homomorphism_tests {
326 use crate::free_group::todd_coxeter::FinitelyGeneratedGroupPresentation;
327
328 use super::*;
329
330 #[test]
331 fn homomorphism_state() {
332 {
333 let grp_g = examples::cyclic_group_structure(6);
335 let grp_h = examples::cyclic_group_structure(6);
336 let f = Homomorphism {
337 domain: &grp_g,
338 range: &grp_h,
339 func: vec![0, 1, 2, 3, 4, 5],
340 };
341 match f.check_state() {
342 Ok(()) => {}
343 Err(_) => panic!(),
344 }
345 }
346
347 {
348 let grp_g = examples::cyclic_group_structure(3);
350 let grp_h = examples::cyclic_group_structure(6);
351 let f = Homomorphism {
352 domain: &grp_g,
353 range: &grp_h,
354 func: vec![0, 2, 4],
355 };
356 match f.check_state() {
357 Ok(()) => {}
358 Err(_) => panic!(),
359 }
360 }
361
362 {
363 let grp_g = examples::cyclic_group_structure(6);
365 let grp_h = examples::cyclic_group_structure(3);
366 let f = Homomorphism {
367 domain: &grp_g,
368 range: &grp_h,
369 func: vec![0, 1, 2, 0, 1, 2],
370 };
371 match f.check_state() {
372 Ok(()) => {}
373 Err(_) => panic!(),
374 }
375 }
376
377 {
378 let grp_g = examples::cyclic_group_structure(3);
380 let grp_h = examples::cyclic_group_structure(6);
381 let f = Homomorphism {
382 domain: &grp_g,
383 range: &grp_h,
384 func: vec![0, 1, 2, 3],
385 };
386 match f.check_state() {
387 Ok(()) => panic!(),
388 Err(_) => {}
389 }
390 }
391
392 {
393 let grp_g = examples::cyclic_group_structure(6);
395 let grp_h = examples::cyclic_group_structure(3);
396 let f = Homomorphism {
397 domain: &grp_g,
398 range: &grp_h,
399 func: vec![0, 1, 2, 3, 4, 5, 6],
400 };
401 match f.check_state() {
402 Ok(()) => panic!(),
403 Err(_) => {}
404 }
405 }
406
407 {
408 let grp_g = examples::cyclic_group_structure(3);
410 let grp_h = examples::cyclic_group_structure(6);
411 let f = Homomorphism {
412 domain: &grp_g,
413 range: &grp_h,
414 func: vec![0, 1, 2],
415 };
416 match f.check_state() {
417 Ok(()) => panic!(),
418 Err(_) => {}
419 }
420 }
421 }
422
423 #[test]
424 fn isomorphism_state() {
425 {
426 let grp_g = examples::cyclic_group_structure(6);
428 let grp_h = examples::cyclic_group_structure(6);
429 let f = Isomorphism {
430 left_group: &grp_g,
431 right_group: &grp_h,
432 left_func: vec![0, 5, 4, 3, 2, 1],
433 right_func: vec![0, 5, 4, 3, 2, 1],
434 };
435 match f.check_state() {
436 Ok(()) => {}
437 Err(_) => panic!(),
438 }
439 }
440
441 {
442 let grp_g = examples::cyclic_group_structure(3);
444 let grp_h = examples::cyclic_group_structure(6);
445 let f = Isomorphism {
446 left_group: &grp_g,
447 right_group: &grp_h,
448 left_func: vec![0, 2, 4],
449 right_func: vec![0, 1, 2, 0, 1, 2],
450 };
451 match f.check_state() {
452 Ok(()) => panic!(),
453 Err(_) => {}
454 }
455 }
456
457 {
458 let grp_g = examples::cyclic_group_structure(6);
460 let grp_h = examples::cyclic_group_structure(6);
461 let f = Isomorphism {
462 left_group: &grp_g,
463 right_group: &grp_h,
464 left_func: vec![0, 2, 4, 0, 2, 4],
465 right_func: vec![0, 5, 4, 3, 2, 1],
466 };
467 match f.check_state() {
468 Ok(()) => panic!(),
469 Err(_) => {}
470 }
471 }
472 }
473
474 #[test]
475 fn homomorphism_to_isomorphism() {
476 {
477 let grp_g = examples::cyclic_group_structure(7);
479 let grp_h = examples::cyclic_group_structure(7);
480 let f = Homomorphism {
481 domain: &grp_g,
482 range: &grp_h,
483 func: vec![0, 3, 6, 2, 5, 1, 4],
484 };
485 f.check_state().unwrap();
486 match f.to_isomorphism() {
487 Some(_f_iso) => {}
488 None => panic!(),
489 }
490 }
491
492 {
493 let grp_g = examples::cyclic_group_structure(3);
495 let grp_h = examples::cyclic_group_structure(6);
496 let f = Homomorphism {
497 domain: &grp_g,
498 range: &grp_h,
499 func: vec![0, 2, 4],
500 };
501 f.check_state().unwrap();
502 match f.to_isomorphism() {
503 Some(_f_iso) => panic!(),
504 None => {}
505 }
506 }
507
508 {
509 let grp_g = examples::cyclic_group_structure(6);
511 let grp_h = examples::cyclic_group_structure(6);
512 let f = Homomorphism {
513 domain: &grp_g,
514 range: &grp_h,
515 func: vec![0, 2, 4, 0, 2, 4],
516 };
517 f.check_state().unwrap();
518 match f.to_isomorphism() {
519 Some(__iso) => panic!(),
520 None => {}
521 }
522 }
523 }
524
525 #[test]
526 fn test_find_isomorphism() {
527 {
528 let grp_g = examples::symmetric_group_structure(3);
529 let grp_h = examples::dihedral_group_structure(3);
530
531 match find_isomorphism(&grp_g, &grp_h) {
532 Some(f) => {
533 assert!(std::ptr::eq(&grp_g, f.left_group));
534 assert!(std::ptr::eq(&grp_h, f.right_group));
535 }
536 None => panic!(),
537 }
538 }
539
540 {
541 let grp_g = examples::symmetric_group_structure(3);
542 let grp_h = examples::cyclic_group_structure(6);
543
544 match find_isomorphism(&grp_g, &grp_h) {
545 Some(_f) => panic!(),
546 None => {}
547 }
548 }
549
550 {
551 let grp_g = examples::symmetric_group_structure(5);
552 let mut grp_h = FinitelyGeneratedGroupPresentation::new();
553 let a = grp_h.add_generator();
554 let b = grp_h.add_generator();
555 let c = grp_h.add_generator();
556 grp_h.add_relation(a.pow(2));
557 grp_h.add_relation(b.pow(2));
558 grp_h.add_relation(c.pow(2));
559 grp_h.add_relation((&a * &c).pow(2));
560 grp_h.add_relation((&a * &b).pow(3));
561 grp_h.add_relation((&b * &c).pow(5));
562 let grp_h = grp_h.into_finite_group(); match find_isomorphism(&grp_g, &grp_h) {
565 Some(_f) => panic!(),
566 None => {}
567 }
568 }
569 }
570}