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