From 59b4f542c7bd831115939fca320b6410901f74c3 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Sun, 1 Jan 2023 23:51:48 +0100 Subject: [PATCH 1/7] Implementation of simplicial set covers and simplicial stes of group presentations --- src/sage/categories/simplicial_sets.py | 213 +++++++++++++++++++ src/sage/topology/simplicial_set.py | 26 +-- src/sage/topology/simplicial_set_catalog.py | 4 +- src/sage/topology/simplicial_set_examples.py | 62 ++++++ 4 files changed, 284 insertions(+), 21 deletions(-) diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 8587e78aebf..438eea4523c 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -366,6 +366,219 @@ def fundamental_group(self, simplify=True): else: return FG.quotient(rels) + def universal_cover_map(self): + r""" + Return the universal covering map of the simplicial set. + + It requires the fundamental group to be finite. + + EXAMPLES:: + + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) + sage: phi = RP2.universal_cover_map() + sage: phi + Simplicial set morphism: + From: Simplicial set with 6 non-degenerate simplices + To: RP^2 + Defn: [(1, 1), (1, e), (f, 1), (f, e), (f * f, 1), (f * f, e)] --> [1, 1, f, f, f * f, f * f] + sage: phi.domain().face_data() + {(f, 1): ((1, e), (1, 1)), + (f, e): ((1, 1), (1, e)), + (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), + (f * f, e): ((f, 1), s_0 (1, e), (f, e)), + (1, e): None, + (1, 1): None} + + """ + from sage.groups.free_group import FreeGroup + skel = self.n_skeleton(2) + graph = skel.graph() + if not skel.is_connected(): + graph = graph.subgraph(skel.base_point()) + edges = [e[2] for e in graph.edges(sort=False)] + spanning_tree = [e[2] for e in graph.min_spanning_tree()] + gens = [e for e in edges if e not in spanning_tree] + + if not gens: + return self + + gens_dict = dict(zip(gens, range(len(gens)))) + FG = FreeGroup(len(gens), 'e') + rels = [] + + for f in skel.n_cells(2): + z = dict() + for i, sigma in enumerate(skel.faces(f)): + if sigma in spanning_tree: + z[i] = FG.one() + elif sigma.is_degenerate(): + z[i] = FG.one() + elif sigma in edges: + z[i] = FG.gen(gens_dict[sigma]) + else: + # sigma is not in the correct connected component. + z[i] = FG.one() + rels.append(z[0]*z[1].inverse()*z[2]) + G = FG.quotient(rels) + char = {g : G.gen(i) for i,g in enumerate(gens)} + for e in edges: + if not e in gens: + char[e] = G.one() + return self.covering_map(char) + + def covering_map(self, character): + r""" + Return the covering map associated to a character. + + The character is represented by a dictionary, that assigns an + element of a finite group to each nondegenerate 1-dimensional + cell. It should correspond to an epimorphism from the fundamental + group. + + INPUT: + + - ``character`` -- a dictionary + + + EXAMPLES:: + + sage: S1 = simplicial_sets.Sphere(1) + sage: W = S1.wedge(S1) + sage: G = CyclicPermutationGroup(3) + sage: C = W.covering_map({a : G.gen(0), b : G.one()}) + sage: C + Simplicial set morphism: + From: Simplicial set with 9 non-degenerate simplices + To: Wedge: (S^1 v S^1) + 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] + sage: C.domain() + Simplicial set with 9 non-degenerate simplices + sage: C.domain().face_data() + {(sigma_1, ()): ((*, ()), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), + (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))), + (sigma_1, ()): ((*, ()), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), + (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))), + (*, ()): None, + (*, (1,3,2)): None, + (*, (1,2,3)): None} + + """ + from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet + from sage.topology.simplicial_set_morphism import SimplicialSetMorphism + char = {a : b for (a,b) in character.items()} + G = list(char.values())[0].parent() + if not G.is_finite(): + raise NotImplementedError("can only compute universal covers of spaces with finite fundamental group") + cells_dict = {} + faces_dict = {} + + for s in self.n_cells(0): + for g in G: + cell = AbstractSimplex(0,name="({}, {})".format(s, g)) + cells_dict[(s,g)] = cell + char[s] = G.one() + + for d in range(1, self.dimension() + 1): + for s in self.n_cells(d): + if not s in char.keys(): + if d==1 and s.is_degenerate(): + char[s] = G.one() + elif s.is_degenerate(): + if 0 in s.degeneracies(): + char[s] = G.one() + else: + char[s] = char[s.nondegenerate()] + else: + char[s] = char[self.face(s, d)] + if s.is_nondegenerate(): + for g in G: + cell = AbstractSimplex(d,name="({}, {})".format(s, g)) + cells_dict[(s,g)] = cell + fd = [] + faces = self.faces(s) + f0 = faces[0] + for h in G: + if h == g*char[s]: + lifted = h + break + grelems = [cells_dict[(f0.nondegenerate(), lifted)].apply_degeneracies(*f0.degeneracies())] + for f in faces[1:]: + grelems.append(cells_dict[(f.nondegenerate(), g)].apply_degeneracies(*f.degeneracies())) + faces_dict[cell] = grelems + cover = SimplicialSet(faces_dict, base_point=cells_dict[(self.base_point(), G.one())]) + cover_map_data = {c : s[0] for (s,c) in cells_dict.items()} + return SimplicialSetMorphism(data = cover_map_data, domain = cover, codomain = self) + + def cover(self, character): + r""" + Return the cover of the simplicial set associated to a character + of the fundamental group. + + The character is represented by a dictionary, that assigns an + element of a finite group to each nondegenerate 1-dimensional + cell. It should correspond to an epimorphism from the fundamental + group. + + INPUT: + + - ``character`` -- a dictionary + + EXAMPLES:: + + sage: S1 = simplicial_sets.Sphere(1) + sage: W = S1.wedge(S1) + sage: G = CyclicPermutationGroup(3) + sage: (a, b) = W.n_cells(1) + sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}).domain() + sage: C.face_data() + {(sigma_1, ()): ((*, (1,2,3)), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), + (sigma_1, ()): ((*, (1,3,2)), (*, ())), + (sigma_1, (1,2,3)): ((*, ()), (*, (1,2,3))), + (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2))), + (*, (1,2,3)): None, + (*, ()): None, + (*, (1,3,2)): None} + sage: C.homology(1) + Z x Z x Z x Z + sage: C.fundamental_group() + Finitely presented group < e0, e1, e2, e3 | > + + """ + return self.covering_map(character).domain() + + def universal_cover(self): + r""" + Return the universal cover of the simplicial set. + The fundamental group must be finite in order to ensure that the + universal cover is a simplicial set of finite type. + + EXAMPLES:: + + sage: RP3 = simplicial_sets.RealProjectiveSpace(3) + sage: C = RP3.universal_cover() + sage: C + Simplicial set with 8 non-degenerate simplices + sage: C.face_data() + {(f, 1): ((1, e), (1, 1)), + (f, e): ((1, 1), (1, e)), + (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), + (f * f, e): ((f, 1), s_0 (1, e), (f, e)), + (f * f * f, 1): ((f * f, e), s_0 (f, 1), s_1 (f, 1), (f * f, 1)), + (f * f * f, e): ((f * f, 1), s_0 (f, e), s_1 (f, e), (f * f, e)), + (1, e): None, + (1, 1): None} + sage: C.fundamental_group() + Finitely presented group < | > + + + """ + return self.universal_cover_map().domain() + + def is_simply_connected(self): """ Return ``True`` if this pointed simplicial set is simply connected. diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 0ca2ff5bcb2..3312e0411e4 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -1686,26 +1686,12 @@ def graph(self): sage: Sigma3.nerve().is_connected() True """ - skel = self.n_skeleton(1) - edges = skel.n_cells(1) - vertices = skel.n_cells(0) - used_vertices = set() # vertices which are in an edge - d = {} - for e in edges: - v = skel.face(e, 0) - w = skel.face(e, 1) - if v in d: - if w in d[v]: - d[v][w] = d[v][w] + [e] - else: - d[v][w] = [e] - else: - d[v] = {w: [e]} - used_vertices.update([v, w]) - for v in vertices: - if v not in used_vertices: - d[v] = {} - return Graph(d, format='dict_of_dicts') + G = Graph(loops=True, multiedges=True) + for e in self.n_cells(1): + G.add_edge(self.face(e,0), self.face(e,1), e) + for v in self.n_cells(0): + G.add_vertex(v) + return G def is_connected(self): """ diff --git a/src/sage/topology/simplicial_set_catalog.py b/src/sage/topology/simplicial_set_catalog.py index 70607a1ab41..d20df19e4a1 100644 --- a/src/sage/topology/simplicial_set_catalog.py +++ b/src/sage/topology/simplicial_set_catalog.py @@ -26,6 +26,8 @@ - the Hopf map: this is a pre-built morphism, from which one can extract its domain, codomain, mapping cone, etc. +- the complex of a group presentation. + All of these examples are accessible by typing ``simplicial_sets.NAME``, where ``NAME`` is the name of the example. Type ``simplicial_sets.[TAB]`` for a complete list. @@ -48,4 +50,4 @@ KleinBottle, Torus, Simplex, Horn, Point, ComplexProjectiveSpace, - HopfMap) + HopfMap, PresentationComplex) diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index 279cf8b7c7d..8cd657574df 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -9,6 +9,8 @@ AUTHORS: - John H. Palmieri (2016-07) + +- Miguel Marco (2022-12) """ # **************************************************************************** # Copyright (C) 2016 John H. Palmieri @@ -48,6 +50,8 @@ from sage.misc.lazy_import import lazy_import lazy_import('sage.categories.simplicial_sets', 'SimplicialSets') + + ######################################################################## # The nerve of a finite monoid, used in sage.categories.finite_monoid. @@ -790,3 +794,61 @@ def HopfMap(): return S3.Hom(S2)({alpha_1:s0_sigma, alpha_2:s1_sigma, alpha_3:s2_sigma, alpha_4:s0_sigma, alpha_5:s2_sigma, alpha_6:s1_sigma}) + + +def PresentationComplex(G): + r""" + Return a simplicial set constructed from a group presentation. + The result is a subdivision of the presentation complex. + + INPUT: + + - "G" -- a finitely presented group + + EXAMPLES:: + + sage: G = SymmetricGroup(2).as_finitely_presented_group() + sage: G + Finitely presented group < a | a^2 > + sage: S = simplicial_sets.PresentationComplex(G) + sage: S + Simplicial set with 5 non-degenerate simplices + sage: S.face_data() + {Delta^0: None, + a: (Delta^0, Delta^0), + a^-1: (Delta^0, Delta^0), + Ta: (a, s_0 Delta^0, a^-1), + a^2: (a, s_0 Delta^0, a)} + sage: S.fundamental_group() + Finitely presented group < e0 | e0^2 > + """ + O = AbstractSimplex(0) + SO = O.apply_degeneracies(0) + edges = {g: AbstractSimplex(1, name=str(g)) for g in G.gens()} + inverseedges = {g.inverse(): AbstractSimplex(1, name=str(g.inverse())) for g in G.gens()} + all_edges = {} + all_edges.update(edges) + all_edges.update(inverseedges) + triangles = {g: AbstractSimplex(2, name='T' + str(g)) for g in G.gens()} + face_maps = {g: [O, O] for g in all_edges.values()} + face_maps.update({triangles[t]: [all_edges[t], SO, all_edges[t.inverse()]] for t in triangles}) + for r in G.relations(): + if len(r.Tietze()) == 1: + pass + elif len(r.Tietze()) == 2: + a = all_edges[G([r.Tietze()[0]])] + b = all_edges[G([r.Tietze()[1]])] + T = AbstractSimplex(2, name=str(r)) + face_maps[T] = [a, SO, b] + else: + words = [all_edges[G([a])] for a in r.Tietze()] + words[-1] = all_edges[G([-r.Tietze()[-1]])] + while len(words) > 3: + auxedge = AbstractSimplex(1) + face_maps[auxedge] = [O, O] + auxtring = AbstractSimplex(2) + face_maps[auxtring] = [words[1], auxedge, words[0]] + words = [auxedge] + words[2:] + auxtring = AbstractSimplex(2) + face_maps[auxtring] = [words[1], words[2], words[0]] + return SimplicialSet_finite(face_maps, base_point=O) From 9be1db026217b02db82f84ee454a353160699aba Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 4 Jan 2023 19:01:22 +0100 Subject: [PATCH 2/7] Deduplicate code in fundamental group and universal cover --- src/sage/categories/simplicial_sets.py | 124 +++++++++++-------------- src/sage/topology/simplicial_set.py | 2 +- 2 files changed, 54 insertions(+), 72 deletions(-) diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 438eea4523c..6223c5b9d26 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -317,7 +317,7 @@ def fundamental_group(self, simplify=True): sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = Sigma3.nerve() sage: pi = BSigma3.fundamental_group(); pi - Finitely presented group < e0, e1 | e0^2, e1^3, (e0*e1^-1)^2 > + Finitely presented group < e1, e2 | e2^2, e1^3, (e2*e1)^2 > sage: pi.order() 6 sage: pi.is_abelian() @@ -331,19 +331,27 @@ def fundamental_group(self, simplify=True): """ # Import this here to prevent importing libgap upon startup. from sage.groups.free_group import FreeGroup - skel = self.n_skeleton(2) + if not self.n_cells(1): + return FreeGroup([]).quotient([]) + FG = self._universal_cover_dict()[0] + if simplify: + return FG.simplified() + else: + return FG + def _universal_cover_dict(self): + r""" + Return the fundamental group and dictionary sending each edge to + the corresponding group element + """ + from sage.groups.free_group import FreeGroup + skel = self.n_skeleton(2) graph = skel.graph() if not skel.is_connected(): graph = graph.subgraph(skel.base_point()) - - edges = [e[2] for e in graph.edges(sort=True)] + edges = [e[2] for e in graph.edges(sort=False)] spanning_tree = [e[2] for e in graph.min_spanning_tree()] gens = [e for e in edges if e not in spanning_tree] - - if not gens: - return FreeGroup([]).quotient([]) - gens_dict = dict(zip(gens, range(len(gens)))) FG = FreeGroup(len(gens), 'e') rels = [] @@ -361,10 +369,13 @@ def fundamental_group(self, simplify=True): # sigma is not in the correct connected component. z[i] = FG.one() rels.append(z[0]*z[1].inverse()*z[2]) - if simplify: - return FG.quotient(rels).simplified() - else: - return FG.quotient(rels) + G = FG.quotient(rels) + char = {g : G.gen(i) for i,g in enumerate(gens)} + for e in edges: + if not e in gens: + char[e] = G.one() + return (G, char) + def universal_cover_map(self): r""" @@ -382,48 +393,18 @@ def universal_cover_map(self): To: RP^2 Defn: [(1, 1), (1, e), (f, 1), (f, e), (f * f, 1), (f * f, e)] --> [1, 1, f, f, f * f, f * f] sage: phi.domain().face_data() - {(f, 1): ((1, e), (1, 1)), - (f, e): ((1, 1), (1, e)), - (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), - (f * f, e): ((f, 1), s_0 (1, e), (f, e)), - (1, e): None, - (1, 1): None} + {(1, 1): None, + (1, e): None, + (f, 1): ((1, e), (1, 1)), + (f, e): ((1, 1), (1, e)), + (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), + (f * f, e): ((f, 1), s_0 (1, e), (f, e))} """ - from sage.groups.free_group import FreeGroup - skel = self.n_skeleton(2) - graph = skel.graph() - if not skel.is_connected(): - graph = graph.subgraph(skel.base_point()) - edges = [e[2] for e in graph.edges(sort=False)] - spanning_tree = [e[2] for e in graph.min_spanning_tree()] - gens = [e for e in edges if e not in spanning_tree] - - if not gens: - return self - - gens_dict = dict(zip(gens, range(len(gens)))) - FG = FreeGroup(len(gens), 'e') - rels = [] - - for f in skel.n_cells(2): - z = dict() - for i, sigma in enumerate(skel.faces(f)): - if sigma in spanning_tree: - z[i] = FG.one() - elif sigma.is_degenerate(): - z[i] = FG.one() - elif sigma in edges: - z[i] = FG.gen(gens_dict[sigma]) - else: - # sigma is not in the correct connected component. - z[i] = FG.one() - rels.append(z[0]*z[1].inverse()*z[2]) - G = FG.quotient(rels) - char = {g : G.gen(i) for i,g in enumerate(gens)} - for e in edges: - if not e in gens: - char[e] = G.one() + edges = self.n_cells(1) + if not edges: + return self.identity() + G, char = self._universal_cover_dict() return self.covering_map(char) def covering_map(self, character): @@ -445,6 +426,7 @@ def covering_map(self, character): sage: S1 = simplicial_sets.Sphere(1) sage: W = S1.wedge(S1) sage: G = CyclicPermutationGroup(3) + sage: a, b = W.n_cells(1) sage: C = W.covering_map({a : G.gen(0), b : G.one()}) sage: C Simplicial set morphism: @@ -454,15 +436,15 @@ def covering_map(self, character): sage: C.domain() Simplicial set with 9 non-degenerate simplices sage: C.domain().face_data() - {(sigma_1, ()): ((*, ()), (*, ())), - (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))), + {(*, ()): None, + (*, (1,2,3)): None, + (*, (1,3,2)): None, + (sigma_1, ()): ((*, (1,2,3)), (*, ())), (sigma_1, ()): ((*, ()), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))), - (*, ()): None, - (*, (1,3,2)): None, - (*, (1,2,3)): None} + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), + (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2)))} """ from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet @@ -531,17 +513,17 @@ def cover(self, character): sage: W = S1.wedge(S1) sage: G = CyclicPermutationGroup(3) sage: (a, b) = W.n_cells(1) - sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}).domain() + sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}) sage: C.face_data() - {(sigma_1, ()): ((*, (1,2,3)), (*, ())), - (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), + {(*, ()): None, + (*, (1,2,3)): None, + (*, (1,3,2)): None, + (sigma_1, ()): ((*, (1,2,3)), (*, ())), (sigma_1, ()): ((*, (1,3,2)), (*, ())), + (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), (sigma_1, (1,2,3)): ((*, ()), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2))), - (*, (1,2,3)): None, - (*, ()): None, - (*, (1,3,2)): None} + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), + (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2)))} sage: C.homology(1) Z x Z x Z x Z sage: C.fundamental_group() @@ -563,14 +545,14 @@ def universal_cover(self): sage: C Simplicial set with 8 non-degenerate simplices sage: C.face_data() - {(f, 1): ((1, e), (1, 1)), + {(1, 1): None, + (1, e): None, + (f, 1): ((1, e), (1, 1)), (f, e): ((1, 1), (1, e)), (f * f, 1): ((f, e), s_0 (1, 1), (f, 1)), (f * f, e): ((f, 1), s_0 (1, e), (f, e)), (f * f * f, 1): ((f * f, e), s_0 (f, 1), s_1 (f, 1), (f * f, 1)), - (f * f * f, e): ((f * f, 1), s_0 (f, e), s_1 (f, e), (f * f, e)), - (1, e): None, - (1, 1): None} + (f * f * f, e): ((f * f, 1), s_0 (f, e), s_1 (f, e), (f * f, e))} sage: C.fundamental_group() Finitely presented group < | > diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 3312e0411e4..5612c1b352d 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -173,7 +173,7 @@ sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = Sigma3.nerve() sage: pi = BSigma3.fundamental_group(); pi - Finitely presented group < e0, e1 | e0^2, e1^3, (e0*e1^-1)^2 > + Finitely presented group < e1, e2 | e2^2, e1^3, (e2*e1)^2 > sage: pi.order() 6 sage: pi.is_abelian() From 1e5cf86d1620ab2dd3430329d6b96cc5d5dbd43a Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 4 Jan 2023 19:55:26 +0100 Subject: [PATCH 3/7] Add explanation about presentation complex. --- src/sage/topology/simplicial_set_examples.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index 8cd657574df..d350bd579d8 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -801,6 +801,10 @@ def PresentationComplex(G): Return a simplicial set constructed from a group presentation. The result is a subdivision of the presentation complex. + The presentation complex has one vertex and one edge for + each generator. Then triangles (and eventually new edges + to glue them) are added to realize the relations. + INPUT: - "G" -- a finitely presented group From fd2cf53182a419e80cb18f248935ee50e27cd9d4 Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Sun, 12 Feb 2023 21:20:46 +0100 Subject: [PATCH 4/7] minor style fixes --- src/sage/categories/simplicial_sets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 6223c5b9d26..d760a4ac9bd 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -372,7 +372,7 @@ def _universal_cover_dict(self): G = FG.quotient(rels) char = {g : G.gen(i) for i,g in enumerate(gens)} for e in edges: - if not e in gens: + if e not in gens: char[e] = G.one() return (G, char) @@ -464,7 +464,7 @@ def covering_map(self, character): for d in range(1, self.dimension() + 1): for s in self.n_cells(d): - if not s in char.keys(): + if s not in char.keys(): if d==1 and s.is_degenerate(): char[s] = G.one() elif s.is_degenerate(): From 7ecdef456acf74cee559fecd57f9e19a72e464ff Mon Sep 17 00:00:00 2001 From: miguelmarco Date: Wed, 15 Mar 2023 19:17:58 +0100 Subject: [PATCH 5/7] Update src/sage/topology/simplicial_set_examples.py Co-authored-by: John H. Palmieri --- src/sage/topology/simplicial_set_examples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index d350bd579d8..e81105a201f 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -801,7 +801,7 @@ def PresentationComplex(G): Return a simplicial set constructed from a group presentation. The result is a subdivision of the presentation complex. - The presentation complex has one vertex and one edge for + The presentation complex has a single vertex and it has one edge for each generator. Then triangles (and eventually new edges to glue them) are added to realize the relations. From dd1ef86756cb8813281e3e055d1fdd533f183b38 Mon Sep 17 00:00:00 2001 From: miguelmarco Date: Wed, 15 Mar 2023 19:18:09 +0100 Subject: [PATCH 6/7] Update src/sage/categories/simplicial_sets.py Co-authored-by: John H. Palmieri --- src/sage/categories/simplicial_sets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index d760a4ac9bd..2986953730b 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -411,7 +411,7 @@ def covering_map(self, character): r""" Return the covering map associated to a character. - The character is represented by a dictionary, that assigns an + The character is represented by a dictionary that assigns an element of a finite group to each nondegenerate 1-dimensional cell. It should correspond to an epimorphism from the fundamental group. From 8a7729c52d6e07d965dde8449ce3a577617b2cbb Mon Sep 17 00:00:00 2001 From: Miguel Marco Date: Wed, 15 Mar 2023 21:01:19 +0100 Subject: [PATCH 7/7] Added doctest for _universal_cover_dict --- src/sage/categories/simplicial_sets.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 2986953730b..6021558c3ec 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -343,6 +343,14 @@ def _universal_cover_dict(self): r""" Return the fundamental group and dictionary sending each edge to the corresponding group element + + TESTS:: + + sage: RP2 = simplicial_sets.RealProjectiveSpace(2) + sage: RP2._universal_cover_dict() + (Finitely presented group < e | e^2 >, {f: e}) + sage: RP2.nondegenerate_simplices() + [1, f, f * f] """ from sage.groups.free_group import FreeGroup skel = self.n_skeleton(2) @@ -445,7 +453,6 @@ def covering_map(self, character): (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2)))} - """ from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet from sage.topology.simplicial_set_morphism import SimplicialSetMorphism @@ -528,7 +535,6 @@ def cover(self, character): Z x Z x Z x Z sage: C.fundamental_group() Finitely presented group < e0, e1, e2, e3 | > - """ return self.covering_map(character).domain() @@ -555,12 +561,9 @@ def universal_cover(self): (f * f * f, e): ((f * f, 1), s_0 (f, e), s_1 (f, e), (f * f, e))} sage: C.fundamental_group() Finitely presented group < | > - - """ return self.universal_cover_map().domain() - def is_simply_connected(self): """ Return ``True`` if this pointed simplicial set is simply connected.