@@ -366,6 +366,219 @@ def fundamental_group(self, simplify=True):
366
366
else :
367
367
return FG .quotient (rels )
368
368
369
+ def universal_cover_map (self ):
370
+ r"""
371
+ Return the universal covering map of the simplicial set.
372
+
373
+ It requires the fundamental group to be finite.
374
+
375
+ EXAMPLES::
376
+
377
+ sage: RP2 = simplicial_sets.RealProjectiveSpace(2)
378
+ sage: phi = RP2.universal_cover_map()
379
+ sage: phi
380
+ Simplicial set morphism:
381
+ From: Simplicial set with 6 non-degenerate simplices
382
+ To: RP^2
383
+ Defn: [(1, 1), (1, e), (f, 1), (f, e), (f * f, 1), (f * f, e)] --> [1, 1, f, f, f * f, f * f]
384
+ sage: phi.domain().face_data()
385
+ {(f, 1): ((1, e), (1, 1)),
386
+ (f, e): ((1, 1), (1, e)),
387
+ (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)),
388
+ (f * f, e): ((f, 1), s_0 (1, e), (f, e)),
389
+ (1, e): None,
390
+ (1, 1): None}
391
+
392
+ """
393
+ from sage .groups .free_group import FreeGroup
394
+ skel = self .n_skeleton (2 )
395
+ graph = skel .graph ()
396
+ if not skel .is_connected ():
397
+ graph = graph .subgraph (skel .base_point ())
398
+ edges = [e [2 ] for e in graph .edges (sort = False )]
399
+ spanning_tree = [e [2 ] for e in graph .min_spanning_tree ()]
400
+ gens = [e for e in edges if e not in spanning_tree ]
401
+
402
+ if not gens :
403
+ return self
404
+
405
+ gens_dict = dict (zip (gens , range (len (gens ))))
406
+ FG = FreeGroup (len (gens ), 'e' )
407
+ rels = []
408
+
409
+ for f in skel .n_cells (2 ):
410
+ z = dict ()
411
+ for i , sigma in enumerate (skel .faces (f )):
412
+ if sigma in spanning_tree :
413
+ z [i ] = FG .one ()
414
+ elif sigma .is_degenerate ():
415
+ z [i ] = FG .one ()
416
+ elif sigma in edges :
417
+ z [i ] = FG .gen (gens_dict [sigma ])
418
+ else :
419
+ # sigma is not in the correct connected component.
420
+ z [i ] = FG .one ()
421
+ rels .append (z [0 ]* z [1 ].inverse ()* z [2 ])
422
+ G = FG .quotient (rels )
423
+ char = {g : G .gen (i ) for i ,g in enumerate (gens )}
424
+ for e in edges :
425
+ if not e in gens :
426
+ char [e ] = G .one ()
427
+ return self .covering_map (char )
428
+
429
+ def covering_map (self , character ):
430
+ r"""
431
+ Return the covering map associated to a character.
432
+
433
+ The character is represented by a dictionary, that assigns an
434
+ element of a finite group to each nondegenerate 1-dimensional
435
+ cell. It should correspond to an epimorphism from the fundamental
436
+ group.
437
+
438
+ INPUT:
439
+
440
+ - ``character`` -- a dictionary
441
+
442
+
443
+ EXAMPLES::
444
+
445
+ sage: S1 = simplicial_sets.Sphere(1)
446
+ sage: W = S1.wedge(S1)
447
+ sage: G = CyclicPermutationGroup(3)
448
+ sage: C = W.covering_map({a : G.gen(0), b : G.one()})
449
+ sage: C
450
+ Simplicial set morphism:
451
+ From: Simplicial set with 9 non-degenerate simplices
452
+ To: Wedge: (S^1 v S^1)
453
+ Defn: [(*, ()), (*, (1,2,3)), (*, (1,3,2)), (sigma_1, ()), (sigma_1, ()), (sigma_1, (1,2,3)), (sigma_1, (1,2,3)), (sigma_1, (1,3,2)), (sigma_1, (1,3,2))] --> [*, *, *, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1]
454
+ sage: C.domain()
455
+ Simplicial set with 9 non-degenerate simplices
456
+ sage: C.domain().face_data()
457
+ {(sigma_1, ()): ((*, ()), (*, ())),
458
+ (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))),
459
+ (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))),
460
+ (sigma_1, ()): ((*, ()), (*, ())),
461
+ (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))),
462
+ (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))),
463
+ (*, ()): None,
464
+ (*, (1,3,2)): None,
465
+ (*, (1,2,3)): None}
466
+
467
+ """
468
+ from sage .topology .simplicial_set import AbstractSimplex , SimplicialSet
469
+ from sage .topology .simplicial_set_morphism import SimplicialSetMorphism
470
+ char = {a : b for (a ,b ) in character .items ()}
471
+ G = list (char .values ())[0 ].parent ()
472
+ if not G .is_finite ():
473
+ raise NotImplementedError ("can only compute universal covers of spaces with finite fundamental group" )
474
+ cells_dict = {}
475
+ faces_dict = {}
476
+
477
+ for s in self .n_cells (0 ):
478
+ for g in G :
479
+ cell = AbstractSimplex (0 ,name = "({}, {})" .format (s , g ))
480
+ cells_dict [(s ,g )] = cell
481
+ char [s ] = G .one ()
482
+
483
+ for d in range (1 , self .dimension () + 1 ):
484
+ for s in self .n_cells (d ):
485
+ if not s in char .keys ():
486
+ if d == 1 and s .is_degenerate ():
487
+ char [s ] = G .one ()
488
+ elif s .is_degenerate ():
489
+ if 0 in s .degeneracies ():
490
+ char [s ] = G .one ()
491
+ else :
492
+ char [s ] = char [s .nondegenerate ()]
493
+ else :
494
+ char [s ] = char [self .face (s , d )]
495
+ if s .is_nondegenerate ():
496
+ for g in G :
497
+ cell = AbstractSimplex (d ,name = "({}, {})" .format (s , g ))
498
+ cells_dict [(s ,g )] = cell
499
+ fd = []
500
+ faces = self .faces (s )
501
+ f0 = faces [0 ]
502
+ for h in G :
503
+ if h == g * char [s ]:
504
+ lifted = h
505
+ break
506
+ grelems = [cells_dict [(f0 .nondegenerate (), lifted )].apply_degeneracies (* f0 .degeneracies ())]
507
+ for f in faces [1 :]:
508
+ grelems .append (cells_dict [(f .nondegenerate (), g )].apply_degeneracies (* f .degeneracies ()))
509
+ faces_dict [cell ] = grelems
510
+ cover = SimplicialSet (faces_dict , base_point = cells_dict [(self .base_point (), G .one ())])
511
+ cover_map_data = {c : s [0 ] for (s ,c ) in cells_dict .items ()}
512
+ return SimplicialSetMorphism (data = cover_map_data , domain = cover , codomain = self )
513
+
514
+ def cover (self , character ):
515
+ r"""
516
+ Return the cover of the simplicial set associated to a character
517
+ of the fundamental group.
518
+
519
+ The character is represented by a dictionary, that assigns an
520
+ element of a finite group to each nondegenerate 1-dimensional
521
+ cell. It should correspond to an epimorphism from the fundamental
522
+ group.
523
+
524
+ INPUT:
525
+
526
+ - ``character`` -- a dictionary
527
+
528
+ EXAMPLES::
529
+
530
+ sage: S1 = simplicial_sets.Sphere(1)
531
+ sage: W = S1.wedge(S1)
532
+ sage: G = CyclicPermutationGroup(3)
533
+ sage: (a, b) = W.n_cells(1)
534
+ sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}).domain()
535
+ sage: C.face_data()
536
+ {(sigma_1, ()): ((*, (1,2,3)), (*, ())),
537
+ (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))),
538
+ (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))),
539
+ (sigma_1, ()): ((*, (1,3,2)), (*, ())),
540
+ (sigma_1, (1,2,3)): ((*, ()), (*, (1,2,3))),
541
+ (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2))),
542
+ (*, (1,2,3)): None,
543
+ (*, ()): None,
544
+ (*, (1,3,2)): None}
545
+ sage: C.homology(1)
546
+ Z x Z x Z x Z
547
+ sage: C.fundamental_group()
548
+ Finitely presented group < e0, e1, e2, e3 | >
549
+
550
+ """
551
+ return self .covering_map (character ).domain ()
552
+
553
+ def universal_cover (self ):
554
+ r"""
555
+ Return the universal cover of the simplicial set.
556
+ The fundamental group must be finite in order to ensure that the
557
+ universal cover is a simplicial set of finite type.
558
+
559
+ EXAMPLES::
560
+
561
+ sage: RP3 = simplicial_sets.RealProjectiveSpace(3)
562
+ sage: C = RP3.universal_cover()
563
+ sage: C
564
+ Simplicial set with 8 non-degenerate simplices
565
+ sage: C.face_data()
566
+ {(f, 1): ((1, e), (1, 1)),
567
+ (f, e): ((1, 1), (1, e)),
568
+ (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)),
569
+ (f * f, e): ((f, 1), s_0 (1, e), (f, e)),
570
+ (f * f * f, 1): ((f * f, e), s_0 (f, 1), s_1 (f, 1), (f * f, 1)),
571
+ (f * f * f, e): ((f * f, 1), s_0 (f, e), s_1 (f, e), (f * f, e)),
572
+ (1, e): None,
573
+ (1, 1): None}
574
+ sage: C.fundamental_group()
575
+ Finitely presented group < | >
576
+
577
+
578
+ """
579
+ return self .universal_cover_map ().domain ()
580
+
581
+
369
582
def is_simply_connected (self ):
370
583
"""
371
584
Return ``True`` if this pointed simplicial set is simply connected.
0 commit comments