# Ticket #12587: trac_12587-simplicial_complex_hash-ts.patch

File trac_12587-simplicial_complex_hash-ts.patch, 163.8 KB (added by tscrim, 9 years ago)
• ## sage/combinat/posets/posets.py

# HG changeset patch
# User Travis Scrimshaw <tscrim@ucdavis.edu>
# Date 1352773572 28800
# Node ID 1746d8f3f09b29a9f84ef4d699c4a3efaf2dbc6f
# Parent ed4766d73d2331becd99980f6557a5af90ce090c
Trac #12587 - Fixed __hash__() for SimplicialComplex by giving immutable option

diff --git a/sage/combinat/posets/posets.py b/sage/combinat/posets/posets.py
 a class FinitePoset(UniqueRepresentation, from sage.homology.simplicial_complex import SimplicialComplex L = self.list() if on_ints: vertices = range(len(L)) iso = dict( [ (L[i],i) for i in vertices ] ) else: vertices = self._elements iso = dict( [ (L[i],i) for i in range(len(L)) ] ) facets = [] for f in self.maximal_chains(): class FinitePoset(UniqueRepresentation, else: facets.append([a.element for a in f]) return SimplicialComplex(vertices, facets) return SimplicialComplex(facets) def promotion(self, i=1): r"""
• ## sage/geometry/polyhedron/base.py

diff --git a/sage/geometry/polyhedron/base.py b/sage/geometry/polyhedron/base.py
 a class Polyhedron_base(SageObject): This method is deprecated. Use triangulate() instead. See http://trac.sagemath.org/11634 for details. sage: sc Simplicial complex with 13 vertices and 20 facets Simplicial complex with 12 vertices and 20 facets """ from sage.misc.superseded import deprecation deprecation(11634, 'This method is deprecated. Use triangulate().simplicial_complex() instead.') from sage.homology.simplicial_complex import SimplicialComplex return SimplicialComplex(vertex_set = self.n_vertices(), maximal_faces = [x[1] for x in self.triangulated_facial_incidences()]) return SimplicialComplex([x[1] for x in self.triangulated_facial_incidences()]) def __add__(self, other): """
• ## sage/geometry/triangulation/element.py

diff --git a/sage/geometry/triangulation/element.py b/sage/geometry/triangulation/element.py
 a class Triangulation(Element): {0: 0, 1: 0, 2: 0, 3: 0} """ from sage.homology.simplicial_complex import SimplicialComplex from sage.misc.all import flatten vertex_set = set(flatten(self)) return SimplicialComplex(vertex_set = vertex_set, maximal_faces = self) return SimplicialComplex(self) @cached_method
• ## sage/graphs/graph.py

diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
 a class Graph(GenericGraph): if self.is_directed() or self.has_loops() or self.has_multiple_edges(): raise ValueError("Self must be an undirected simple graph to have a clique complex.") import sage.homology.simplicial_complex C = sage.homology.simplicial_complex.SimplicialComplex(self.vertices(),self.cliques_maximal(),maximality_check=True) C = sage.homology.simplicial_complex.SimplicialComplex(self.cliques_maximal(), maximality_check=True) C._graph = self return C
• ## sage/homology/cell_complex.py

diff --git a/sage/homology/cell_complex.py b/sage/homology/cell_complex.py
 a is meant as a base class from which othe such, most of its properties are not implemented.  It is meant for use by developers producing new classes, not casual users. .. note:: .. NOTE:: Keywords for :meth:GenericCellComplex.chain_complex, :meth:GenericCellComplex.homology, etc.: any keywords given to Keywords for :meth:~GenericCellComplex.chain_complex, :meth:~GenericCellComplex.homology, etc.: any keywords given to the :meth:~GenericCellComplex.homology method get passed on to the :meth:~GenericCellComplex.chain_complex method and also to the constructor for chain complexes in class GenericCellComplex(SageObject): """ The cells of this cell complex, in the form of a dictionary: the keys are integers, representing dimension, and the value associated to an integer d is the set of d-cells.  If the associated to an integer d is the set of d-cells.  If the optional argument subcomplex is present, then return only the faces which are *not* in the subcomplex. class GenericCellComplex(SageObject): The dimension of this cell complex: the maximum dimension of its cells. .. warning:: .. WARNING:: If the :meth:cells method calls :meth:dimension, then you'll get an infinite loop.  So either don't use class GenericCellComplex(SageObject): def n_cells(self, n, subcomplex=None): """ List of cells of dimension n of this cell complex. List of cells of dimension n of this cell complex. If the optional argument subcomplex is present, then return the n-dimensional faces which are *not* in the subcomplex. class GenericCellComplex(SageObject): :type n: non-negative integer :param subcomplex: a subcomplex of this cell complex. Return the cells which are not in this subcomplex. :type subcomplex: optional, default None :type subcomplex: optional, default None EXAMPLES:: class GenericCellComplex(SageObject): except that :meth:homology accepts a cohomology key word, while this function does not: cohomology is automatically true here.  Indeed, this function just calls :meth:homology with cohomology set to True. :meth:homology with cohomology set to True. :param dim: :param base_ring: class GenericCellComplex(SageObject): EXAMPLES:: sage: circle = SimplicialComplex(2, [[0,1], [1,2], [0, 2]]) sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) sage: circle.cohomology(0) 0 sage: circle.cohomology(1) Z sage: P2 = SimplicialComplex(5, [[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]])   # projective plane sage: P2 = SimplicialComplex([[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]])   # projective plane sage: P2.cohomology(2) C2 sage: P2.cohomology(2, base_ring=GF(2)) class GenericCellComplex(SageObject): Relative cohomology:: sage: T = SimplicialComplex(1, [[0,1]]) sage: U = SimplicialComplex(1, [[0], [1]]) sage: T = SimplicialComplex([[0,1]]) sage: U = SimplicialComplex([[0], [1]]) sage: T.cohomology(1, subcomplex=U) Z class GenericCellComplex(SageObject): (or a single Betti number, if only one dimension is given): the ith Betti number is the rank of the ith homology group. :param dim: If None, then return every Betti number, as :param dim: If None, then return every Betti number, as a dictionary with keys the non-negative integers.  If dim is an integer or list, return the Betti number for each given dimension.  (Actually, if dim is a list, return the Betti numbers, as a dictionary, in the range from min(dim) to max(dim).  If dim is a number, return the Betti number in that dimension.) :type dim: integer or list of integers or None; optional, default None :type dim: integer or list of integers or None; optional, default None :param subcomplex: a subcomplex of this cell complex.  Compute the Betti numbers of the homology relative to this subcomplex. :type subcomplex: optional, default None the Betti numbers of the homology relative to this subcomplex. :type subcomplex: optional, default None EXAMPLES: Build the two-sphere as a three-fold join of a EXAMPLES: Build the two-sphere as a three-fold join of a two-point space with itself:: sage: S = SimplicialComplex(1, [[0], [1]]) sage: S = SimplicialComplex([[0], [1]]) sage: (S*S*S).betti() {0: 1, 1: 0, 2: 1} sage: (S*S*S).betti([1,2]) class GenericCellComplex(SageObject): EXAMPLES:: sage: P = SimplicialComplex(3, [[0, 1], [1,2], [2,3]]).face_poset(); P sage: P = SimplicialComplex([[0, 1], [1,2], [2,3]]).face_poset(); P Finite poset containing 7 elements sage: P.list() [(3,), (2,), (2, 3), (1,), (0,), (0, 1), (1, 2)]
• ## sage/homology/chain_complex.py

diff --git a/sage/homology/chain_complex.py b/sage/homology/chain_complex.py
 a from sage.rings.all import GF, prime_ran def dhsw_snf(mat, verbose=False): """ Preprocess a matrix using the "Elimination algorithm" described by Dumas et al., and then call elementary_divisors on the Dumas et al. [DHSW]_, and then call elementary_divisors on the resulting (smaller) matrix. 'dhsw' stands for 'Dumas, Heckenbach, Saunders, Welker,' and 'snf' stands for 'Smith Normal Form.' .. NOTE:: 'snf' stands for 'Smith Normal Form.' INPUT: -  mat - an integer matrix, either sparse or dense. -  mat -- an integer matrix, either sparse or dense. (They use the transpose of the matrix considered here, so they use rows instead of columns.) def dhsw_snf(mat, verbose=False): Algorithm: go through mat one column at a time.  For each column, add multiples of previous columns to it until either - it's zero, in which case it should be deleted. - its first nonzero entry is 1 or -1, in which case it should be kept. - its first nonzero entry is something else, in which case it is deferred until the second pass. - it's zero, in which case it should be deleted. - its first nonzero entry is 1 or -1, in which case it should be kept. - its first nonzero entry is something else, in which case it is deferred until the second pass. Then do a second pass on the deferred columns. def dhsw_snf(mat, verbose=False): REFERENCES: - Dumas, Heckenbach, Saunders, Welker, "Computing simplicial homology based on efficient Smith normal form algorithms," in "Algebra, geometry, and software systems" (2003), 177-206. .. [DHSW] Dumas, Heckenbach, Saunders, Welker, "Computing simplicial homology based on efficient Smith normal form algorithms," in "Algebra, geometry, and software systems" (2003), 177-206. """ ring = mat.base_ring() rows = mat.nrows() def _latex_module(R, m): INPUT: - R - a commutative ring - m - non-negative integer - R -- a commutative ring - m -- non-negative integer This is used by the _latex_ method for chain complexes. def _latex_module(R, m): return str(latex(FreeModule(R, m))) class ChainComplex(SageObject): """ r""" Define a chain complex. INPUT: -  data - the data defining the chain complex; see below for -  data -- the data defining the chain complex; see below for more details. -  base_ring - a commutative ring (optional), the ring over -  base_ring -- a commutative ring (optional), the ring over which the chain complex is defined. If this is not specified, it is determined by the data defining the chain complex. -  grading_group - a free abelian group (optional, default ZZ), the group over which the chain complex is indexed. -  grading_group -- a free abelian group (optional, default ZZ), the group over which the chain complex is indexed. -  degree - element of grading_group (optional, default 1), -  degree -- element of grading_group (optional, default 1), the degree of the differential. -  check_products - boolean (optional, default True).  If True, check that each consecutive pair of differentials are -  check_products -- boolean (optional, default True). If True, check that each consecutive pair of differentials are composable and have composite equal to zero. OUTPUT: a chain complex .. warning:: .. WARNING:: Right now, homology calculations will only work if the base ring is either ZZ or a field, so please take this into account ring is either \ZZ or a field, so please take this into account when defining a chain complex. Use data to define the chain complex.  This may be in any of the following forms. 1. a dictionary with integers (or more generally, elements of grading_group) for keys, and with data[n] a matrix representing grading_group) for keys, and with data[n] a matrix representing (via left multiplication) the differential coming from degree n.  (Note that the shape of the matrix then determines the rank of the free modules C_n and C_{n+d}.) class ChainComplex(SageObject): 2. a list or tuple of the form [C_0, d_0, C_1, d_1, C_2, d_2, ...], where each C_i is a free module and each d_i is a matrix, as above.  This only makes sense if grading_group is \\ZZ and degree is 1. is \ZZ and degree is 1. 3. a list or tuple of the form [r_0, d_0, r_1, d_1, r_2, d_2, ...], where r_i is the rank of the free module C_i and each d_i is a matrix, as above.  This only makes sense if grading_group is \\ZZ and degree is 1. grading_group is \ZZ and degree is 1. 4. a list or tuple of the form [d_0, d_1, d_2, ...] where each d_i is a matrix, as above.  This only makes sense if grading_group is \\ZZ and degree is 1. grading_group is \ZZ and degree is 1. .. note:: .. NOTE:: In fact, the free modules C_i in case 2 and the ranks r_i in case 3 are ignored: only the matrices are kept, and from class ChainComplex(SageObject): def __init__(self, data=None, **kwds): """ See ChainComplex for full documentation. See :mod:ChainComplex for full documentation. EXAMPLES:: class ChainComplex(SageObject): INPUT: -  dim - element of the grading group (optional, default None).  If this is None, return a dictionary of all of the differentials.  If this is a single element, return the None).  If this is None, return a dictionary of all of the differentials.  If this is a single element, return the differential starting in that dimension. OUTPUT: either a dictionary of all of the differentials or a single class ChainComplex(SageObject): def __cmp__(self, other): """ Return True iff this chain complex is the same as other: that Return True iff this chain complex is the same as other: that is, if the base rings and the matrices of the two are the same. class ChainComplex(SageObject): return -1 def homology(self, dim=None, **kwds): """ r""" The homology of the chain complex in the given dimension. INPUT: -  dim - an element of the grading group for the chain complex (optional, default None): the degree in which to compute homology. If this is None, return the homology in -  dim -- an element of the grading group for the chain complex (optional, default None): the degree in which to compute homology. If this is None, return the homology in every dimension in which the chain complex is possibly nonzero. -  base_ring - a commutative ring (optional, default is the -  base_ring -- a commutative ring (optional, default is the base ring for the chain complex).  Must be either the integers \\ZZ or a field. integers \ZZ or a field. -  generators - boolean (optional, default False).  If -  generators -- boolean (optional, default False).  If True, return generators for the homology groups along with the groups.  NOTE: this is only implemented if the CHomP package is available. the groups. -  verbose - boolean (optional, default False).  If True, print some messages as the homology is computed. .. NOTE:: -  algorithm - string (optional, default 'auto').  The options are 'auto', 'dhsw', 'pari' or 'no_chomp'.  See below for descriptions. This is only implemented if the CHomP package is available. -  verbose - boolean (optional, default False).  If True, print some messages as the homology is computed. -  algorithm - string (optional, default 'auto').  The options are 'auto', 'dhsw', 'pari' or 'no_chomp'. See below for descriptions. OUTPUT: if dim is specified, the homology in dimension dim. Otherwise, the homology in every dimension as a dictionary class ChainComplex(SageObject): ALGORITHM: If algorithm is set to 'auto' (the default), then use If algorithm is set to 'auto' (the default), then use CHomP if available.  (CHomP is available at the web page http://chomp.rutgers.edu/.  It is also an experimental package for Sage.) class ChainComplex(SageObject): dimensions of the homology groups as vector spaces.  Over the integers, compute Smith normal form of the boundary matrices defining the chain complex according to the value of algorithm.  If algorithm is 'auto' or 'no_chomp', then for each relatively small matrix, use the standard Sage algorithm.  If algorithm is 'auto' or 'no_chomp', then for each relatively small matrix, use the standard Sage method, which calls the Pari package.  For any large matrix, reduce it using the Dumas, Heckenbach, Saunders, and Welker elimination algorithm: see :func:sage.homology.chain_complex.dhsw_snf for details. elimination algorithm [DHSW]_: see :func:~sage.homology.chain_complex.dhsw_snf for details. Finally, algorithm may also be 'pari' or 'dhsw', which Finally, algorithm may also be 'pari' or 'dhsw', which forces the named algorithm to be used regardless of the size of the matrices and regardless of whether CHomP is available. As of this writing, CHomP is by far the fastest option, followed by the 'auto' or 'no_chomp' setting of using the followed by the 'auto' or 'no_chomp' setting of using the Dumas, Heckenbach, Saunders, and Welker elimination algorithm for large matrices and Pari for small ones. [DHSW]_ for large matrices and Pari for small ones. .. warning:: .. WARNING:: This only works if the base ring is the integers or a field.  Other values will return an error. class ChainComplex(SageObject): INPUT: -  dim - an element of the grading group for the chain complex or None (optional, default None).  If None, then return every Betti number, as a dictionary indexed by -  dim -- an element of the grading group for the chain complex or None (optional, default None).  If None, then return every Betti number, as a dictionary indexed by degree.  If an element of the grading group, then return the Betti number in that dimension. -  base_ring - a commutative ring (optional, default is the -  base_ring -- a commutative ring (optional, default is the base ring for the chain complex).  Compute homology with these coefficients.  Must be either the integers or a field. class ChainComplex(SageObject): raise NotImplementedError, "Not implemented: unable to compute Betti numbers if the base ring is not ZZ or a field." def torsion_list(self, max_prime, min_prime=2): """ r""" Look for torsion in this chain complex by computing its mod p homology for a range of primes p. INPUT: -  max_prime - prime number: search for torsion mod p for -  max_prime -- prime number: search for torsion mod p for all p strictly less than this number. -  min_prime - prime (optional, default 2): search for -  min_prime -- prime (optional, default 2): search for torsion mod p for primes at least as big as this. Return a list of pairs (p, dims) where p is a prime at class ChainComplex(SageObject): max_prime.  Compute the mod P homology of C, and use this as the base-line computation: the assumption is that this is isomorphic to the integral homology tensored with \\GF{P}.  Then compute the mod p homology for a range of \GF{P}.  Then compute the mod p homology for a range of primes p, and record whenever the answer differs from the base-line answer. class ChainComplex(SageObject): def _flip_(self): """ Flip chain complex upside down (degree n gets changed to degree -n), thus turning a chain complex into a cochain complex without changing the homology (except for flipping it, too). degree -n), thus turning a chain complex into a cochain complex without changing the homology (except for flipping it, too). EXAMPLES:: class ChainComplex(SageObject): def _chomp_repr_(self): r""" String representation of self suitable for use by the CHomP String representation of self suitable for use by the CHomP program. Since CHomP can only handle chain complexes, not cochain class ChainComplex(SageObject): class HomologyGroup_class(AdditiveAbelianGroup_fixed_gens): """ Abelian group on n generators. This class inherits from AdditiveAbelianGroup; see that for more documentation. The main :class:AdditiveAbelianGroup; see that for more documentation. The main difference between the classes is in the print representation. EXAMPLES:: class HomologyGroup_class(AdditiveAbelia """ def __init__(self, n, invfac): """ See HomologyGroup for full documentation. See :func:HomologyGroup for full documentation. EXAMPLES:: class HomologyGroup_class(AdditiveAbelia def HomologyGroup(n, invfac=None): """ Abelian group on n generators. This class inherits from AdditiveAbelianGroup; see that for more documentation.  The main difference between the classes is in the print representation. Abelian group on n generators. EXAMPLES::
• ## sage/homology/chain_complex_homspace.py

diff --git a/sage/homology/chain_complex_homspace.py b/sage/homology/chain_complex_homspace.py
 a Homspaces between chain complexes Note that some significant functionality is lacking. Namely, the homspaces are not actually modules over the base ring. It will be necessary to enrich some of the structure of chain complexes for this to be naturally available. On other hand, there are various overloaded operators. __mul__ acts as composition. One can __add__, and one can __mul__ with a ring element on the right. available. On other hand, there are various overloaded operators. __mul__ acts as composition. One can __add__, and one can __mul__ with a ring element on the right. EXAMPLES:: EXAMPLES:: sage: C = S.chain_complex() sage: G = Hom(C,C) sage: w = G(f) sage: w==x sage: w == x True """ import sage.homology.chain_complex_morph def is_ChainComplexHomspace(x): """ Returns True if and only if x is a morphism of chain complexes. Returns True if and only if x is a morphism of chain complexes. EXAMPLES:: sage: from sage.homology.chain_complex_homspace import is_ChainComplexHomspace sage: T = SimplicialComplex(17,[[1,2,3,4],[7,8,9]]) sage: C = T.chain_complex(augmented=True,cochain=True) sage: T = SimplicialComplex([[1,2,3,4],[7,8,9]]) sage: C = T.chain_complex(augmented=True, cochain=True) sage: G = Hom(C,C) sage: is_ChainComplexHomspace(G) True class ChainComplexHomspace(sage.categori EXAMPLES:: sage: T = SimplicialComplex(17,[[1,2,3,4],[7,8,9]]) sage: C = T.chain_complex(augmented=True,cochain=True) sage: T = SimplicialComplex([[1,2,3,4],[7,8,9]]) sage: C = T.chain_complex(augmented=True, cochain=True) sage: G = Hom(C,C) sage: G Set of Morphisms from Chain complex with at most 5 nonzero terms over Integer Ring to Chain complex with at most 5 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring class ChainComplexHomspace(sage.categori """ def __call__(self, f): """ f is a dictionary of matrices in the basis of the chain complex. f is a dictionary of matrices in the basis of the chain complex. EXAMPLES:: class ChainComplexHomspace(sage.categori sage: x = i.associated_chain_complex_morphism() sage: f = x._matrix_dictionary sage: y = G(f) sage: x==y sage: x == y True """
• ## sage/homology/chain_complex_morphism.py

diff --git a/sage/homology/chain_complex_morphism.py b/sage/homology/chain_complex_morphism.py
 a AUTHORS: - Benjamin Antieau (2009.06) This module implements morphisms of chain complexes. The input is a dictionary whose keys are in the grading group of the chain complex and whose values are matrix morphisms. - Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to work with the homset cache. This module implements morphisms of chain complexes. The input is a dictionary whose keys are in the grading group of the chain complex and whose values are matrix morphisms. EXAMPLES:: from sage.rings.integer_ring import ZZ def is_ChainComplexMorphism(x): """ Returns True if and only if x is a chain complex morphism. Returns True if and only if x is a chain complex morphism. EXAMPLES:: class ChainComplexMorphism(SageObject): def __neg__(self): """ Returns -x. Returns -x. EXAMPLES:: class ChainComplexMorphism(SageObject): def __add__(self,x): """ Returns self+x. Returns self + x. EXAMPLES:: class ChainComplexMorphism(SageObject): def __mul__(self,x): """ Returns self*x if self and x are composable morphisms or if x is an element of the base_ring. Returns self * x if self and x are composable morphisms or if x is an element of the base ring. EXAMPLES:: class ChainComplexMorphism(SageObject): def __rmul__(self,x): """ Returns x*self if x is an element of the base_ring. Returns x * self if x is an element of the base ring. EXAMPLES:: class ChainComplexMorphism(SageObject): def __sub__(self,x): """ Returns self-x. Returns self - x. EXAMPLES:: class ChainComplexMorphism(SageObject): def __eq__(self,x): """ Returns True if and only if self==x. Returns True if and only if self == x. EXAMPLES:: sage: S = SimplicialComplex(3) sage: S = SimplicialComplex(is_mutable=False) sage: H = Hom(S,S) sage: i = H.identity() sage: x = i.associated_chain_complex_morphism() class ChainComplexMorphism(SageObject): sage: C = S.chain_complex() sage: G = Hom(C,C) sage: y = G(f) sage: x==y sage: x == y True """ class ChainComplexMorphism(SageObject): def _repr_(self): """ Returns the string representation of self. Returns the string representation of self. EXAMPLES:: sage: S = SimplicialComplex(3) sage: S = SimplicialComplex(is_mutable=False) sage: H = Hom(S,S) sage: i = H.identity() sage: x = i.associated_chain_complex_morphism()
• ## sage/homology/examples.py

diff --git a/sage/homology/examples.py b/sage/homology/examples.py
 a These provide examples of large simplici simplices. All of these examples are accessible by typing "simplicial_complexes.NAME", where "NAME" is the name of the example. You can get a list by typing "simplicial_complexes." and hitting the simplicial_complexes.NAME, where NAME is the name of the example. You can get a list by typing simplicial_complexes. and hitting the TAB key:: simplicial_complexes.ChessboardComplex from sage.combinat.subset import Subsets import sage.misc.prandom as random def matching(A, B): """ List of maximal matchings between the sets A and B: a matching is a set of pairs (a,b) in A x B where each a, b appears in at most one pair.  A maximal matching is one which is maximal with respect to inclusion of subsets of A x B. r""" List of maximal matchings between the sets A and B. A matching is a set of pairs (a,b) \in A \times B where each a and b appears in at most one pair.  A maximal matching is one which is maximal with respect to inclusion of subsets of A \times B. INPUT: -  A, B - list, tuple, or indeed anything which can be -  A, B -- list, tuple, or indeed anything which can be converted to a set. EXAMPLES:: sage: from sage.homology.examples import matching sage: matching([1,2], [3,4]) [set([(1, 3), (2, 4)]), set([(2, 3), (1, 4)])] def matching(A, B): def facets_for_RP4(): """ Return the list of facets for a minimal triangulation of 4-dimensional real projective space. We use vertices numbered 1 through 16, define two facets, and define a certain subgroup G of the symmetric group S_{16}. Then the set of all facets is the G-orbit of the two given facets. real projective space. We use vertices numbered 1 through 16, define two facets, and define a certain subgroup G of the symmetric group S_{16}. Then the set of all facets is the G-orbit of the two given facets. See the description in Example 3.12 in Datta [Da2007]_. EXAMPLES:: def facets_for_RP4(): def facets_for_K3(): """ Returns the facets for a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 Returns the facets for a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 vertices and 288 facets. The facets are obtained by constructing a few facets and a permutation group G, and then computing the G-orbit of those facets. See Casella and Kühnel in [CK2001]_ and Spreer and Kühnel [SK2011]_; the construction here uses the labeling from Spreer and Kühnel. G-orbit of those facets. See Casella and Kühnel in [CK2001]_ and Spreer and Kühnel [SK2011]_; the construction here uses the labeling from Spreer and Kühnel. EXAMPLES:: class SimplicialComplexExamples(): Some examples of simplicial complexes. Here are the available examples; you can also type "simplicial_complexes."  and hit tab to get a list:: simplicial_complexes.  and hit tab to get a list:: ChessboardComplex ComplexProjectivePlane K3Surface KleinBottle MatchingComplex MooreSpace NotIConnectedGraphs PoincareHomologyThreeSphere RandomComplex RealProjectivePlane RealProjectiveSpace Simplex Sphere SurfaceOfGenus Torus - :meth:ChessboardComplex - :meth:ComplexProjectivePlane - :meth:K3Surface - :meth:KleinBottle - :meth:MatchingComplex - :meth:MooreSpace - :meth:NotIConnectedGraphs - :meth:PoincareHomologyThreeSphere - :meth:RandomComplex - :meth:RealProjectivePlane - :meth:RealProjectiveSpace - :meth:Simplex - :meth:Sphere - :meth:SurfaceOfGenus - :meth:Torus EXAMPLES:: class SimplicialComplexExamples(): def Sphere(self,n): """ A minimal triangulation of the n-dimensional sphere. A minimal triangulation of the n-dimensional sphere. INPUT: -  n - positive integer -  n -- positive integer EXAMPLES:: class SimplicialComplexExamples(): """ S = Simplex(n+1) facets = S.faces() S = SimplicialComplex(n+1, facets) return S return SimplicialComplex(facets, is_mutable=False) def Simplex(self, n): """ class SimplicialComplexExamples(): INPUT: -  n - a non-negative integer -  n -- a non-negative integer OUTPUT: the simplicial complex consisting of the n-simplex on vertices (0, 1, ..., n) and all of its faces. class SimplicialComplexExamples(): sage: simplicial_complexes.Simplex(5).euler_characteristic() 1 """ S = Simplex(n) return SimplicialComplex(n, list(S)) return SimplicialComplex([Simplex(n)], is_mutable=False) def Torus(self): """ class SimplicialComplexExamples(): sage: simplicial_complexes.Torus().homology(1) Z x Z """ return SimplicialComplex(6, [[0,1,2], [1,2,4], [1,3,4], [1,3,6], [0,1,5], [1,5,6], [2,3,5], [2,4,5], [2,3,6], [0,2,6], [0,3,4], [0,3,5], [4,5,6], [0,4,6]]) return SimplicialComplex([[0,1,2], [1,2,4], [1,3,4], [1,3,6], [0,1,5], [1,5,6], [2,3,5], [2,4,5], [2,3,6], [0,2,6], [0,3,4], [0,3,5], [4,5,6], [0,4,6]], is_mutable=False) def RealProjectivePlane(self): """ class SimplicialComplexExamples(): sage: P.cohomology(2, base_ring=GF(2)) Vector space of dimension 1 over Finite Field of size 2 """ return SimplicialComplex(5, [[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]]) return SimplicialComplex([[0,1,2], [0,2,3], [0,1,5], [0,4,5], [0,3,4], [1,2,4], [1,3,4], [1,3,5], [2,3,5], [2,4,5]], is_mutable=False) ProjectivePlane = RealProjectivePlane class SimplicialComplexExamples(): return SimplicialComplex([[2,3,7], [1,2,3], [1,3,5], [1,5,7], [1,4,7], [2,4,6], [1,2,6], [1,6,0], [1,4,0], [2,4,0], [3,4,7], [3,4,6], [3,5,6], [5,6,0], [2,5,0], [2,5,7]]) [3,5,6], [5,6,0], [2,5,0], [2,5,7]], is_mutable=False) def SurfaceOfGenus(self, g, orientable=True): """ A surface of genus g. A surface of genus g. INPUT: -  g - a non-negative integer.  The desired genus -  g -- a non-negative integer.  The desired genus -  orientable - boolean (optional, default True). If True, return an orientable surface, and if False, return a non-orientable surface. -  orientable -- boolean (optional, default True). If True, return an orientable surface, and if False, return a non-orientable surface. In the orientable case, return a sphere if g is zero, and otherwise return a g-fold connected sum of a torus with itself. otherwise return a g-fold connected sum of a torus with itself. In the non-orientable case, raise an error if g is zero.  If g is positive, return a g-fold connected sum of a class SimplicialComplexExamples(): T = simplicial_complexes.RealProjectivePlane() S = T for i in range(g-1): S = S.connected_sum(T) S = S.connected_sum(T, is_mutable=False) return S def MooreSpace(self, q): """ Triangulation of the mod q Moore space. Triangulation of the mod q Moore space. INPUT: -  q - integer, at least 2 -  q -0 integer, at least 2 This is a simplicial complex with simplices of dimension 0, 1, and 2, such that its reduced homology is isomorphic to class SimplicialComplexExamples(): Simplicial complex with 19 vertices and 54 facets """ if q <= 1: raise ValueError, "The mod q Moore space is only defined if q is at least 2" raise ValueError("The mod q Moore space is only defined if q is at least 2") if q == 2: return simplicial_complexes.RealProjectivePlane() vertices = [1, 2, 3] return RealProjectivePlane() facets = [] for i in range(q): Ai = "A" + str(i) Aiplus = "A" + str((i+1)%q) Bi = "B" + str(i) vertices.append(Ai) vertices.append(Bi) facets.append([1, 2, Ai]) facets.append([2, 3, Ai]) facets.append([3, 1, Bi]) class SimplicialComplexExamples(): Ai = "A" + str(i) Aiplus = "A" + str((i+1)%q) facets.append(["A0", Ai, Aiplus]) return SimplicialComplex(vertices, facets) return SimplicialComplex(facets, is_immutable=True) def ComplexProjectivePlane(self): """ class SimplicialComplexExamples(): [7, 8, 1, 2, 3], [8, 9, 2, 3, 1], [9, 7, 3, 1, 2], [7, 8, 1, 2, 6], [8, 9, 2, 3, 4], [9, 7, 3, 1, 5], [8, 9, 3, 1, 6], [9, 7, 1, 2, 4], [7, 8, 2, 3, 5], [9, 7, 2, 3, 6], [7, 8, 3, 1, 4], [8, 9, 1, 2, 5]]) [9, 7, 2, 3, 6], [7, 8, 3, 1, 4], [8, 9, 1, 2, 5]], is_mutable=False) def PoincareHomologyThreeSphere(self): """ class SimplicialComplexExamples(): [7, 8, 11, 15], [7, 8, 14, 15], [7, 9, 14, 15], [8, 12, 14, 15], [9, 10, 11, 12], [9, 10, 11, 16], [9, 10, 15, 16], [9, 11, 14, 16], [9, 14, 15, 16], [10, 11, 13, 16], [10, 13, 15, 16], [11, 13, 14, 16], [12, 13, 14, 15], [13, 14, 15, 16]]) [11, 13, 14, 16], [12, 13, 14, 15], [13, 14, 15, 16]], is_mutable=False) def RealProjectiveSpace(self, n): r""" class SimplicialComplexExamples(): INPUT: - n - integer, the dimension of the real projective space - n -- integer, the dimension of the real projective space to construct The first few cases are pretty trivial: class SimplicialComplexExamples(): but if you have CHomP installed, Sage will use that and the computation should only take a second or two.  (You can download CHomP from http://chomp.rutgers.edu/, or you can install it as a Sage package using "sage -i chomp"). :: install it as a Sage package using sage -i chomp). :: sage: P5.homology()  # long time # optional - CHomP {0: 0, 1: C2, 2: 0, 3: C2, 4: 0, 5: Z} class SimplicialComplexExamples(): [4, 5, 6, 11], [1, 3, 5, 10], [1, 5, 6, 11], [2, 4, 8, 10], [3, 4, 8, 9], [4, 5, 7, 9], [1, 3, 5, 11], [1, 5, 8, 10], [2, 5, 7, 8], [3, 5, 9, 10], [4, 6, 7, 10], [1, 3, 7, 10], [1, 6, 8, 9], [2, 5, 7, 9], [3, 6, 7, 8], [5, 6, 7, 8]]) [1, 6, 8, 9], [2, 5, 7, 9], [3, 6, 7, 8], [5, 6, 7, 8]], is_mutable=False) if n == 4: return SimplicialComplex( [(1, 3, 8, 12, 13), (2, 7, 8, 13, 16), (4, 8, 9, 12, 14), class SimplicialComplexExamples(): (4, 7, 8, 12, 15), (2, 3, 5, 10, 15), (2, 6, 8, 10, 16), (3, 4, 10, 15, 16), (1, 5, 6, 14, 16), (2, 3, 5, 14, 15), (2, 3, 7, 9, 16), (2, 7, 9, 13, 14), (3, 4, 6, 7, 15), (4, 8, 10, 14, 16), (3, 4, 7, 15, 16), (2, 8, 10, 15, 16)]) (4, 8, 10, 14, 16), (3, 4, 7, 15, 16), (2, 8, 10, 15, 16)], is_mutable=False) if n >= 5: # Use the construction given by Datta in Example 3.21. V = set(range(0, n+2)) class SimplicialComplexExamples(): else: new.append(v) facets.add(tuple(new)) return SimplicialComplex(list(facets)) return SimplicialComplex(list(facets), is_mutable=False) def K3Surface(self): """ Returns a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 vertices Returns a minimal triangulation of the K3 surface. This is a pure simplicial complex of dimension 4 with 16 vertices and 288 facets. It was constructed by Casella and Kühnel in [CK2001]_. The construction here uses the labeling from Spreer and Kühnel [SK2011]_. class SimplicialComplexExamples(): (6, 9, 10, 13, 16), (2, 4, 9, 13, 16), (1, 6, 7, 8, 13), (1, 4, 12, 13, 15), (2, 4, 7, 10, 11), (1, 4, 9, 11, 13), (6, 7, 11, 14, 16), (1, 4, 9, 11, 16), (1, 4, 12, 15, 16), (1, 2, 4, 7, 15), (2, 3, 7, 8, 16), (1, 4, 5, 6, 10)]) (1, 2, 4, 7, 15), (2, 3, 7, 8, 16), (1, 4, 5, 6, 10)], is_mutable=False) ############################################################### # examples from graph theory: def NotIConnectedGraphs(self, n, i): """ The simplicial complex of all graphs on n vertices which are not i-connected. The simplicial complex of all graphs on n vertices which are not i-connected. Fix an integer n>0 and consider the set of graphs on n vertices.  View each graph as its set of edges, so it is a class SimplicialComplexExamples(): INPUT: -  n, i - non-negative integers with i at most n -  n, i -- non-negative integers with i at most n See Dumas et al. [DHSW2003]_ for information on computing its homology by computer, and see Babson et al. [BBLSW1999]_ for theory.  For example, Babson et al. show that when i=2, the reduced homology of See Dumas et al. [DHSW2003]_ for information on computing its homology by computer, and see Babson et al. [BBLSW1999]_ for theory.  For example, Babson et al. show that when i=2, the reduced homology of this complex is nonzero only in dimension 2n-5, where it is free abelian of rank (n-2)!. class SimplicialComplexExamples(): bad_edge = (min(v,w), max(v,w)) facet = facet.difference(Set([bad_edge])) facets.append(facet) return SimplicialComplex(E_list, facets) return SimplicialComplex(facets, is_mutable=False) def MatchingComplex(self, n): """ The matching complex of graphs on n vertices. The matching complex of graphs on n vertices. Fix an integer n>0 and consider a set V of n vertices. A 'partial matching' on V is a graph formed by edges so that class SimplicialComplexExamples(): INPUT: -  n - positive integer. -  n -- positive integer. See Dumas et al. [DHSW2003]_ for information on computing its homology by computer, and see Wachs [Wa2003]_ for an expository article about the theory.  For example, the homology of these complexes seems to See Dumas et al. [DHSW2003]_ for information on computing its homology by computer, and see Wachs [Wa2003]_ for an expository article about the theory.  For example, the homology of these complexes seems to have only mod 3 torsion, and this has been proved for the bottom non-vanishing homology group for the matching complex M_n. bottom non-vanishing homology group for the matching complex M_n. EXAMPLES:: class SimplicialComplexExamples(): 345-385) """ G_vertices = Set(range(1,n+1)) E_list = [] for w in G_vertices: for v in range(1,w): E_list.append((v,w)) facets = [] if is_even(n): half = int(n/2) class SimplicialComplexExamples(): for pair in M: facet.append(tuple(sorted(pair))) facets.append(facet) return SimplicialComplex(E_list, facets) return SimplicialComplex(facets, is_mutable=False) def ChessboardComplex(self, n, i): r""" The chessboard complex for an n by i chessboard. The chessboard complex for an n \times i chessboard. Fix integers n, i > 0 and consider sets V of n vertices and W of i vertices.  A 'partial matching' between V and class SimplicialComplexExamples(): INPUT: -  n, i - positive integers. -  n, i -- positive integers. See Dumas et al. [DHSW2003]_ for information on computing its homology by computer, and see Wachs [Wa2003]_ for an expository article about class SimplicialComplexExamples(): for w in B: E_dict[(v,w)] = index index += 1 E = range(n*i) facets = [] for M in matching(A, B): facet = [] for pair in M: facet.append(E_dict[pair]) facets.append(facet) return SimplicialComplex(E, facets) return SimplicialComplex(facets, is_mutable=False) def RandomComplex(self, n, d, p=0.5): """ A random d-dimensional simplicial complex on n vertices. A random d-dimensional simplicial complex on n vertices. INPUT: - n - number of vertices - d - dimension of the complex -  p - floating point number between 0 and 1 - n -- number of vertices - d -- dimension of the complex -  p -- floating point number between 0 and 1 (optional, default 0.5) A random d-dimensional simplicial complex on n vertices, as defined for example by Meshulam and Wallach [MW2009]_, is constructed as follows: take n vertices and include all of the simplices of dimension strictly less than d, and then for each possible simplex of dimension d, include it with probability p. possible simplex of dimension d, include it with probability p. EXAMPLES:: class SimplicialComplexExamples(): facets = Subsets(vertices, d).list() maybe = Subsets(vertices, d+1) facets.extend([f for f in maybe if random.random() <= p]) return SimplicialComplex(n-1, facets) return SimplicialComplex(facets, is_mutable=False) simplicial_complexes = SimplicialComplexExamples()
• ## sage/homology/simplicial_complex.py

diff --git a/sage/homology/simplicial_complex.py b/sage/homology/simplicial_complex.py
 a AUTHORS: remove_facet, and is_flag_complex methods; cached the output of the graph() method. - Travis Scrimshaw (2012-08-17): Made :class:SimplicialComplex have an immutable option, and added __hash__() function which checks to make sure it is immutable. Made :meth:SimplicialComplex.remove_face() into a mutator. Deprecated the vertex_set parameter. This module implements the basic structure of finite simplicial complexes. Given a set V of "vertices", a simplicial complex on V is a collection K of subsets of V satisfying the condition that if tuple, or set, or it can be a non-negati the vertex set is (0, ..., n).  Also specify the facets: the maximal faces. .. note:: .. NOTE:: The elements of the vertex set are not automatically contained in the simplicial complex: each one is only included if and only if it is a vertex of at least one of the specified facets. .. note:: .. NOTE:: This class derives from :class:~sage.homology.cell_complex.GenericCellComplex, and so faces. EXAMPLES:: sage: SimplicialComplex([1, 3, 7], [[1], [3, 7]]) sage: SimplicialComplex([[1], [3, 7]]) Simplicial complex with vertex set (1, 3, 7) and facets {(3, 7), (1,)} sage: SimplicialComplex(2)   # the empty simplicial complex Simplicial complex with vertex set (0, 1, 2) and facets {()} sage: X = SimplicialComplex(3, [[0,1], [1,2], [2,3], [3,0]]) sage: SimplicialComplex()   # the empty simplicial complex Simplicial complex with vertex set () and facets {()} sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [3,0]]) sage: X Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 2), (2, 3), (0, 3), (0, 1)} sage: X.stanley_reisner_ring() EXAMPLES:: Sage can perform a number of operations on simplicial complexes, such as the join and the product, and it can also compute homology:: sage: S = SimplicialComplex(2, [[0,1], [1,2], [0,2]]) # circle sage: S = SimplicialComplex([[0,1], [1,2], [0,2]]) # circle sage: T = S.product(S)  # torus sage: T Simplicial complex with 9 vertices and 18 facets as the join and the product, and it can Sage knows about some basic combinatorial data associated to a simplicial complex:: sage: X = SimplicialComplex(3, [[0,1], [1,2], [2,3], [0,3]]) sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [0,3]]) sage: X.f_vector() [1, 4, 4] sage: X.face_poset() Finite poset containing 8 elements sage: X.stanley_reisner_ring() Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3, x0*x2) Mutability (see :trac:12587):: sage: S = SimplicialComplex([[1,4], [2,4]]) sage: S.add_face([1,3]) sage: S.remove_face([1,3]); S Simplicial complex with vertex set (1, 2, 3, 4) and facets {(2, 4), (1, 4), (3,)} sage: hash(S) Traceback (most recent call last): ... ValueError: This simplicial complex must be immutable. Call set_immutable(). sage: S = SimplicialComplex([[1,4], [2,4]]) sage: S.set_immutable() sage: S.add_face([1,3]) Traceback (most recent call last): ... ValueError: This simplicial complex is not mutable sage: S.remove_face([1,3]) Traceback (most recent call last): ... ValueError: This simplicial complex is not mutable sage: hash(S) 264071120            # 32-bit -3244381654768326704 # 64-bit sage: S2 = SimplicialComplex([[1,4], [2,4]], is_mutable=False) sage: hash(S2) == hash(S) True """ # possible future directions for SimplicialComplex: def lattice_paths(t1, t2, length=None): :param t1: labeling for vertices :param t2: labeling for vertices :param length: if not None, then an integer, the length of the desired path. :type length: integer or None; optional, default None :param length: if not None, then an integer, the length of the desired path. :type length: integer or None; optional, default None :type t1: tuple, list, other iterable :type t2: tuple, list, other iterable :return: list of lists of vertices making up the paths as described above def lattice_paths(t1, t2, length=None): def rename_vertex(n, keep, left = True): """ Rename a vertex: the vertices from the list 'keep' get Rename a vertex: the vertices from the list keep get relabeled 0, 1, 2, ..., in order.  Any other vertex (e.g. 4) gets renamed to by prepending an 'L' or an 'R' (thus to either 'L4' or 'R4'), depending on whether the argument left is True or False. 'R4'), depending on whether the argument left is True or False. :param n: a 'vertex': either an integer or a string :param keep: a list of three vertices :param left: if True, rename for use in left factor :type left: boolean; optional, default True This is used by the connected_sum method for simplicial complexes. :param left: if True, rename for use in left factor :type left: boolean; optional, default True This is used by the :meth:~SimplicialComplex.connected_sum method for simplicial complexes. EXAMPLES:: class Simplex(SageObject): vertex must be hashable, so it should be a number, a string, or a tuple, for instance, but not a list. .. warning:: .. WARNING:: The vertices should be distinct, and no error checking is done to make sure this is the case. class Simplex(SageObject): def __init__(self, X): """ Define a simplex.  See Simplex for full documentation. Define a simplex.  See :class:Simplex for full documentation. EXAMPLES:: class Simplex(SageObject): def is_face(self, other): """ Return True iff this simplex is a face of other. Return True iff this simplex is a face of other. EXAMPLES:: class Simplex(SageObject): def __contains__(self, x): """ Return True iff x is a vertex of this simplex. Return True iff x is a vertex of this simplex. EXAMPLES:: class Simplex(SageObject): def __getitem__(self, n): """ Return the nth vertex in this simplex. Return the n-th vertex in this simplex. EXAMPLES:: class Simplex(SageObject): :param n: an integer between 0 and the dimension of this simplex :type n: integer :return: the simplex obtained by removing the nth vertex from this simplex :return: the simplex obtained by removing the n-th vertex from this simplex EXAMPLES:: class Simplex(SageObject): def dimension(self): """ The dimension of this simplex: the number of vertices minus 1. The dimension of this simplex. The dimension of a simplex is the number of vertices minus 1. EXAMPLES:: class Simplex(SageObject): def is_empty(self): """ Return True iff this simplex is the empty simplex. Return True iff this simplex is the empty simplex. EXAMPLES:: class Simplex(SageObject): :param right: the other simplex (the right-hand factor) :param rename_vertices: If this is True, the vertices in the :param rename_vertices: If this is True, the vertices in the join will be renamed by this formula: vertex "v" in the left-hand factor --> vertex "Lv" in the join, vertex "w" in the right-hand factor --> vertex "Rw" in the join.  If class Simplex(SageObject): renaming the vertices; this may cause problems if the two factors have any vertices with names in common. :type rename_vertices: boolean; optional, default True :type rename_vertices: boolean; optional, default True EXAMPLES:: class Simplex(SageObject): return Simplex(vertex_set) def product(self, other, rename_vertices=True): """ r""" The product of this simplex with another one, as a list of simplices. :param other: the other simplex :param rename_vertices: If this is False, then the vertices in :param rename_vertices: If this is False, then the vertices in the product are the set of ordered pairs (v,w) where v is a vertex in the left-hand factor (self) and w is a vertex in the right-hand factor (other). If this is True, then the vertices are renamed as "LvRw" (e.g., the True, then the vertices are renamed as "LvRw" (e.g., the vertex (1,2) would become "L1R2").  This is useful if you want to define the Stanley-Reisner ring of the complex: vertex names like (0,1) are not suitable for that, while vertex names like "L0R1" are. :type rename-vertices: boolean; optional, default True Algorithm: see Hatcher, p. 277-278 (who in turn refers to Eilenberg-Steenrod, p. 68): given Simplex(m) and Simplex(n), then Simplex(m) x Simplex(n) can be :type rename-vertices: boolean; optional, default True Algorithm: see Hatcher, p. 277-278 [Hat]_ (who in turn refers to Eilenberg-Steenrod, p. 68): given S = Simplex(m) and T = Simplex(n), then S \times T can be triangulated as follows: for each path f from (0,0) to (m,n) along the integer grid in the plane, going up or right at each lattice point, associate an (m+n)-simplex with class Simplex(SageObject): where v is a vertex in the left-hand factor and w is a vertex in the right-hand factor. .. note:: This produces a list of simplices -- not a Simplex, not a SimplicialComplex. .. NOTE:: This produces a list of simplices -- not a :class:Simplex, not a :class:SimplicialComplex. EXAMPLES:: class Simplex(SageObject): REFERENCES: - A. Hatcher, "Algebraic Topology", Cambridge University Press (2002). .. [Hat] A. Hatcher, "Algebraic Topology", Cambridge University Press (2002). """ if not rename_vertices: return [Simplex(x) for x in lattice_paths(self.tuple(), other.tuple())] class Simplex(SageObject): def __cmp__(self, other): """ Return True iff this simplex is the same as other: that Return True iff this simplex is the same as other: that is, if the vertices of the two are the same, even with a different ordering class SimplicialComplex(GenericCellCompl r""" Define a simplicial complex. :param vertex_set: set of vertices :param maximal_faces: set of maximal faces :param vertex_check: see below :type vertex_check: boolean; optional, default True :param maximality_check: see below :type maximality_check: boolean; optional, default True :type maximality_check: boolean; optional, default True :param sort_facets: see below :type sort_facets: boolean; optional, default True :type sort_facets: boolean; optional, default True :param name_check: see below :type name_check: boolean; optional, default False :type name_check: boolean; optional, default False :param is_mutable: Set to False to make this immutable :type is_mutable: boolean; optional, default True :return: a simplicial complex vertex_set may be a non-negative integer n (in which case the simplicial complex will have n+1 vertices \{0, 1, ..., n\}), or it may be anything which may be converted to a tuple. Call the elements of this 'vertices'. maximal_faces should be a list or tuple or set (indeed, anything which may be converted to a set) whose elements are lists (or tuples, etc.) of vertices.  Maximal faces are also known as 'facets'. If vertex_check is True, check to see that each given maximal face is a subset of the vertex set. Raise an error for any bad face. If maximality_check is True, check that each maximal face is, If maximality_check is True, check that each maximal face is, in fact, maximal. In this case, when producing the internal representation of the simplicial complex, omit those that are not. It is highly recommended that this be True; various methods for It is highly recommended that this be True; various methods for this class may fail if faces which are claimed to be maximal are in fact not. If sort_facets is True, sort the vertices in each facet.  If If sort_facets is True, sort the vertices in each facet.  If the vertices in different facets are not ordered compatibly (e.g., if you have facets (1, 3, 5) and (5, 3, 8)), then homology if you have facets (1, 3, 5) and (5, 3, 8)), then homology calculations may have unpredictable results. If name_check is True, check the names of the vertices to see If name_check is True, check the names of the vertices to see if they can be easily converted to generators of a polynomial ring -- use this if you plan to use the Stanley-Reisner ring for the simplicial complex. .. note:: The elements of vertex_set are not automatically in the simplicial complex: each one is only included if it is a vertex of at least one of the specified facets. EXAMPLES:: sage: SimplicialComplex(4, [[1,2], [1,4]]) Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(1, 2), (1, 4)} sage: SimplicialComplex(3, [[0,2], [0,3], [0]]) Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2), (0, 3)} sage: SimplicialComplex(3, [[0,2], [0,3], [0]], maximality_check=False) Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2), (0, 3), (0,)} sage: S = SimplicialComplex(['a', 'b', 'c'], (('a', 'b'), ('a', 'c'), ('b', 'c'))) sage: SimplicialComplex([[1,2], [1,4]]) Simplicial complex with vertex set (1, 2, 4) and facets {(1, 2), (1, 4)} sage: SimplicialComplex([[0,2], [0,3], [0]]) Simplicial complex with vertex set (0, 2, 3) and facets {(0, 2), (0, 3)} sage: SimplicialComplex([[0,2], [0,3], [0]], maximality_check=False) Simplicial complex with vertex set (0, 2, 3) and facets {(0, 2), (0, 3), (0,)} sage: S = SimplicialComplex((('a', 'b'), ['a', 'c'], ('b', 'c'))) sage: S Simplicial complex with vertex set ('a', 'b', 'c') and facets {('b', 'c'), ('a', 'c'), ('a', 'b')} class SimplicialComplex(GenericCellCompl TESTS:: sage: S = SimplicialComplex(['a', 'b', 'c'], (('a', 'b'), ('a', 'c'), ('b', 'c'))) sage: S = SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c'))) sage: S == loads(dumps(S)) True """ def __init__(self, vertex_set=[], maximal_faces=[], **kwds): def __init__(self, vertex_set=None, maximal_faces=None, **kwds): """ Define a simplicial complex.  See SimplicialComplex for more documentation. .. WARNING:: We are deprecating the option vertex_set in :trac:12587. EXAMPLES:: sage: SimplicialComplex(3, [[0,2], [0,3], [0]]) Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2), (0, 3)} sage: SimplicialComplex(['a', 'b', 'c'], (('a', 'b'), ('a', 'c'), ('b', 'c'))) Simplicial complex with vertex set ('a', 'b', 'c') and facets {('b', 'c'), ('a', 'c'), ('a', 'b')} sage: SimplicialComplex([[0,2], [0,3], [0]]) Simplicial complex with vertex set (0, 2, 3) and facets {(0, 2), (0, 3)} sage: SimplicialComplex((('a', 'b'), ('a', 'c'), ('b', 'c'))) Simplicial complex with vertex set ('a', 'b', 'c') and facets {('b', 'c'), ('a', 'c'), ('a', 'b')} TESTS:: sage: S = SimplicialComplex([[1,4], [2,4]]) sage: S2 = SimplicialComplex([[1,4], [2,4]], is_mutable=False) sage: S == S2 True sage: S3 = SimplicialComplex(maximal_faces=[[1,4], [2,4]]) sage: S == S3 True """ from sage.misc.misc import union # process kwds sort_facets = kwds.get('sort_facets', True) vertex_check = kwds.get('vertex_check', True) maximality_check = kwds.get('maximality_check', True) name_check = kwds.get('name_check', False) # done with kwds # # if there are no maximal faces, perhaps the vertex_set was # omitted.  Check to see if it is a list (or tuple) of lists # (or tuples or simplices) , and if so, use that for # 'maximal_faces', and use the union of all of the vertices for # 'vertex_set'. if maximal_faces == []: C = None if isinstance(vertex_set, (list, tuple)) and isinstance(vertex_set[0], (list, tuple, Simplex)): maximal_faces = vertex_set vertex_set = reduce(union, vertex_set) elif isinstance(vertex_set, SimplicialComplex): C = vertex_set else: try: C = vertex_set._simplicial_() except AttributeError: pass if C is not None: self._vertex_set = copy(C.vertices()) self._facets = list(C.facets()) self._faces = copy(C._faces) self._gen_dict = copy(C._gen_dict) self._complex = copy(C._complex) self.__contractible = copy(C.__contractible) self.__enlarged = copy(C.__enlarged) self._graph = copy(C._graph) self._numeric = C._numeric self._numeric_translation = copy(C._numeric_translation) return # done with kwds except mutability # For deprecation #12587 if maximal_faces is None: maximal_faces = vertex_set elif vertex_set is not None: # We've passed in both vertex_set and maximal_faces from sage.misc.superseded import deprecation deprecation(12587, "vertex_set is deprecated.") if 'vertex_check' in kwds: from sage.misc.superseded import deprecation deprecation(12587, "vertex_check is deprecated.") C = None if maximal_faces is None: vertex_set = [] maximal_faces = [] elif isinstance(maximal_faces, SimplicialComplex): C = maximal_faces else: try: C = maximal_faces._simplicial_() except AttributeError: if not isinstance(maximal_faces, (list, tuple, Simplex)): # Convert it into a list (in case it is an iterable) maximal_faces = list(maximal_faces) if len(maximal_faces) != 0: vertex_set = reduce(union, maximal_faces) if C is not None: self._vertex_set = copy(C.vertices()) self._facets = list(C.facets()) self._faces = copy(C._faces) self._gen_dict = copy(C._gen_dict) self._complex = copy(C._complex) self.__contractible = copy(C.__contractible) self.__enlarged = copy(C.__enlarged) self._graph = copy(C._graph) self._numeric = C._numeric self._numeric_translation = copy(C._numeric_translation) self._is_mutable = C._is_mutable return if sort_facets: try:  # vertex_set is an iterable class SimplicialComplex(GenericCellCompl good_faces = [] maximal_simplices = [Simplex(f) for f in maximal_faces] for face in maximal_simplices: # check whether vertices of each face are contained in vertex set if vertex_check: if not face.is_face(vertices): raise ValueError, "The face %s is not a subset of the vertex set." % face # check whether each given face is actually maximal face_is_maximal = True if maximality_check: class SimplicialComplex(GenericCellCompl d = zip(vertices, range(len(tuple(vertices)))) self._numeric = numeric self._numeric_translation = d # Handle mutability keywords self._is_mutable = True if not kwds.get('is_mutable', True) or kwds.get('is_immutable', False): self.set_immutable() def __hash__(self): """ Compute the hash value of self. If this simplicial complex is immutable, it computes the hash value based upon the facets. Otherwise it raises a ValueError. EXAMPLES:: sage: S = SimplicialComplex([[1,4], [2,4]]) sage: hash(S) Traceback (most recent call last): ... ValueError: This simplicial complex must be immutable. Call set_immutable(). sage: S.set_immutable() sage: hash(S) == hash(S) True sage: S2 = SimplicialComplex([[1,4], [2,4]], is_mutable=False) sage: S == S2 True sage: hash(S) == hash(S2) True """ if self._is_mutable: raise ValueError("This simplicial complex must be immutable. Call set_immutable().") return hash(self._facets) def __cmp__(self,right): """ class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: SimplicialComplex(4, [[1,2], [2,3], [4]]) == SimplicialComplex(4, [[4], [2,3], [3], [2,1]]) sage: SimplicialComplex([[1,2], [2,3], [4]]) == SimplicialComplex([[4], [2,3], [3], [2,1]]) True sage: X = SimplicialComplex(4) sage: X = SimplicialComplex() sage: X.add_face([1,3]) sage: X == SimplicialComplex(4, [[1,3]]) sage: X == SimplicialComplex([[1,3]]) True """ if (self.vertices() == right.vertices() and set(self._facets) == set(right._facets)): if set(self._facets) == set(right._facets): return 0 else: return -1 class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: S = SimplicialComplex(15, [[0,1], [1,2]]) sage: S = SimplicialComplex([[i] for i in range(16)] + [[0,1], [1,2]]) sage: S Simplicial complex with 16 vertices and facets {(1, 2), (0, 1)} Simplicial complex with 16 vertices and 15 facets sage: S.vertices() (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: Y = SimplicialComplex(5, [[0,2], [1,4]]) sage: Y = SimplicialComplex([[0,2], [1,4]]) sage: Y.maximal_faces() {(1, 4), (0, 2)} facets is a synonym for maximal_faces:: sage: S = SimplicialComplex(2, [[0,1], [0,1,2]]) sage: S = SimplicialComplex([[0,1], [0,1,2]]) sage: S.facets() {(0, 1, 2)} """ class SimplicialComplex(GenericCellCompl :param subcomplex: a subcomplex of this simplicial complex. Return faces which are not in this subcomplex. :type subcomplex: optional, default None :type subcomplex: optional, default None EXAMPLES:: sage: Y = SimplicialComplex(5, [[1,2], [1,4]]) sage: Y = SimplicialComplex([[1,2], [1,4]]) sage: Y.faces() {0: set([(4,), (2,), (1,)]), 1: set([(1, 2), (1, 4)]), -1: set([()])} sage: L = SimplicialComplex(5, [[1,2]]) sage: L = SimplicialComplex([[1,2]]) sage: Y.faces(subcomplex=L) {0: set([(4,)]), 1: set([(1, 4)]), -1: set([])} """ # Make the subcomplex immutable if it is not if subcomplex is not None and subcomplex._is_mutable: subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, sort_facets=False, is_mutable=False) if subcomplex not in self._faces: # Faces is the dictionary of faces in self but not in # subcomplex, indexed by dimension class SimplicialComplex(GenericCellCompl def n_faces(self, n, subcomplex=None): """ The set of simplices of dimension n of this simplicial complex. The set of simplices of dimension n of this simplicial complex. If the optional argument subcomplex is present, then return the n-dimensional faces which are *not* in the subcomplex. class SimplicialComplex(GenericCellCompl :param subcomplex: a subcomplex of this simplicial complex. Return n-dimensional faces which are not in this subcomplex. :type subcomplex: optional, default None :type subcomplex: optional, default None EXAMPLES:: sage: S = Set(range(1,5)) sage: Z = SimplicialComplex(S, S.subsets()) sage: Z = SimplicialComplex(S.subsets()) sage: Z Simplicial complex with vertex set (1, 2, 3, 4) and facets {(1, 2, 3, 4)} sage: Z.n_faces(2) set([(1, 3, 4), (1, 2, 3), (2, 3, 4), (1, 2, 4)]) sage: K = SimplicialComplex(S, [[1,2,3], [2,3,4]]) sage: K = SimplicialComplex([[1,2,3], [2,3,4]]) sage: Z.n_faces(2, subcomplex=K) set([(1, 3, 4), (1, 2, 4)]) """ class SimplicialComplex(GenericCellCompl def is_pure(self): """ True iff this simplicial complex is pure: a simplicial complex is pure iff all of its maximal faces have the same dimension. .. warning:: Return True iff this simplicial complex is pure. A simplicial complex is pure if and only if all of its maximal faces have the same dimension. .. WARNING:: This may give the wrong answer if the simplicial complex was constructed with maximality_check set to False. was constructed with maximality_check set to False. EXAMPLES:: sage: U = SimplicialComplex(5, [[1,2], [1, 3, 4]]) sage: U = SimplicialComplex([[1,2], [1, 3, 4]]) sage: U.is_pure() False sage: X = SimplicialComplex(3, [[0,1], [0,2], [1,2]]) sage: X = SimplicialComplex([[0,1], [0,2], [1,2]]) sage: X.is_pure() True Demonstration of the warning:: sage: S = SimplicialComplex([[0,1], [0]], maximality_check=False) sage: S.is_pure() False """ dims = [face.dimension() for face in self._facets] return max(dims) == min(dims) class SimplicialComplex(GenericCellCompl empy simplex), then the h-vector (h_0, h_1, ..., h_d, h_{d+1}) is defined by .. math:: .. MATH:: \sum_{i=0}^{d+1} h_i x^{d+1-i} = \sum_{i=0}^{d+1} f_{i-1} (x-1)^{d+1-i}. Alternatively, .. math:: .. MATH:: h_j = \sum_{i=-1}^{j-1} (-1)^{j-i-1} \binom{d-i}{j-i-1} f_i. class SimplicialComplex(GenericCellCompl g = Graph([V,E]) return g.is_connected() def product(self, right, rename_vertices=True): def product(self, right, rename_vertices=True, is_mutable=True): """ The product of this simplicial complex with another one. class SimplicialComplex(GenericCellCompl :param rename_vertices: If this is False, then the vertices in the product are the set of ordered pairs (v,w) where v is a vertex in self and w is a vertex in right. If this is True, then the vertices are renamed right. If this is True, then the vertices are renamed as "LvRw" (e.g., the vertex (1,2) would become "L1R2"). This is useful if you want to define the Stanley-Reisner ring of the complex: vertex names like (0,1) are not suitable for that, while vertex names like "L0R1" are. :type rename_vertices: boolean; optional, default True :type rename_vertices: boolean; optional, default True :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True The vertices in the product will be the set of ordered pairs (v,w) where v is a vertex in self and w is a vertex in right. .. warning:: .. WARNING:: If X and Y are simplicial complexes, then X*Y returns their join, not their product. EXAMPLES:: sage: S = SimplicialComplex(3, [[0,1], [1,2], [0,2]]) # circle sage: K = SimplicialComplex(1, [[0,1]])   # edge sage: S = SimplicialComplex([[0,1], [1,2], [0,2]]) # circle sage: K = SimplicialComplex([[0,1]])   # edge sage: S.product(K).vertices()  # cylinder ('L0R0', 'L0R1', 'L1R0', 'L1R1', 'L2R0', 'L2R1', 'L3R0', 'L3R1') ('L0R0', 'L0R1', 'L1R0', 'L1R1', 'L2R0', 'L2R1') sage: S.product(K, rename_vertices=False).vertices() ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)) ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)) sage: T = S.product(S)  # torus sage: T Simplicial complex with 16 vertices and 18 facets Simplicial complex with 9 vertices and 18 facets sage: T.homology() {0: 0, 1: Z x Z, 2: Z} class SimplicialComplex(GenericCellCompl sage: T.product(K)      # long time: 5 or 6 seconds Simplicial complex with 56 vertices and 1344 facets """ vertices = [] for v in self.vertices(): for w in right.vertices(): if rename_vertices: vertices.append("L" + str(v) + "R" + str(w)) else: vertices.append((v,w)) facets = [] for f in self._facets: for g in right._facets: facets.extend(f.product(g, rename_vertices)) return SimplicialComplex(vertices, facets) def join(self, right, rename_vertices=True): return SimplicialComplex(facets, is_mutable=is_mutable) def join(self, right, rename_vertices=True, is_mutable=True): """ The join of this simplicial complex with another one. class SimplicialComplex(GenericCellCompl the vertices; this will cause problems if the two factors have any vertices with names in common. :type rename_vertices: boolean; optional, default True :type rename_vertices: boolean; optional, default True :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True EXAMPLES:: sage: S = SimplicialComplex(1, [[0], [1]]) sage: T = SimplicialComplex([2, 3], [[2], [3]]) sage: S = SimplicialComplex([[0], [1]]) sage: T = SimplicialComplex([[2], [3]]) sage: S.join(T) Simplicial complex with vertex set ('L0', 'L1', 'R2', 'R3') and 4 facets sage: S.join(T, rename_vertices=False) class SimplicialComplex(GenericCellCompl sage: S * S * S * S * S * S * S * S Simplicial complex with 16 vertices and 256 facets """ if rename_vertices: vertex_set = (["L" + str(v) for v in self.vertices()] + ["R" + str(w) for w in right.vertices()]) else: vertex_set = tuple(self._vertex_set) + tuple(right.vertices()) facets = [] for f in self._facets: for g in right._facets: facets.append(f.join(g, rename_vertices)) return SimplicialComplex(vertex_set, facets) return SimplicialComplex(facets, is_mutable=is_mutable) # Use * to mean 'join': __mul__ = join def cone(self): def cone(self, is_mutable=True): """ The cone on this simplicial complex. :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True The cone is the simplicial complex formed by adding a new vertex C and simplices of the form [C, v_0, ..., v_k] for every simplex [v_0, ..., v_k] in the original simplicial class SimplicialComplex(GenericCellCompl complex with a one-point simplicial complex. EXAMPLES:: sage: S = SimplicialComplex(1, [[0], [1]]) sage: S = SimplicialComplex([[0], [1]]) sage: S.cone() Simplicial complex with vertex set ('L0', 'L1', 'R0') and facets {('L0', 'R0'), ('L1', 'R0')} """ return self.join(SimplicialComplex(["0"], [["0"]]), return self.join(SimplicialComplex([["0"]], is_mutable=is_mutable), rename_vertices = True) def suspension(self, n=1): def suspension(self, n=1, is_mutable=True): r""" The suspension of this simplicial complex. class SimplicialComplex(GenericCellCompl :type n: optional, default 1 :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True The suspension is the simplicial complex formed by adding two new vertices S_0 and S_1 and simplices of the form [S_0, v_0, ..., v_k] and [S_1, v_0, ..., v_k] for every simplex class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: S0 = SimplicialComplex(1, [[0], [1]]) sage: S0 = SimplicialComplex([[0], [1]]) sage: S0.suspension() == simplicial_complexes.Sphere(1) True sage: S3 = S0.suspension(3)  # the 3-sphere class SimplicialComplex(GenericCellCompl new_facets.append(f.join(w, rename_vertices=False)) return SimplicialComplex(new_facets) else: return self.join(SimplicialComplex(["0", "1"], [["0"], ["1"]]), return self.join(SimplicialComplex(["0", "1"], [["0"], ["1"]], is_mutable=is_mutable), rename_vertices = True) return self.suspension().suspension(int(n-1)) def disjoint_union(self, right, rename_vertices=True): return self.suspension(is_mutable).suspension(int(n-1), is_mutable) def disjoint_union(self, right, rename_vertices=True, is_mutable=True): """ The disjoint union of this simplicial complex with another one. class SimplicialComplex(GenericCellCompl sage: S1.disjoint_union(S2).homology() {0: Z, 1: Z, 2: Z} """ if rename_vertices: vertex_set = (["L" + str(v) for v in self.vertices()] + ["R" + str(w) for w in right.vertices()]) else: vertex_set = tuple(self._vertex_set) + tuple(right.vertices()) facets = [] for f in self._facets: facets.append(tuple(["L" + str(v) for v in f])) for f in right._facets: facets.append(tuple(["R" + str(v) for v in f])) return SimplicialComplex(vertex_set, facets) def wedge(self, right, rename_vertices=True): return SimplicialComplex(facets, is_mutable=is_mutable) def wedge(self, right, rename_vertices=True, is_mutable=True): """ The wedge (one-point union) of this simplicial complex with another one. :param right: the other simplicial complex (the right-hand factor) :param rename_vertices: If this is True, the vertices in the :param rename_vertices: If this is True, the vertices in the wedge will be renamed by the formula: first vertex in each are glued together and called "0".  Otherwise, each vertex "v" in the left-hand factor --> vertex "Lv" in the wedge, vertex "w" in the right-hand factor --> vertex "Rw" in the wedge.  If this is false, this tries to construct the wedge wedge.  If this is False, this tries to construct the wedge without renaming the vertices; this will cause problems if the two factors have any vertices with names in common. :type rename_vertices: boolean; optional, default True .. note:: :type rename_vertices: boolean; optional, default True :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True .. NOTE:: This operation is not well-defined if self or other is not path-connected. EXAMPLES:: sage: S1 = simplicial_complexes.Sphere(1) class SimplicialComplex(GenericCellCompl left_dict = {left_0: 0} right_dict = {right_0: 0} if rename_vertices: vertex_set = ([0] + ["L" + str(v) for v in left_vertices] + ["R" + str(w) for w in right_vertices]) facets = [] for v in left_vertices: left_dict[v] = "L" + str(v) for v in right_vertices: right_dict[v] = "R" + str(v) else: vertex_set = (0,) + tuple(left_vertices) + tuple(right_vertices) if rename_vertices: facets = [] for f in self._facets: facets.append(tuple([left_dict[v] for v in f])) for f in right._facets: facets.append(tuple([right_dict[v] for v in f])) else: facets = self._facets + right._facets return SimplicialComplex(vertex_set, facets) return SimplicialComplex(facets, is_mutable=is_mutable) def chain_complex(self, **kwds): """ The chain complex associated to this simplicial complex. :param dimensions: if None, compute the chain complex in all :param dimensions: if None, compute the chain complex in all dimensions.  If a list or tuple of integers, compute the chain complex in those dimensions, setting the chain groups in all other dimensions to zero. :param base_ring: commutative ring :type base_ring: optional, default ZZ :type base_ring: optional, default ZZ :param subcomplex: a subcomplex of this simplicial complex. Compute the chain complex relative to this subcomplex. :type subcomplex: optional, default empty :param augmented: If True, return the augmented chain complex :param augmented: If True, return the augmented chain complex (that is, include a class in dimension -1 corresponding to the empty cell).  This is ignored if dimensions is specified. :type augmented: boolean; optional, default False :param cochain: If True, return the cochain complex (that is, :type augmented: boolean; optional, default False :param cochain: If True, return the cochain complex (that is, the dual of the chain complex). :type cochain: boolean; optional, default False :param verbose: If True, print some messages as the chain :type cochain: boolean; optional, default False :param verbose: If True, print some messages as the chain complex is computed. :type verbose: boolean; optional, default False :param check_diffs: If True, make sure that the chain complex :type verbose: boolean; optional, default False :param check_diffs: If True, make sure that the chain complex is actually a chain complex: the differentials are composable and their product is zero. :type check_diffs: boolean; optional, default False .. note:: :type check_diffs: boolean; optional, default False .. NOTE:: If subcomplex is nonempty, then the argument augmented has no effect: the chain complex relative to a nonempty class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: circle = SimplicialComplex(2, [[0,1], [1,2], [0, 2]]) sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) sage: circle.chain_complex() Chain complex with at most 2 nonzero terms over Integer Ring sage: circle.chain_complex()._latex_() class SimplicialComplex(GenericCellCompl # initialize subcomplex if subcomplex is None: subcomplex = SimplicialComplex(self.vertices()) subcomplex = SimplicialComplex(is_mutable=False) else: # subcomplex is not empty, so don't augment the chain complex augmented = False # Use an immutable copy of the subcomplex if not subcomplex._is_mutable: subcomplex = SimplicialComplex(subcomplex._facets, maximality_check=False, sort_facets=False, is_mutable=False) # now construct the range of dimensions in which to compute if dimensions is None: dimensions = range(0, self.dimension()+1) class SimplicialComplex(GenericCellCompl """ The reduced homology of this simplicial complex. :param dim: If None, then return the homology in every :param dim: If None, then return the homology in every dimension.  If dim is an integer or list, return the homology in the given dimensions.  (Actually, if dim is a list, return the homology in the range from min(dim) to max(dim).) :type dim: integer or list of integers or None; optional, default None :param base_ring: commutative ring. Must be ZZ or a field. :type dim: integer or list of integers or None; optional, default None :param base_ring: commutative ring. Must be ZZ or a field. :type base_ring: optional, default ZZ :type base_ring: optional, default ZZ :param subcomplex: a subcomplex of this simplicial complex. Compute homology relative to this subcomplex. :type subcomplex: optional, default None :param cohomology: If True, compute cohomology rather than :type subcomplex: optional, default None :param cohomology: If True, compute cohomology rather than homology. :type cohomology: boolean; optional, default False :param enlarge: If True, find a new subcomplex homotopy :type cohomology: boolean; optional, default False :param enlarge: If True, find a new subcomplex homotopy equivalent to, and probably larger than, the given one. :type enlarge: boolean; optional, default True :param algorithm: The options are 'auto', 'dhsw', 'pari' or 'no_chomp'.  If 'auto', first try CHomP, then use the Dumas, Heckenbach, Saunders, and Welker elimination :type enlarge: boolean; optional, default True :param algorithm: The options are 'auto', 'dhsw', 'pari' or  'no_chomp'.  If 'auto', first try CHomP, then use the Dumas, Heckenbach, Saunders, and Welker elimination algorithm for large matrices, Pari for small ones.  If 'no_chomp', then don't try CHomP, but behave the same otherwise.  If 'pari', then compute elementary divisors using Pari.  If 'dhsw', then use the DHSW algorithm to 'no_chomp', then don't try CHomP, but behave the same otherwise.  If 'pari', then compute elementary divisors using Pari.  If 'dhsw', then use the DHSW algorithm to compute elementary divisors.  (As of this writing, CHomP is by far the fastest option, followed by the 'auto' or 'no_chomp' setting of using DHSW for large matrices and by far the fastest option, followed by the 'auto' or 'no_chomp' setting of using DHSW for large matrices and Pari for small ones.) :type algorithm: string; optional, default 'auto' :type algorithm: string; optional, default 'auto' :param verbose: If True, print some messages as the homology :param verbose: If True, print some messages as the homology is computed. :type verbose: boolean; optional, default False Algorithm: if subcomplex is None, replace it with a facet :type verbose: boolean; optional, default False Algorithm: if subcomplex is None, replace it with a facet -- a contractible subcomplex of the original complex.  Then no matter what subcomplex is, replace it with a subcomplex L which is homotopy equivalent and as large as possible. class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: circle = SimplicialComplex(2, [[0,1], [1,2], [0, 2]]) sage: circle = SimplicialComplex([[0,1], [1,2], [0, 2]]) sage: circle._homology_() {0: 0, 1: Z} sage: disk = SimplicialComplex(3, [[0,1,2,3]]) sage: sphere = disk.remove_face([0,1,2,3]) sage: sphere = SimplicialComplex([[0,1,2,3]]) sage: sphere.remove_face([0,1,2,3]) sage: sphere Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} sage: sphere._homology_() class SimplicialComplex(GenericCellCompl Another way to get a two-sphere: take a two-point space and take its three-fold join with itself:: sage: S = SimplicialComplex(1, [[0], [1]]) sage: S = SimplicialComplex([[0], [1]]) sage: (S*S*S)._homology_(dim=2, cohomology=True) Z Relative homology:: sage: T = SimplicialComplex(2, [[0,1,2]]) sage: U = SimplicialComplex(2, [[0,1], [1,2], [0,2]]) sage: T = SimplicialComplex([[0,1,2]]) sage: U = SimplicialComplex([[0,1], [1,2], [0,2]]) sage: T._homology_(subcomplex=U) {0: 0, 1: 0, 2: Z} """ class SimplicialComplex(GenericCellCompl print "Done finding contractible subcomplex." vec = [len(self.n_faces(n-1, subcomplex=L)) for n in range(self.dimension()+2)] print "The difference between the f-vectors is:" print "  %s" % vec print "  %s" % vec else: L = SimplicialComplex(self.vertices(), [[self.vertices().tuple()[0]]]) L = SimplicialComplex([[self.vertices().tuple()[0]]]) else: if enlarge: if verbose: class SimplicialComplex(GenericCellCompl print "Done enlarging subcomplex:" else: L = subcomplex L.set_immutable() if verbose: print "Computing the chain complex..." kwds['subcomplex']=L class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: X = SimplicialComplex(2, [[0,1], [0,2]]) sage: X = SimplicialComplex([[0,1], [0,2]]) sage: X.add_face([0,1,2,]); X Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)} sage: Y = SimplicialComplex(3); Y Simplicial complex with vertex set (0, 1, 2, 3) and facets {()} sage: Y = SimplicialComplex(); Y Simplicial complex with vertex set () and facets {()} sage: Y.add_face([0,1]) sage: Y.add_face([1,2,3]) sage: Y class SimplicialComplex(GenericCellCompl sage: Y.add_face([1,3]); Y Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 2, 3), (0, 1)} """ if not self._is_mutable: raise ValueError("This simplicial complex is not mutable") new_face = Simplex(face) if not new_face.is_face(self.vertices()): raise ValueError, "The face to be added is not a subset of the vertex set." else: face_is_maximal = True for other in self._facets: if face_is_maximal: face_is_maximal = not new_face.is_face(other) face_is_maximal = True for other in self._facets: if face_is_maximal: # remove any old facets which are no longer maximal Facets = list(self._facets) for old_face in self._facets: if old_face.is_face(new_face): Facets.remove(old_face) # add new_face to facet list Facets.append(new_face) self._facets = Facets # update self._faces if necessary if None in self._faces: all_new_faces = SimplicialComplex(self.vertices(), [new_face]).faces() for dim in range(0, new_face.dimension()+1): if dim in self._faces[None]: self._faces[None][dim] = self._faces[None][dim].union(all_new_faces[dim]) else: self._faces[None][dim] = all_new_faces[dim] # update self._graph if necessary if self._graph is None: pass else: d = new_face.dimension()+1 for i in range(d): for j in range(i+1,d): self._graph.add_edge(new_face[i],new_face[j]) return None face_is_maximal = not new_face.is_face(other) if face_is_maximal: # remove any old facets which are no longer maximal Facets = list(self._facets) for old_face in self._facets: if old_face.is_face(new_face): Facets.remove(old_face) # add new_face to facet list Facets.append(new_face) self._facets = Facets # Update the vertex set from sage.misc.misc import union self._vertex_set = Simplex(reduce(union, [self._vertex_set, new_face])) # update self._faces if necessary if None in self._faces: all_new_faces = SimplicialComplex([new_face]).faces() for dim in range(0, new_face.dimension()+1): if dim in self._faces[None]: self._faces[None][dim] = self._faces[None][dim].union(all_new_faces[dim]) else: self._faces[None][dim] = all_new_faces[dim] # update self._graph if necessary if self._graph is not None: d = new_face.dimension()+1 for i in range(d): for j in range(i+1,d): self._graph.add_edge(new_face[i],new_face[j]) def remove_face(self, face): """ class SimplicialComplex(GenericCellCompl :param face: a face of the simplicial complex Algorithm: the facets of the new simplicial complex are This *changes* the simplicial complex. ALGORITHM: The facets of the new simplicial complex are the facets of the original complex not containing face, together with those of link(face)*boundary(face). EXAMPLES:: sage: S = range(1,5) sage: Z = SimplicialComplex(S, [S]); Z sage: Z = SimplicialComplex([S]); Z Simplicial complex with vertex set (1, 2, 3, 4) and facets {(1, 2, 3, 4)} sage: Z2 = Z.remove_face([1,2]) sage: Z2 sage: Z.remove_face([1,2]) sage: Z Simplicial complex with vertex set (1, 2, 3, 4) and facets {(1, 3, 4), (2, 3, 4)} sage: S = SimplicialComplex(4,[[0,1,2],[2,3]]) sage: S = SimplicialComplex([[0,1,2],[2,3]]) sage: S Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2), (2, 3)} sage: S2 = S.remove_face([0,1,2]) sage: S2 Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(1, 2), (2, 3), (0, 2), (0, 1)} Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (2, 3)} sage: S.remove_face([0,1,2]) sage: S Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 2), (2, 3), (0, 2), (0, 1)} """ if not self._is_mutable: raise ValueError("This simplicial complex is not mutable") simplex = Simplex(face) facets = self.facets() if all([not simplex.is_face(F) for F in facets]): class SimplicialComplex(GenericCellCompl for g in link.facets(): join_facets.append(f.join(g, rename_vertices=False)) # join_facets is the list of facets in the join bdry(face) * link(face) other_facets = [elem for elem in facets if not simplex.is_face(elem)] return SimplicialComplex(self.vertices(), join_facets + other_facets) def connected_sum(self, other): remaining = join_facets + [elem for elem in facets if not simplex.is_face(elem)] # Check to see if there are any non-maximial faces # build set of facets self._facets = [] for f in remaining: face = Simplex(f) face_is_maximal = True faces_to_be_removed = [] for other in self._facets: if other.is_face(face): faces_to_be_removed.append(other) elif face_is_maximal: face_is_maximal = not face.is_face(other) for x in faces_to_be_removed: self._facets.remove(x) face = Simplex(sorted(face.tuple())) if face_is_maximal: self._facets.append(face) # if no maximal faces, add the empty face as a facet if len(remaining) == 0: self._facets.append(Simplex(-1)) # Recreate the vertex set from sage.misc.misc import union self._vertex_set = Simplex(reduce(union, self._facets)) # Update self._faces and self._graph if necessary if None in self._faces: self._faces = {} self.faces() if self._graph is not None: # Only if removing a 1 or 2 dim face will the graph be affected if len(face) == 1: self._graph.delete_vertex(face[0]) self._graph.add_vertex(face[0]) elif len(face) == 2: self._graph.delete_edge(face[0], face[1]) def connected_sum(self, other, is_mutable=True): """ The connected sum of this simplicial complex with another one. :param other: another simplicial complex :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True :return: the connected sum self # other .. warning:: This does not check that self and other are manifolds, only that their facets all have the same dimension.  Since a .. WARNING:: This does not check that self and other are manifolds, only that their facets all have the same dimension.  Since a (more or less) random facet is chosen from each complex and then glued together, this method may return random results if applied to non-manifolds, depending on which class SimplicialComplex(GenericCellCompl Simplicial complex with 9 vertices and 18 facets The notation '+' may be used for connected sum, also:: sage: P + P    # the Klein bottle Simplicial complex with 9 vertices and 18 facets sage: (P + P).homology()[1] class SimplicialComplex(GenericCellCompl # construct the set of vertices: left = set(self.vertices()).difference(set(keep_left)) right = set(other.vertices()).difference(set(keep_right)) vertex_set = (range(dim+1) + ["L" + str(v) for v in left] + ["R" + str(v) for v in right]) # construct the set of facets: left = set(self._facets).difference(set([keep_left])) right = set(other._facets).difference(set([keep_right])) class SimplicialComplex(GenericCellCompl + [[rename_vertex(v, keep=list(keep_right), left=False) for v in face] for face in right]) # return the new surface return SimplicialComplex(vertex_set, facet_set) return SimplicialComplex(facet_set, is_mutable=is_mutable) __add__ = connected_sum def link(self, simplex): def link(self, simplex, is_mutable=True): """ The link of a simplex in this simplicial complex. class SimplicialComplex(GenericCellCompl \cup G is a simplex. :param simplex: a simplex in this simplicial complex. :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True EXAMPLES:: sage: X = SimplicialComplex(4, [[0,1,2], [1,2,3]]) sage: X = SimplicialComplex([[0,1,2], [1,2,3]]) sage: X.link(Simplex([0])) Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(1, 2)} Simplicial complex with vertex set (1, 2) and facets {(1, 2)} sage: X.link([1,2]) Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(3,), (0,)} sage: Y = SimplicialComplex(3, [[0,1,2,3]]) Simplicial complex with vertex set (0, 3) and facets {(3,), (0,)} sage: Y = SimplicialComplex([[0,1,2,3]]) sage: Y.link([1]) Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3)} Simplicial complex with vertex set (0, 2, 3) and facets {(0, 2, 3)} """ faces = [] s = Simplex(simplex) for f in self._facets: if s.is_face(f): faces.append(Simplex(list(f.set().difference(s.set())))) return SimplicialComplex(self.vertices(), faces) return SimplicialComplex(faces, is_mutable=is_mutable) def effective_vertices(self): """ The set of vertices belonging to some face. Returns a Simplex. The set of vertices belonging to some face. Returns the list of vertices. EXAMPLES:: sage: S = SimplicialComplex(15) sage: S = SimplicialComplex([[0,1,2,3],[6,7]]) sage: S Simplicial complex with 16 vertices and facets {()} Simplicial complex with vertex set (0, 1, 2, 3, 6, 7) and facets {(6, 7), (0, 1, 2, 3)} sage: S.effective_vertices() () sage: S = SimplicialComplex(15,[[0,1,2,3],[6,7]]) sage: S Simplicial complex with 16 vertices and facets {(6, 7), (0, 1, 2, 3)} sage: S.effective_vertices() doctest:1: DeprecationWarning: effective_vertices is deprecated. Use vertices instead See http://trac.sagemath.org/12587 for details. (0, 1, 2, 3, 6, 7) sage: type(S.effective_vertices()) """ try: v = self.faces()[0] except KeyError: return Simplex(-1) f = [] for i in v: f.append(i[0]) return Simplex(set(f)) def generated_subcomplex(self,sub_vertex_set): from sage.misc.superseded import deprecation deprecation(12587, "effective_vertices is deprecated. Use vertices instead") return self._vertex_set def generated_subcomplex(self,sub_vertex_set, is_mutable=True): """ Returns the largest sub-simplicial complex of self containing Returns the largest sub-simplicial complex of self containing exactly sub_vertex_set as vertices. :param sub_vertex_set: The sub-vertex set. :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) class SimplicialComplex(GenericCellCompl """ if not self.vertices().set().issuperset(sub_vertex_set): raise TypeError, "input must be a subset of the vertex set." raise ValueError, "input must be a subset of the vertex set." faces = [] for i in range(self.dimension()+1): for j in self.faces()[i]: if j.set().issubset(sub_vertex_set): faces.append(j) return SimplicialComplex(sub_vertex_set,faces,maximality_check=True) return SimplicialComplex(faces, maximality_check=True, is_mutable=is_mutable) def _complement(self, simplex): """ class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: X = SimplicialComplex(5) sage: X = SimplicialComplex([[0,1,2,3,4,5]]) sage: X._complement([1,2,3]) (0, 4, 5) sage: X._complement([0,1,3,4]) class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: X = SimplicialComplex(5) sage: X = SimplicialComplex() sage: X._transpose_simplices([1,2]) [(1,), (2,)] sage: X._transpose_simplices([1,2], [3,4]) [(1, 3), (1, 4), (2, 3), (2, 4)] In the following example, one can construct the simplices (1,2) and (1,3), but you can also construct (1,1) = (1,), (1,2) and (1,3), but you can also construct (1,1) = (1,), which is a face of both of the others.  So the answer omits (1,2) and (1,3):: (1,2) and (1,3):: sage: X._transpose_simplices([1,2], [1,3]) [(1,), (2, 3)] class SimplicialComplex(GenericCellCompl ones.  (The last two steps are taken care of by the _transpose_simplices routine.) This is used in computing the Stanley-Reisner ring and the Alexander dual. This is used in computing the :meth:Stanley-Reisner ring and the :meth:Alexander dual. EXAMPLES:: sage: X = SimplicialComplex(4) sage: X = SimplicialComplex([[1,3],[1,2]]) sage: X.minimal_nonfaces() {(4,), (2,), (3,), (0,), (1,)} sage: X.add_face([1,2]) sage: X.add_face([1,3]) sage: X.minimal_nonfaces() {(4,), (2, 3), (0,)} sage: Y = SimplicialComplex(3, [[0,1], [1,2], [2,3], [3,0]]) {(2, 3)} sage: Y = SimplicialComplex([[0,1], [1,2], [2,3], [3,0]]) sage: Y.minimal_nonfaces() {(1, 3), (0, 2)} """ class SimplicialComplex(GenericCellCompl quotient. :param base_ring: a commutative ring :type base_ring: optional, default ZZ :type base_ring: optional, default ZZ :return: a polynomial algebra with coefficients in base_ring, with one generator for each vertex in the simplicial complex. See the documentation for stanley_reisner_ring for a See the documentation for :meth:stanley_reisner_ring for a warning about the names of the vertices. EXAMPLES:: sage: X = SimplicialComplex(3, [[1,2], [0]]) sage: X = SimplicialComplex([[1,2], [0], [3]]) sage: X._stanley_reisner_base_ring() Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring sage: Y = SimplicialComplex(['a', 'b', 'c']) sage: Y = SimplicialComplex([['a', 'b', 'c']]) sage: Y._stanley_reisner_base_ring(base_ring=QQ) Multivariate Polynomial Ring in a, c, b over Rational Field """ class SimplicialComplex(GenericCellCompl The Stanley-Reisner ring of this simplicial complex. :param base_ring: a commutative ring :type base_ring: optional, default ZZ :type base_ring: optional, default ZZ :return: a quotient of a polynomial algebra with coefficients in base_ring, with one generator for each vertex in the simplicial complex, by the ideal generated by the products class SimplicialComplex(GenericCellCompl Thus the ideal is generated by the products corresponding to the minimal nonfaces of the simplicial complex. .. warning:: .. WARNING:: This may be quite slow! Also, this may behave badly if the vertices have the 'wrong' names. To avoid this, define the simplicial complex at the start with the flag name_check set to True. at the start with the flag name_check set to True. More precisely, this is a quotient of a polynomial ring with one generator for each vertex.  If the name of a vertex is a non-negative integer, then the corresponding polynomial generator is named 'x' followed by that integer (e.g., 'x2', 'x3', 'x5', ...).  Otherwise, the polynomial generators are given the same names as the vertices.  Thus if the vertex set is (2, 'x2'), there will be problems. polynomial generator is named 'x' followed by that integer (e.g., 'x2', 'x3', 'x5', ...).  Otherwise, the polynomial generators are given the same names as the vertices. Thus if the vertex set is (2, 'x2'), there will be problems. EXAMPLES:: sage: X = SimplicialComplex(3, [[0,1], [1,2], [2,3], [0,3]]) sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [0,3]]) sage: X.stanley_reisner_ring() Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3 over Integer Ring by the ideal (x1*x3, x0*x2) sage: Y = SimplicialComplex(4); Y Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {()} sage: Y.stanley_reisner_ring() Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3, x4 over Integer Ring by the ideal (x4, x2, x3, x0, x1) sage: Y = SimplicialComplex([[0,1,2,3,4]]); Y Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(0, 1, 2, 3, 4)} sage: Y.add_face([0,1,2,3,4]) sage: Y.stanley_reisner_ring(base_ring=QQ) Quotient of Multivariate Polynomial Ring in x0, x1, x2, x3, x4 over Rational Field by the ideal (0) class SimplicialComplex(GenericCellCompl products.append(prod) return R.quotient(products) def alexander_dual(self): def alexander_dual(self, is_mutable=True): """ The Alexander dual of this simplicial complex: according to the Macaulay2 documentation, this is the simplicial complex class SimplicialComplex(GenericCellCompl Thus find the minimal nonfaces and take their complements to find the facets in the Alexander dual. :param is_mutable: Determines if the output is mutable :type is_mutable: boolean; optional, default True EXAMPLES:: sage: Y = SimplicialComplex(4); Y Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {()} sage: Y = SimplicialComplex([[i] for i in range(5)]); Y Simplicial complex with vertex set (0, 1, 2, 3, 4) and facets {(4,), (2,), (3,), (0,), (1,)} sage: Y.alexander_dual() Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets sage: X = SimplicialComplex(3, [[0,1], [1,2], [2,3], [3,0]]) Simplicial complex with vertex set (0, 1, 2, 3, 4) and 10 facets sage: X = SimplicialComplex([[0,1], [1,2], [2,3], [3,0]]) sage: X.alexander_dual() Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 3), (0, 2)} """ nonfaces = self.minimal_nonfaces() return SimplicialComplex(self.vertices(), [self._complement(f) for f in nonfaces]) return SimplicialComplex([self._complement(f) for f in nonfaces], is_mutable=is_mutable) def barycentric_subdivision(self): """ class SimplicialComplex(GenericCellCompl EXAMPLES:: sage: triangle = SimplicialComplex(2, [[0,1], [1,2], [0, 2]]) sage: triangle = SimplicialComplex([[0,1], [1,2], [0, 2]]) sage: hexagon = triangle.barycentric_subdivision() sage: hexagon Simplicial complex with 6 vertices and 6 facets class SimplicialComplex(GenericCellCompl """ The 1-skeleton of this simplicial complex, as a graph. .. warning:: .. WARNING:: This may give the wrong answer if the simplicial complex was constructed with maximality_check set to False. was constructed with maximality_check set to False. EXAMPLES:: sage: S = SimplicialComplex(3, [[0,1,2,3]]) sage: S = SimplicialComplex([[0,1,2,3]]) sage: G = S.graph(); G Graph on 4 vertices sage: G.edges() [(0, 1, None), (0, 2, None), (0, 3, None), (1, 2, None), (1, 3, None), (2, 3, None)] sage: S = SimplicialComplex(3,[[1,2,3],[1]],maximality_check=False) sage: S = SimplicialComplex([[1,2,3],[1]],maximality_check=False) sage: G = S.graph() sage: G.is_connected() False class SimplicialComplex(GenericCellCompl is essentially identical to the simplicial complex: it has same simplices with the same boundaries. :param sort_simplices: if True, sort the list of simplices in :param sort_simplices: if True, sort the list of simplices in each dimension :type sort_simplices: boolean; optional, default False :type sort_simplices: boolean; optional, default False EXAMPLES:: class SimplicialComplex(GenericCellCompl def is_flag_complex(self): """ Returns True if and only if self is a flag complex. A flag complex is a simplicial complex that is the largest simplicial complex on its 1-skeleton. Thus a flag complex is the clique complex of its graph. Returns True if and only if self is a flag complex. A flag complex is a simplicial complex that is the largest simplicial complex on its 1-skeleton. Thus a flag complex is the clique complex of its graph. EXAMPLES:: class SimplicialComplex(GenericCellCompl sage: X.is_flag_complex() True """ return self==self.graph().clique_complex() return self == self.graph().clique_complex() def is_connected(self): """ Returns True if and only if self is connected. .. warning:: Returns True if and only if self is connected. .. WARNING:: This may give the wrong answer if the simplicial complex was constructed with maximality_check set to False. was constructed with maximality_check set to False. See the final example. EXAMPLES:: sage: V = SimplicialComplex([0,1,2,3],[[0,1,2],[3]]) sage: V = SimplicialComplex([[0,1,2],[3]]) sage: V Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (3,)} sage: V.is_connected() False sage: X = SimplicialComplex([0,1,2,3],[[0,1,2]]) sage: X = SimplicialComplex([[0,1,2]]) sage: X.is_connected() True class SimplicialComplex(GenericCellCompl sage: W.is_connected() True sage: S = SimplicialComplex(4,[[0,1],[2,3]]) sage: S = SimplicialComplex([[0,1],[2,3]]) sage: S.is_connected() False sage: S = SimplicialComplex(2,[[0,1],[1],[0]],maximality_check=False) sage: S = SimplicialComplex([[0,1],[1],[0]],maximality_check=False) sage: S.is_connected() False """ class SimplicialComplex(GenericCellCompl def n_skeleton(self, n): """ The n-skeleton of this simplicial complex: the simplicial complex obtained by discarding all of the simplices in dimensions larger than n. The n-skeleton of this simplicial complex. The n-skeleton of a simplicial complex is obtained by discarding all of the simplices in dimensions larger than n. :param n: non-negative integer EXAMPLES:: sage: X = SimplicialComplex(3, [[0,1], [1,2,3], [0,2,3]]) sage: X = SimplicialComplex([[0,1], [1,2,3], [0,2,3]]) sage: X.n_skeleton(1) Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 2), (1, 3), (1, 2), (0, 3), (0, 1)} sage: X.set_immutable() sage: X.n_skeleton(2) Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (1, 2, 3), (0, 1)} """ facets = filter(lambda f: f.dimension() facet_limit: facet_string = "%s facets" % len(facets) return "Simplicial complex " + vertex_string + " and " + facet_string def set_immutable(self): """ Make this simplicial complex immutable. EXAMPLES:: sage: S = SimplicialComplex([[1,4], [2,4]]) sage: S.is_mutable() True sage: S.set_immutable() sage: S.is_mutable() False """ self._is_mutable = False self._facets = tuple(self._facets) def is_mutable(self): """ Return True if mutable. EXAMPLES:: sage: S = SimplicialComplex([[1,4], [2,4]]) sage: S.is_mutable() True sage: S.set_immutable() sage: S.is_mutable() False sage: S2 = SimplicialComplex([[1,4], [2,4]], is_mutable=False) sage: S2.is_mutable() False sage: S3 = SimplicialComplex([[1,4], [2,4]], is_mutable=False) sage: S3.is_mutable() False """ return self._is_mutable def is_immutable(self): """ Return True if immutable. EXAMPLES:: sage: S = SimplicialComplex([[1,4], [2,4]]) sage: S.is_immutable() False sage: S.set_immutable() sage: S.is_immutable() True """ return not self._is_mutable
• ## sage/homology/simplicial_complex_homset.py

diff --git a/sage/homology/simplicial_complex_homset.py b/sage/homology/simplicial_complex_homset.py
 a r""" Homsets between simplicial complexes AUTHORS: - Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to work with the homset cache. EXAMPLES: :: import sage.homology.simplicial_complex_ def is_SimplicialComplexHomset(x): """ Return True if and only if x is a simplicial complex homspace. Return True if and only if x is a simplicial complex homspace. EXAMPLES:: sage: H = Hom(SimplicialComplex(2),SimplicialComplex(3)) sage: S = SimplicialComplex(is_mutable=False) sage: T = SimplicialComplex(is_mutable=False) sage: H = Hom(S, T) sage: H Set of Morphisms from Simplicial complex with vertex set (0, 1, 2) and facets {()} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {()} in Category of simplicial complexes Set of Morphisms from Simplicial complex with vertex set () and facets {()} to Simplicial complex with vertex set () and facets {()} in Category of simplicial complexes sage: from sage.homology.simplicial_complex_homset import is_SimplicialComplexHomset sage: is_SimplicialComplexHomset(H) True class SimplicialComplexHomset(sage.categ def __call__(self, f): """ INPUT: f -- a dictionary with keys exactly the vertices of the domain and values vertices of the codomain EXAMPLE:: - f -- a dictionary with keys exactly the vertices of the domain and values vertices of the codomain EXAMPLES:: sage: S = simplicial_complexes.Sphere(3) sage: T = simplicial_complexes.Sphere(2) class SimplicialComplexHomset(sage.categ sage: x = H(f) sage: x Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 2, 4: 2} from Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 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)} """ return simplicial_complex_morphism.SimplicialComplexMorphism(f,self.domain(),self.codomain()) def diagonal_morphism(self,rename_vertices=True): """ Returns the diagonal morphism in Hom(S,SxS). r""" Returns the diagonal morphism in Hom(S, S \times S). EXAMPLES:: sage: S = simplicial_complexes.Sphere(2) sage: H = Hom(S,S.product(S)) sage: H = Hom(S,S.product(S, is_mutable=False)) sage: d = H.diagonal_morphism() sage: d Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3'} 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 16 vertices and 96 facets Simplicial complex morphism {0: 'L0R0', 1: 'L1R1', 2: 'L2R2', 3: 'L3R3'} 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 16 vertices and 96 facets sage: T = SimplicialComplex(3) sage: U = T.product(T,rename_vertices = False) sage: T = SimplicialComplex([[0], [1]], is_mutable=False) sage: U = T.product(T,rename_vertices = False, is_mutable=False) sage: G = Hom(T,U) sage: e = G.diagonal_morphism(rename_vertices = False) sage: e Simplicial complex morphism {0: (0, 0), 1: (1, 1), 2: (2, 2), 3: (3, 3)} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {()} to Simplicial complex with 16 vertices and facets {()} Simplicial complex morphism {0: (0, 0), 1: (1, 1)} from Simplicial complex with vertex set (0, 1) and facets {(0,), (1,)} to Simplicial complex with 4 vertices and facets {((1, 1),), ((1, 0),), ((0, 0),), ((0, 1),)} """ if self._codomain == self._domain.product(self._domain,rename_vertices=rename_vertices): class SimplicialComplexHomset(sage.categ else: for i in self._domain.vertices().set(): f[i] = (i,i) return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,X) return simplicial_complex_morphism.SimplicialComplexMorphism(f, self._domain,X) else: raise TypeError, "Diagonal morphism is only defined for Hom(X,XxX)." def identity(self): """ Returns the identity morphism of Hom(S,S). Returns the identity morphism of Hom(S,S). EXAMPLES:: class SimplicialComplexHomset(sage.categ sage: i.is_identity() True sage: T = SimplicialComplex(3,[[0,1]]) sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: G = Hom(T,T) sage: G.identity() Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1)} Simplicial complex morphism {0: 0, 1: 1} from Simplicial complex with vertex set (0, 1) and facets {(0, 1)} to Simplicial complex with vertex set (0, 1) and facets {(0, 1)} """ if self.is_endomorphism_set(): f = dict() class SimplicialComplexHomset(sage.categ f[i]=i return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain) else: raise TypeError, "Identity map is only defined for endomorphism sets." raise TypeError("Identity map is only defined for endomorphism sets.") def an_element(self): """ Returns a (non-random) element of self. Returns a (non-random) element of self. EXAMPLES::
• ## sage/homology/simplicial_complex_morphism.py

diff --git a/sage/homology/simplicial_complex_morphism.py b/sage/homology/simplicial_complex_morphism.py
 a AUTHORS: - Benjamin Antieau (2009.06) - Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to work with the homset cache. This module implements morphisms of simplicial complexes. The input is given by a dictionary on the vertex set or the effective vertex set of a simplicial complex. The initialization checks that faces are sent to faces. by a dictionary on the vertex set of a simplicial complex. The initialization checks that faces are sent to faces. There is also the capability to create the fiber product of two morphisms with the same codomain. There is also the capability to create the fiber product of two morphisms with the same codomain. EXAMPLES:: sage: S = SimplicialComplex(5,[[0,2],[1,5],[3,4]]) sage: H = Hom(S,S.product(S)) sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False) sage: H = Hom(S,S.product(S, is_mutable=False)) sage: H.diagonal_morphism() Simplicial 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 facets sage: S = SimplicialComplex(5,[[0,2],[1,5],[3,4]]) sage: T = SimplicialComplex(4,[[0,2],[1,3]]) sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False) sage: T = SimplicialComplex([[0,2],[1,3]], is_mutable=False) sage: f = {0:0,1:1,2:2,3:1,4:3,5:3} sage: H = Hom(S,T) sage: x = H(f) sage: x.image() Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 3), (0, 2)} sage: x.is_surjective() False True sage: x.is_injective() False sage: x.is_identity() EXAMPLES:: Simplicial 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)} sage: S = simplicial_complexes.Sphere(2) sage: T = S.product(SimplicialComplex(1,[[0,1]]),rename_vertices = False) sage: T = S.product(SimplicialComplex([[0,1]]), rename_vertices = False, is_mutable=False) sage: H = Hom(T,S) sage: T Simplicial complex with 8 vertices and 12 facets EXAMPLES:: sage: z = y.fiber_product(x) sage: z                                     # this is the mapping path space Simplicial 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)} """ #***************************************************************************** from sage.algebras.steenrod.steenrod_alg def is_SimplicialComplexMorphism(x): """ Returns True if and only if x is a morphism of simplicial complexes. Returns True if and only if x is a morphism of simplicial complexes. EXAMPLES:: sage: from sage.homology.simplicial_complex_morphism import is_SimplicialComplexMorphism sage: S = SimplicialComplex(5,[[0,1],[3,4]]) sage: S = SimplicialComplex([[0,1],[3,4]], is_mutable=False) sage: H = Hom(S,S) sage: f = {0:0,1:1,2:2,3:3,4:4,5:5} sage: f = {0:0,1:1,3:3,4:4} sage: x = H(f) sage: is_SimplicialComplexMorphism(x) True class SimplicialComplexMorphism(SageObje """ def __init__(self,f,X,Y): """ Input is a dictionary f, the domain, and the codomain. Input is a dictionary f, the domain X, and the codomain Y. One can define the dictionary either on the vertices of X or on the effective vertices of X (X.effective_vertices()). Note that this difference 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. This is because two SimplicialComplexes with the same faces but different vertex sets are not equal. One can define the dictionary on the vertices of X. EXAMPLES:: sage: S = SimplicialComplex(5,[[0,1],[3,4]]) sage: S = SimplicialComplex([[0,1],[2],[3,4],[5]], is_mutable=False) sage: H = Hom(S,S) sage: f = {0:0,1:1,2:2,3:3,4:4,5:5} sage: g = {0:0,1:1,3:3,4:4} sage: g = {0:0,1:1,2:0,3:3,4:4,5:0} sage: x = H(f) sage: y = H(g) sage: x==y sage: x == y False sage: x.image() Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (0, 1)} Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (5,), (2,), (0, 1)} sage: y.image() Simplicial complex with vertex set (0, 1, 3, 4) and facets {(3, 4), (0, 1)} sage: x.image()==y.image() sage: x.image() == y.image() False """ if not isinstance(X,simplicial_complex.SimplicialComplex) or not isinstance(Y,simplicial_complex.SimplicialComplex): raise ValueError, "X and Y must be SimplicialComplexes." if not set(f.keys())==X._vertex_set.set() and not set(f.keys())==X.effective_vertices().set(): raise ValueError, "f must be a dictionary from the vertex set of X to single values in the vertex set of Y." raise ValueError("X and Y must be SimplicialComplexes.") if not set(f.keys()) == X._vertex_set.set(): raise ValueError("f must be a dictionary from the vertex set of X to single values in the vertex set of Y.") dim = X.dimension() Y_faces = Y.faces() for k in range(dim+1): class SimplicialComplexMorphism(SageObje fi.append(f[j]) v = simplicial_complex.Simplex(set(fi)) if not v in Y_faces[v.dimension()]: raise ValueError, "f must be a dictionary from the vertices of X to the vertices of Y." raise ValueError("f must be a dictionary from the vertices of X to the vertices of Y.") self._vertex_dictionary = f self._domain = X self._codomain = Y def __eq__(self,x): """ Returns True if and only if self == x. Returns True if and only if self == x. EXAMPLES:: class SimplicialComplexMorphism(SageObje sage: i==j False sage: T = SimplicialComplex(3,[[1,2]]) sage: T = SimplicialComplex([[1,2]], is_mutable=False) sage: T Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 2)} Simplicial complex with vertex set (1, 2) and facets {(1, 2)} sage: G = Hom(T,T) sage: k = G.identity() sage: g = {0:0,1:1,2:2,3:3} sage: g = {1:1,2:2} sage: l = G(g) sage: k==l sage: k == l True """ class SimplicialComplexMorphism(SageObje """ Input is a simplex of the domain. Output is the image simplex. If optional argument orientation is True, return a pair (image simplex, oriented) where oriented is 1 or -1 depending on whether the map preserves or reverses the orientation of the image simplex. If the optional argument orientation is True, then this returns a pair (image simplex, oriented) where oriented is 1 or -1 depending on whether the map preserves or reverses the orientation of the image simplex. EXAMPLES:: class SimplicialComplexMorphism(SageObje An orientation-reversing example:: sage: X = SimplicialComplex(1, [[0,1]]) sage: X = SimplicialComplex([[0,1]], is_mutable=False) sage: g = Hom(X,X)({0:1, 1:0}) sage: g(Simplex([0,1])) (0, 1) class SimplicialComplexMorphism(SageObje def _repr_(self): """ Print representation Return a string representation of self. EXAMPLES:: class SimplicialComplexMorphism(SageObje 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)} sage: i._repr_() '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)}' """ return "Simplicial complex morphism " + str(self._vertex_dictionary) + " from " + self._domain._repr_() + " to " + self._codomain._repr_() def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False): """ Returns the associated chain complex morphism of self. Returns the associated chain complex morphism of self. EXAMPLES:: class SimplicialComplexMorphism(SageObje [ 0  0  0] [ 0 -1  0], 2: []} sage: X = SimplicialComplex(1, [[0, 1]]) sage: X = SimplicialComplex([[0, 1]], is_mutable=False) sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary {0: [0 1] [1 0], 1: [-1]} class SimplicialComplexMorphism(SageObje def image(self): """ Computes the image simplicial complex of f. Computes the image simplicial complex of f. EXAMPLES:: sage: S = SimplicialComplex(3,[[0,1],[2,3]]) sage: T = SimplicialComplex(1,[[0,1]]) sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False) sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: f = {0:0,1:1,2:0,3:1} sage: H = Hom(S,T) sage: x = H(f) sage: x.image() Simplicial complex with vertex set (0, 1) and facets {(0, 1)} sage: S = SimplicialComplex(2) sage: S = SimplicialComplex(is_mutable=False) sage: H = Hom(S,S) sage: i = H.identity() sage: i.image() Simplicial complex with vertex set (0, 1, 2) and facets {()} Simplicial complex with vertex set () and facets {()} sage: i.is_surjective() True sage: S = SimplicialComplex(5,[[0,1]]) sage: T = SimplicialComplex(3,[[0,1]]) sage: S = SimplicialComplex([[0,1]], is_mutable=False) sage: T = SimplicialComplex([[0,1], [0,2]], is_mutable=False) sage: f = {0:0,1:1} sage: g = {0:0,1:1,2:2,3:3,4:4,5:5} sage: g = {0:0,1:1} sage: k = {0:0,1:2} sage: H = Hom(S,T) sage: x = H(f) sage: y = H(g) sage: z = H(k) sage: x == y True sage: x == z False sage: x.image() Simplicial complex with vertex set (0, 1) and facets {(0, 1)} sage: y.image() Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(0, 1)} Simplicial complex with vertex set (0, 1) and facets {(0, 1)} sage: z.image() Simplicial complex with vertex set (0, 2) and facets {(0, 2)} """ fa = [self(i) for i in self._domain.facets()] return simplicial_complex.SimplicialComplex(set(self._vertex_dictionary.values()),fa,maximality_check=True) return simplicial_complex.SimplicialComplex(fa, maximality_check=True) def domain(self): """ class SimplicialComplexMorphism(SageObje EXAMPLES:: sage: S = SimplicialComplex(3,[[0,1],[2,3]]) sage: T = SimplicialComplex(1,[[0,1]]) sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False) sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: f = {0:0,1:1,2:0,3:1} sage: H = Hom(S,T) sage: x = H(f) sage: x.domain() Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 1)} """ return self._domain class SimplicialComplexMorphism(SageObje EXAMPLES:: sage: S = SimplicialComplex(3,[[0,1],[2,3]]) sage: T = SimplicialComplex(1,[[0,1]]) sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False) sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: f = {0:0,1:1,2:0,3:1} sage: H = Hom(S,T) sage: x = H(f) class SimplicialComplexMorphism(SageObje def is_surjective(self): """ Returns True if and only if self is surjective. Returns True if and only if self is surjective. EXAMPLES:: sage: S = SimplicialComplex(3,[(0,1,2)]) sage: S = SimplicialComplex([(0,1,2)], is_mutable=False) sage: S Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2)} sage: T = SimplicialComplex(2,[(0,1)]) Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)} sage: T = SimplicialComplex([(0,1)], is_mutable=False) sage: T Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1)} Simplicial complex with vertex set (0, 1) and facets {(0, 1)} sage: H = Hom(S,T) sage: x = H({0:0,1:1,2:1,3:2}) sage: x = H({0:0,1:1,2:1}) sage: x.is_surjective() True sage: S = SimplicialComplex(3,[[0,1],[2,3]]) sage: T = SimplicialComplex(1,[[0,1]]) sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False) sage: T = SimplicialComplex([[0,1]], is_mutable=False) sage: f = {0:0,1:1,2:0,3:1} sage: H = Hom(S,T) sage: x = H(f) sage: x.is_surjective() True """ """ return self._codomain == self.image() def is_injective(self): """ Returns True if and only if self is injective. Returns True if and only if self is injective. EXAMPLES:: class SimplicialComplexMorphism(SageObje def is_identity(self): """ If x is an identity morphism, returns True. Otherwise, False. If self is an identity morphism, returns True. Otherwise, False. EXAMPLES:: class SimplicialComplexMorphism(SageObje return False else: f = dict() for i in self._domain.vertices().set(): for i in self._domain._vertex_set.set(): f[i] = i if self._vertex_dictionary != f: return False else: return True def fiber_product(self,other,rename_vertices = True): def fiber_product(self, other, rename_vertices = True): """ Fiber product of self and other. Both morphisms should have the same codomain. The method returns a morphism of simplicial complexes, which is the morphism from the space of the fiber product to the codomain. Fiber product of self and other. Both morphisms should have the same codomain. The method returns a morphism of simplicial complexes, which is the morphism from the space of the fiber product to the codomain. EXAMPLES:: sage: S = SimplicialComplex(2,[[0,1],[1,2]]) sage: T = SimplicialComplex(2,[[0,2]]) sage: U = SimplicialComplex(1,[[0,1]]) sage: S = SimplicialComplex([[0,1],[1,2]], is_mutable=False) sage: T = SimplicialComplex([[0,2],[1]], is_mutable=False) sage: U = SimplicialComplex([[0,1],[2]], is_mutable=False) sage: H = Hom(S,U) sage: G = Hom(T,U) sage: f = {0:0,1:1,2:0} class SimplicialComplexMorphism(SageObje sage: y = G(g) sage: z = x.fiber_product(y) sage: z Simplicial 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)} Simplicial complex morphism {'L1R2': 1, 'L1R1': 1, 'L2R0': 0, 'L0R0': 0} from Simplicial complex with 4 vertices and facets {('L2R0',), ('L1R1',), ('L0R0', 'L1R2')} to Simplicial complex with vertex set (0, 1, 2) and facets {(2,), (0, 1)} """ if self._codomain != other._codomain: raise ValueError, "self and other must have the same codomain." raise ValueError("self and other must have the same codomain.") X = self._domain.product(other._domain,rename_vertices = rename_vertices) v = [] f = dict() eff1 = self._domain.effective_vertices() eff2 = other._domain.effective_vertices() eff1 = self._domain._vertex_set eff2 = other._domain._vertex_set for i in eff1: for j in eff2: if self(simplicial_complex.Simplex([i])) == other(simplicial_complex.Simplex([j])): class SimplicialComplexMorphism(SageObje else: v.append((i,j)) f[(i,j)] = self._vertex_dictionary[i] return SimplicialComplexMorphism(f,X.generated_subcomplex(v),self._codomain) return SimplicialComplexMorphism(f, X.generated_subcomplex(v), self._codomain)
• ## sage/schemes/toric/divisor.py

diff --git a/sage/schemes/toric/divisor.py b/sage/schemes/toric/divisor.py`
 a class ToricDivisor_generic(Divisor_gener sage: D = -D0 + 2*D2 - D3 sage: M = dP6.fan().dual_lattice() sage: D._sheaf_complex( M(1,0) ) Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3,), (0, 1)} Simplicial complex with vertex set (0, 1, 3) and facets {(3,), (0, 1)} """ fan = self.parent().scheme().fan() ray_is_negative = [ m*ray + self.coefficient(i) < 0 class ToricDivisor_generic(Divisor_gener return False return all(ray_is_negative[i] for i in cone.ambient_ray_indices()) negative_cones = filter(cone_is_negative, flatten(fan.cones())) return SimplicialComplex(fan.nrays() - 1, [c.ambient_ray_indices() for c in negative_cones]) return SimplicialComplex([c.ambient_ray_indices() for c in negative_cones]) def _sheaf_cohomology(self, cplx): """ class ToricDivisor_generic(Divisor_gener sage: dP6 = toric_varieties.dP6() sage: D = dP6.divisor(1) sage: D._sheaf_cohomology( SimplicialComplex([1],[]) ) sage: D._sheaf_cohomology( SimplicialComplex() ) (1, 0, 0) sage: D._sheaf_cohomology( SimplicialComplex([1,2,3],[[1,2],[2,3],[3,1]]) ) sage: D._sheaf_cohomology( SimplicialComplex([[1,2],[2,3],[3,1]]) ) (0, 0, 1) A more complicated example to test that trac #10731 is fixed::