Path: blob/master/sage/homology/simplicial_complex_morphism.py
4079 views
r"""1Morphisms of simplicial complexes23AUTHORS:45- Benjamin Antieau <[email protected]> (2009.06)67This module implements morphisms of simplicial complexes. The input is given8by a dictionary on the vertex set or the effective vertex set of a simplicial complex.9The initialization checks that faces are sent to faces.1011There is also the capability to create the fiber product of two morphisms with the same codomain.1213EXAMPLES::1415sage: S = SimplicialComplex(5,[[0,2],[1,5],[3,4]])16sage: H = Hom(S,S.product(S))17sage: H.diagonal_morphism()18Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3', 4: 'L4R4', 5: 'L5R5'} from Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (1, 5), (0, 2)} to Simplicial complex with 36 vertices and 18 facets1920sage: S = SimplicialComplex(5,[[0,2],[1,5],[3,4]])21sage: T = SimplicialComplex(4,[[0,2],[1,3]])22sage: f = {0:0,1:1,2:2,3:1,4:3,5:3}23sage: H = Hom(S,T)24sage: x = H(f)25sage: x.image()26Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 3), (0, 2)}27sage: x.is_surjective()28False29sage: x.is_injective()30False31sage: x.is_identity()32False3334sage: S = simplicial_complexes.Sphere(2)35sage: H = Hom(S,S)36sage: i = H.identity()37sage: i.image()38Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}39sage: i.is_surjective()40True41sage: i.is_injective()42True43sage: i.is_identity()44True4546sage: S = simplicial_complexes.Sphere(2)47sage: H = Hom(S,S)48sage: i = H.identity()49sage: j = i.fiber_product(i)50sage: j51Simplicial complex morphism {'L1R1': 1, 'L3R3': 3, 'L2R2': 2, 'L0R0': 0} from Simplicial complex with 4 vertices and 4 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}5253sage: S = simplicial_complexes.Sphere(2)54sage: T = S.product(SimplicialComplex(1,[[0,1]]),rename_vertices = False)55sage: H = Hom(T,S)56sage: T57Simplicial complex with 8 vertices and 12 facets58sage: T.vertices()59((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1))60sage: f = {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1, (2, 0): 2, (2, 1): 2, (3, 0): 3, (3, 1): 3}61sage: x = H(f)62sage: U = simplicial_complexes.Sphere(1)63sage: G = Hom(U,S)64sage: U65Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}66sage: g = {0:0,1:1,2:2}67sage: y = G(g)68sage: z = y.fiber_product(x)69sage: z # this is the mapping path space70Simplicial complex morphism {'L2R(2, 0)': 2, 'L2R(2, 1)': 2, 'L0R(0, 0)': 0, 'L0R(0, 1)': 0, 'L1R(1, 0)': 1, 'L1R(1, 1)': 1} from Simplicial complex with 6 vertices and 6 facets to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}717273"""7475#*****************************************************************************76# Copyright (C) 2009 D. Benjamin Antieau <[email protected]>77#78# Distributed under the terms of the GNU General Public License (GPL)79#80# This code is distributed in the hope that it will be useful,81# but WITHOUT ANY WARRANTY; without even the implied warranty82# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.83#84# See the GNU General Public License for more details; the full text85# is available at:86#87# http://www.gnu.org/licenses/88#89#*****************************************************************************9091import sage.homology.simplicial_complex as simplicial_complex92import sage.matrix.all as matrix93from sage.structure.sage_object import SageObject94from sage.rings.integer_ring import ZZ95from sage.homology.chain_complex_morphism import ChainComplexMorphism96from sage.combinat.permutation import Permutation97from sage.algebras.steenrod.steenrod_algebra_misc import convert_perm9899def is_SimplicialComplexMorphism(x):100"""101Returns True if and only if x is a morphism of simplicial complexes.102103EXAMPLES::104105sage: from sage.homology.simplicial_complex_morphism import is_SimplicialComplexMorphism106sage: S = SimplicialComplex(5,[[0,1],[3,4]])107sage: H = Hom(S,S)108sage: f = {0:0,1:1,2:2,3:3,4:4,5:5}109sage: x = H(f)110sage: is_SimplicialComplexMorphism(x)111True112113"""114return isinstance(x,SimplicialComplexMorphism)115116class SimplicialComplexMorphism(SageObject):117"""118An element of this class is a morphism of simplicial complexes.119"""120def __init__(self,f,X,Y):121"""122Input is a dictionary f, the domain, and the codomain.123124One can define the dictionary either on the vertices of X or on the effective vertices of X (X.effective_vertices()). Note that this125difference does matter. For instance, it changes the result of the image method, and hence it changes the result of the is_surjective method as well.126This is because two SimplicialComplexes with the same faces but different vertex sets are not equal.127128EXAMPLES::129130sage: S = SimplicialComplex(5,[[0,1],[3,4]])131sage: H = Hom(S,S)132sage: f = {0:0,1:1,2:2,3:3,4:4,5:5}133sage: g = {0:0,1:1,3:3,4:4}134sage: x = H(f)135sage: y = H(g)136sage: x==y137False138sage: x.image()139Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (0, 1)}140sage: y.image()141Simplicial complex with vertex set (0, 1, 3, 4) and facets {(3, 4), (0, 1)}142sage: x.image()==y.image()143False144145"""146if not isinstance(X,simplicial_complex.SimplicialComplex) or not isinstance(Y,simplicial_complex.SimplicialComplex):147raise ValueError, "X and Y must be SimplicialComplexes."148if not set(f.keys())==X._vertex_set.set() and not set(f.keys())==X.effective_vertices().set():149raise ValueError, "f must be a dictionary from the vertex set of X to single values in the vertex set of Y."150dim = X.dimension()151Y_faces = Y.faces()152for k in range(dim+1):153for i in X.faces()[k]:154tup = i.tuple()155fi = []156for j in tup:157fi.append(f[j])158v = simplicial_complex.Simplex(set(fi))159if not v in Y_faces[v.dimension()]:160raise ValueError, "f must be a dictionary from the vertices of X to the vertices of Y."161self._vertex_dictionary = f162self._domain = X163self._codomain = Y164165def __eq__(self,x):166"""167Returns True if and only if self == x.168169EXAMPLES::170171sage: S = simplicial_complexes.Sphere(2)172sage: H = Hom(S,S)173sage: i = H.identity()174sage: i175Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}176sage: f = {0:0,1:1,2:2,3:2}177sage: j = H(f)178sage: i==j179False180181sage: T = SimplicialComplex(3,[[1,2]])182sage: T183Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 2)}184sage: G = Hom(T,T)185sage: k = G.identity()186sage: g = {0:0,1:1,2:2,3:3}187sage: l = G(g)188sage: k==l189True190191"""192if not isinstance(x,SimplicialComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._vertex_dictionary != x._vertex_dictionary:193return False194else:195return True196197def __call__(self,x,orientation=False):198"""199Input is a simplex of the domain. Output is the image simplex.200201If optional argument ``orientation`` is True, return a pair202``(image simplex, oriented)`` where ``oriented`` is 1 or `-1`203depending on whether the map preserves or reverses the204orientation of the image simplex.205206EXAMPLES::207208sage: S = simplicial_complexes.Sphere(2)209sage: T = simplicial_complexes.Sphere(3)210sage: S211Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}212sage: T213Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets214sage: f = {0:0,1:1,2:2,3:3}215sage: H = Hom(S,T)216sage: x = H(f)217sage: from sage.homology.simplicial_complex import Simplex218sage: x(Simplex([0,2,3]))219(0, 2, 3)220221An orientation-reversing example::222223sage: X = SimplicialComplex(1, [[0,1]])224sage: g = Hom(X,X)({0:1, 1:0})225sage: g(Simplex([0,1]))226(0, 1)227sage: g(Simplex([0,1]), orientation=True)228((0, 1), -1)229"""230dim = self._domain.dimension()231if not isinstance(x,simplicial_complex.Simplex) or x.dimension() > dim or not x in self._domain.faces()[x.dimension()]:232raise ValueError, "x must be a simplex of the source of f"233tup=x.tuple()234fx=[]235for j in tup:236fx.append(self._vertex_dictionary[j])237if orientation:238if len(set(fx)) == len(tup):239oriented = Permutation(convert_perm(fx)).signature()240else:241oriented = 1242return (simplicial_complex.Simplex(set(fx)), oriented)243else:244return simplicial_complex.Simplex(set(fx))245246def _repr_(self):247"""248Print representation249250EXAMPLES::251252sage: S = simplicial_complexes.Sphere(2)253sage: H = Hom(S,S)254sage: i = H.identity()255sage: i256Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}257sage: i._repr_()258'Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}'259260261"""262return "Simplicial complex morphism " + str(self._vertex_dictionary) + " from " + self._domain._repr_() + " to " + self._codomain._repr_()263264def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False):265"""266Returns the associated chain complex morphism of self.267268EXAMPLES::269270sage: S = simplicial_complexes.Sphere(1)271sage: T = simplicial_complexes.Sphere(2)272sage: H = Hom(S,T)273sage: f = {0:0,1:1,2:2}274sage: x = H(f)275sage: x276Simplicial complex morphism {0: 0, 1: 1, 2: 2} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}277sage: a = x.associated_chain_complex_morphism()278sage: a279Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring280sage: a._matrix_dictionary281{0: [0 0 0]282[0 1 0]283[0 0 1]284[1 0 0],2851: [0 0 0]286[0 1 0]287[0 0 0]288[1 0 0]289[0 0 0]290[0 0 1],2912: []}292sage: x.associated_chain_complex_morphism(augmented=True)293Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring294sage: x.associated_chain_complex_morphism(cochain=True)295Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring296sage: x.associated_chain_complex_morphism(augmented=True,cochain=True)297Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring298sage: x.associated_chain_complex_morphism(base_ring=GF(11))299Chain complex morphism from Chain complex with at most 2 nonzero terms over Finite Field of size 11 to Chain complex with at most 3 nonzero terms over Finite Field of size 11300301Some simplicial maps which reverse the orientation of a few simplices::302303sage: g = {0:1, 1:2, 2:0}304sage: H(g).associated_chain_complex_morphism()._matrix_dictionary305{0: [0 0 0]306[1 0 0]307[0 1 0]308[0 0 1], 1: [ 0 0 0]309[-1 0 0]310[ 0 0 0]311[ 0 0 1]312[ 0 0 0]313[ 0 -1 0], 2: []}314315sage: X = SimplicialComplex(1, [[0, 1]])316sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary317{0: [0 1]318[1 0], 1: [-1]}319"""320max_dim = max(self._domain.dimension(),self._codomain.dimension())321min_dim = min(self._domain.dimension(),self._codomain.dimension())322matrices = {}323if augmented is True:324m = matrix.Matrix(base_ring,1,1,1)325if not cochain:326matrices[-1] = m327else:328matrices[-1] = m.transpose()329for dim in range(min_dim+1):330# X_faces = list(self._domain.faces()[dim])331# Y_faces = list(self._codomain.faces()[dim])332X_faces = list(self._domain.n_cells(dim))333Y_faces = list(self._codomain.n_cells(dim))334num_faces_X = len(X_faces)335num_faces_Y = len(Y_faces)336mval = [0 for i in range(num_faces_X*num_faces_Y)]337for i in X_faces:338y, oriented = self(i, orientation=True)339if y.dimension() < dim:340pass341else:342mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented343m = matrix.Matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True)344if not cochain:345matrices[dim] = m346else:347matrices[dim] = m.transpose()348for dim in range(min_dim+1,max_dim+1):349try:350l1 = len(self._codomain.n_cells(dim))351except KeyError:352l1 = 0353try:354l2 = len(self._domain.n_cells(dim))355except KeyError:356l2 = 0357m = matrix.zero_matrix(base_ring,l1,l2,sparse=True)358if not cochain:359matrices[dim] = m360else:361matrices[dim] = m.transpose()362if not cochain:363return ChainComplexMorphism(matrices,\364self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\365self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))366else:367return ChainComplexMorphism(matrices,\368self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\369self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))370371def image(self):372"""373Computes the image simplicial complex of f.374375EXAMPLES::376377sage: S = SimplicialComplex(3,[[0,1],[2,3]])378sage: T = SimplicialComplex(1,[[0,1]])379sage: f = {0:0,1:1,2:0,3:1}380sage: H = Hom(S,T)381sage: x = H(f)382sage: x.image()383Simplicial complex with vertex set (0, 1) and facets {(0, 1)}384385sage: S = SimplicialComplex(2)386sage: H = Hom(S,S)387sage: i = H.identity()388sage: i.image()389Simplicial complex with vertex set (0, 1, 2) and facets {()}390sage: i.is_surjective()391True392sage: S = SimplicialComplex(5,[[0,1]])393sage: T = SimplicialComplex(3,[[0,1]])394sage: f = {0:0,1:1}395sage: g = {0:0,1:1,2:2,3:3,4:4,5:5}396sage: H = Hom(S,T)397sage: x = H(f)398sage: y = H(g)399sage: x == y400False401sage: x.image()402Simplicial complex with vertex set (0, 1) and facets {(0, 1)}403sage: y.image()404Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(0, 1)}405406"""407fa = [self(i) for i in self._domain.facets()]408return simplicial_complex.SimplicialComplex(set(self._vertex_dictionary.values()),fa,maximality_check=True)409410def domain(self):411"""412Returns the domain of the morphism.413414EXAMPLES::415416sage: S = SimplicialComplex(3,[[0,1],[2,3]])417sage: T = SimplicialComplex(1,[[0,1]])418sage: f = {0:0,1:1,2:0,3:1}419sage: H = Hom(S,T)420sage: x = H(f)421sage: x.domain()422Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 1)}423424"""425return self._domain426427def codomain(self):428"""429Returns the codomain of the morphism.430431EXAMPLES::432433sage: S = SimplicialComplex(3,[[0,1],[2,3]])434sage: T = SimplicialComplex(1,[[0,1]])435sage: f = {0:0,1:1,2:0,3:1}436sage: H = Hom(S,T)437sage: x = H(f)438sage: x.codomain()439Simplicial complex with vertex set (0, 1) and facets {(0, 1)}440441"""442return self._codomain443444def is_surjective(self):445"""446Returns True if and only if self is surjective.447448EXAMPLES::449450sage: S = SimplicialComplex(3,[(0,1,2)])451sage: S452Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2)}453sage: T = SimplicialComplex(2,[(0,1)])454sage: T455Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1)}456sage: H = Hom(S,T)457sage: x = H({0:0,1:1,2:1,3:2})458sage: x.is_surjective()459True460461sage: S = SimplicialComplex(3,[[0,1],[2,3]])462sage: T = SimplicialComplex(1,[[0,1]])463sage: f = {0:0,1:1,2:0,3:1}464sage: H = Hom(S,T)465sage: x = H(f)466sage: x.is_surjective()467True468469"""470return self._codomain == self.image()471472def is_injective(self):473"""474Returns True if and only if self is injective.475476EXAMPLES::477478sage: S = simplicial_complexes.Sphere(1)479sage: T = simplicial_complexes.Sphere(2)480sage: U = simplicial_complexes.Sphere(3)481sage: H = Hom(T,S)482sage: G = Hom(T,U)483sage: f = {0:0,1:1,2:0,3:1}484sage: x = H(f)485sage: g = {0:0,1:1,2:2,3:3}486sage: y = G(g)487sage: x.is_injective()488False489sage: y.is_injective()490True491492"""493v = [self._vertex_dictionary[i[0]] for i in self._domain.faces()[0]]494for i in v:495if v.count(i) > 1:496return False497return True498499def is_identity(self):500"""501If x is an identity morphism, returns True. Otherwise, False.502503EXAMPLES::504505sage: T = simplicial_complexes.Sphere(1)506sage: G = Hom(T,T)507sage: T508Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}509sage: j = G({0:0,1:1,2:2})510sage: j.is_identity()511True512513sage: S = simplicial_complexes.Sphere(2)514sage: T = simplicial_complexes.Sphere(3)515sage: H = Hom(S,T)516sage: f = {0:0,1:1,2:2,3:3}517sage: x = H(f)518sage: x519Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets520sage: x.is_identity()521False522523"""524if self._domain != self._codomain:525return False526else:527f = dict()528for i in self._domain.vertices().set():529f[i] = i530if self._vertex_dictionary != f:531return False532else:533return True534535def fiber_product(self,other,rename_vertices = True):536"""537Fiber product of self and other. Both morphisms should have the same codomain. The method returns a morphism of simplicial complexes, which538is the morphism from the space of the fiber product to the codomain.539540EXAMPLES::541542sage: S = SimplicialComplex(2,[[0,1],[1,2]])543sage: T = SimplicialComplex(2,[[0,2]])544sage: U = SimplicialComplex(1,[[0,1]])545sage: H = Hom(S,U)546sage: G = Hom(T,U)547sage: f = {0:0,1:1,2:0}548sage: g = {0:0,1:1,2:1}549sage: x = H(f)550sage: y = G(g)551sage: z = x.fiber_product(y)552sage: z553Simplicial complex morphism {'L1R2': 1, 'L2R0': 0, 'L0R0': 0} from Simplicial complex with vertex set ('L0R0', 'L1R2', 'L2R0') and facets {('L2R0',), ('L0R0', 'L1R2')} to Simplicial complex with vertex set (0, 1) and facets {(0, 1)}554555"""556if self._codomain != other._codomain:557raise ValueError, "self and other must have the same codomain."558X = self._domain.product(other._domain,rename_vertices = rename_vertices)559v = []560f = dict()561eff1 = self._domain.effective_vertices()562eff2 = other._domain.effective_vertices()563for i in eff1:564for j in eff2:565if self(simplicial_complex.Simplex([i])) == other(simplicial_complex.Simplex([j])):566if rename_vertices:567v.append("L"+str(i)+"R"+str(j))568f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i]569else:570v.append((i,j))571f[(i,j)] = self._vertex_dictionary[i]572return SimplicialComplexMorphism(f,X.generated_subcomplex(v),self._codomain)573574575