Ticket #6099: trac_6099-rebased.patch

File trac_6099-rebased.patch, 58.8 KB (added by jhpalmieri, 13 years ago)

rebased version of patch. apply only this file.

  • doc/en/reference/homology.rst

    # HG changeset patch
    # User J. H. Palmieri <palmieri@math.washington.edu>
    # Date 1259091902 28800
    # Node ID e3035f8ac9b555085e66a6ec9722b46c22481283
    # Parent  44f70d431d43e3dfaa1487641ee6864d5025fb06
    rebased patch for 6099
    
    diff -r 44f70d431d43 -r e3035f8ac9b5 doc/en/reference/homology.rst
    a b  
    88   :maxdepth: 2
    99
    1010   sage/homology/simplicial_complex
     11   sage/homology/simplicial_complex_morphism
     12   sage/homology/simplicial_complex_homset
    1113   sage/homology/chain_complex
     14   sage/homology/chain_complex_morphism
     15   sage/homology/chain_complex_homspace
    1216   sage/homology/examples
  • sage/homology/all.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/all.py
    a b  
    11from chain_complex import ChainComplex
    22
     3from chain_complex_morphism import ChainComplexMorphism
     4
    35from simplicial_complex import SimplicialComplex
    46
     7from simplicial_complex_morphism import SimplicialComplexMorphism
     8
    59from examples import simplicial_complexes
  • sage/homology/chain_complex.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/chain_complex.py
    a b  
    338338    EXAMPLES::
    339339
    340340        sage: ChainComplex()
    341         Chain complex with at most 0 nonzero terms over Integer Ring.
     341        Chain complex with at most 0 nonzero terms over Integer Ring
    342342        sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])})
    343343        sage: C
    344         Chain complex with at most 2 nonzero terms over Integer Ring.
     344        Chain complex with at most 2 nonzero terms over Integer Ring
    345345        sage: D = ChainComplex([matrix(ZZ, 2, 2, [0, 1, 0, 0]), matrix(ZZ, 2, 2, [0, 1, 0, 0])], base_ring=GF(2)); D
    346         Chain complex with at most 3 nonzero terms over Finite Field of size 2.
     346        Chain complex with at most 3 nonzero terms over Finite Field of size 2
    347347        sage: D == loads(dumps(D))
    348348        True
    349349
     
    361361    Defining the base ring implicitly::
    362362
    363363        sage: ChainComplex([matrix(QQ, 3, 1), matrix(ZZ, 4, 3)])
    364         Chain complex with at most 2 nonzero terms over Rational Field.
     364        Chain complex with at most 2 nonzero terms over Rational Field
    365365        sage: ChainComplex([matrix(GF(125, 'a'), 3, 1), matrix(ZZ, 4, 3)])
    366         Chain complex with at most 2 nonzero terms over Finite Field in a of size 5^3.
     366        Chain complex with at most 2 nonzero terms over Finite Field in a of size 5^3
    367367
    368368    If the matrices are defined over incompatible rings, an error results::
    369369
     
    389389        EXAMPLES::
    390390
    391391            sage: C = ChainComplex(); C
    392             Chain complex with at most 0 nonzero terms over Integer Ring.
     392            Chain complex with at most 0 nonzero terms over Integer Ring
    393393            sage: D = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])})
    394394            sage: D
    395             Chain complex with at most 2 nonzero terms over Integer Ring.
     395            Chain complex with at most 2 nonzero terms over Integer Ring
    396396        """
    397397        try:
    398398            deg = grading_group(degree)
     
    874874        import sage.categories.all       
    875875        return sage.categories.all.ChainComplexes(self.base_ring())
    876876
     877    def _Hom_(self, other, category=None):
     878        """
     879        Return the set of chain maps between chain complexes ``self``
     880        and ``other``.
     881
     882        EXAMPLES::
     883
     884            sage: S = simplicial_complexes.Sphere(2)
     885            sage: T = simplicial_complexes.Torus()
     886            sage: C = S.chain_complex(augmented=True,cochain=True)
     887            sage: D = T.chain_complex(augmented=True,cochain=True)
     888            sage: Hom(C,D)  # indirect doctest
     889            Set of Morphisms from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring
     890        """
     891        from sage.homology.chain_complex_homspace import ChainComplexHomspace
     892        return ChainComplexHomspace(self, other)
     893
    877894    def _repr_(self):
    878895        """
    879896        Print representation.
     
    882899
    883900            sage: C = ChainComplex({0: matrix(ZZ, 2, 3, [3, 0, 0, 0, 0, 0])})
    884901            sage: C._repr_()
    885             'Chain complex with at most 2 nonzero terms over Integer Ring.'
     902            'Chain complex with at most 2 nonzero terms over Integer Ring'
    886903        """
    887904        diffs = filter(lambda mat: mat.nrows() + mat.ncols() > 0,
    888905                       self._diff.values())
    889906        string1 = "Chain complex with at most"
    890         string2 = " %s nonzero terms over %s." % (len(diffs),
     907        string2 = " %s nonzero terms over %s" % (len(diffs),
    891908                                                  self._base_ring)
    892909        return string1 + string2
    893910
  • new file sage/homology/chain_complex_homspace.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/chain_complex_homspace.py
    - +  
     1r"""
     2Homspaces between chain complexes
     3
     4Note that some significant functionality is lacking. Namely, the homspaces
     5are not actually modules over the base ring. It will be necessary to
     6enrich some of the structure of chain complexes for this to be naturally
     7available. On other hand, there are various overloaded operators. __mul__
     8acts as composition. One can __add__, and one can __mul__ with a ring element
     9on the right.
     10
     11EXAMPLES::
     12
     13    sage: S = simplicial_complexes.Sphere(2)
     14    sage: T = simplicial_complexes.Torus()
     15    sage: C = S.chain_complex(augmented=True,cochain=True)
     16    sage: D = T.chain_complex(augmented=True,cochain=True)
     17    sage: G = Hom(C,D)
     18    sage: G
     19    Set of Morphisms from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring in Category of chain complexes over Integer Ring
     20
     21    sage: S = simplicial_complexes.ChessboardComplex(3,3)
     22    sage: H = Hom(S,S)
     23    sage: i = H.identity()
     24    sage: x = i.associated_chain_complex_morphism(augmented=True)
     25    sage: x
     26    Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring
     27    sage: x._matrix_dictionary
     28    {0: [1 0 0 0 0 0 0 0 0]
     29    [0 1 0 0 0 0 0 0 0]
     30    [0 0 1 0 0 0 0 0 0]
     31    [0 0 0 1 0 0 0 0 0]
     32    [0 0 0 0 1 0 0 0 0]
     33    [0 0 0 0 0 1 0 0 0]
     34    [0 0 0 0 0 0 1 0 0]
     35    [0 0 0 0 0 0 0 1 0]
     36    [0 0 0 0 0 0 0 0 1], 1: [1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     37    [0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     38    [0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     39    [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
     40    [0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0]
     41    [0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0]
     42    [0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0]
     43    [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0]
     44    [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
     45    [0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0]
     46    [0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
     47    [0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0]
     48    [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0]
     49    [0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
     50    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
     51    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0]
     52    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0]
     53    [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1], 2: [1 0 0 0 0 0]
     54    [0 1 0 0 0 0]
     55    [0 0 1 0 0 0]
     56    [0 0 0 1 0 0]
     57    [0 0 0 0 1 0]
     58    [0 0 0 0 0 1], -1: [1]}
     59
     60    sage: S = simplicial_complexes.Sphere(2)
     61    sage: A = Hom(S,S)
     62    sage: i = A.identity()
     63    sage: x = i.associated_chain_complex_morphism()
     64    sage: x
     65    Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring
     66    sage: y = x*4
     67    sage: z = y*y
     68    sage: (y+z)
     69    Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring
     70    sage: f = x._matrix_dictionary
     71    sage: C = S.chain_complex()
     72    sage: G = Hom(C,C)
     73    sage: w = G(f)
     74    sage: w==x
     75    True
     76
     77"""
     78
     79#*****************************************************************************
     80# Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com>
     81#
     82#  Distributed under the terms of the GNU General Public License (GPL)
     83#
     84#    This code is distributed in the hope that it will be useful,
     85#    but WITHOUT ANY WARRANTY; without even the implied warranty
     86#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     87#
     88#  See the GNU General Public License for more details; the full text
     89#  is available at:
     90#
     91#                  http://www.gnu.org/licenses/
     92#
     93#*****************************************************************************
     94
     95import sage.categories.homset
     96import sage.homology.chain_complex as chain_complex
     97import sage.homology.chain_complex_morphism as chain_complex_morphism
     98
     99def is_ChainComplexHomspace(x):
     100    """
     101    Returns True if and only if x is a morphism of chain complexes.
     102
     103    EXAMPLES::
     104
     105        sage: from sage.homology.chain_complex_homspace import is_ChainComplexHomspace
     106        sage: T = SimplicialComplex(17,[[1,2,3,4],[7,8,9]])
     107        sage: C = T.chain_complex(augmented=True,cochain=True)
     108        sage: G = Hom(C,C)
     109        sage: is_ChainComplexHomspace(G)
     110        True
     111
     112    """
     113    return isinstance(x,ChainComplexHomspace)
     114
     115class ChainComplexHomspace(sage.categories.homset.Homset):
     116    """
     117    Class of homspaces of chain complex morphisms.
     118   
     119    EXAMPLES::
     120
     121        sage: T = SimplicialComplex(17,[[1,2,3,4],[7,8,9]])
     122        sage: C = T.chain_complex(augmented=True,cochain=True)
     123        sage: G = Hom(C,C)
     124        sage: G
     125        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
     126
     127    """
     128    def __call__(self, f):
     129        """
     130        f is a dictionary of matrices in the basis of the chain complex.
     131
     132        EXAMPLES::
     133
     134            sage: S = simplicial_complexes.Sphere(5)
     135            sage: H = Hom(S,S)
     136            sage: i = H.identity()
     137            sage: C = S.chain_complex()
     138            sage: G = Hom(C,C)
     139            sage: x = i.associated_chain_complex_morphism()
     140            sage: f = x._matrix_dictionary
     141            sage: y = G(f)
     142            sage: x==y
     143            True
     144
     145        """
     146        return chain_complex_morphism.ChainComplexMorphism(f, self.domain(), self.codomain())
  • new file sage/homology/chain_complex_morphism.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/chain_complex_morphism.py
    - +  
     1r"""
     2Morphisms of chain complexes
     3
     4AUTHORS:
     5
     6- Benjamin Antieau <d.ben.antieau@gmail.com> (2009.06)
     7
     8This module implements morphisms of chain complexes. The input is a dictionary whose
     9keys are in the grading group of the chain complex and whose values are matrix morphisms.
     10
     11EXAMPLES::
     12
     13    from sage.matrix.constructor import zero_matrix
     14    sage: S = simplicial_complexes.Sphere(1)
     15    sage: S
     16    Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
     17    sage: C = S.chain_complex()
     18    sage: C.differential()
     19    {0: [], 1: [ 1  1  0]
     20    [ 0 -1 -1]
     21    [-1  0  1]}
     22    sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)}
     23    sage: G = Hom(C,C)
     24    sage: x = G(f)
     25    sage: x
     26    Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring
     27    sage: x._matrix_dictionary
     28    {0: [0 0 0]
     29    [0 0 0]
     30    [0 0 0], 1: [0 0 0]
     31    [0 0 0]
     32    [0 0 0]}
     33
     34"""
     35
     36#*****************************************************************************
     37# Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com>
     38#
     39#  Distributed under the terms of the GNU General Public License (GPL)
     40#
     41#    This code is distributed in the hope that it will be useful,
     42#    but WITHOUT ANY WARRANTY; without even the implied warranty
     43#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     44#
     45#  See the GNU General Public License for more details; the full text
     46#  is available at:
     47#
     48#                  http://www.gnu.org/licenses/
     49#
     50#*****************************************************************************
     51
     52import sage.homology.simplicial_complex as simplicial_complex
     53import sage.matrix.all as matrix
     54from sage.structure.sage_object import SageObject
     55from sage.rings.integer_ring import ZZ
     56
     57def is_ChainComplexMorphism(x):
     58    """
     59    Returns True if and only if x is a chain complex morphism.
     60
     61    EXAMPLES::
     62
     63        sage: from sage.homology.chain_complex_morphism import is_ChainComplexMorphism
     64        sage: S = simplicial_complexes.Sphere(14)
     65        sage: H = Hom(S,S)
     66        sage: i = H.identity()
     67        sage: S = simplicial_complexes.Sphere(6)
     68        sage: H = Hom(S,S)
     69        sage: i = H.identity()
     70        sage: x = i.associated_chain_complex_morphism()
     71        sage: x # indirect doctest
     72        Chain complex morphism from Chain complex with at most 7 nonzero terms over Integer Ring to Chain complex with at most 7 nonzero terms over Integer Ring
     73        sage: is_ChainComplexMorphism(x)
     74        True
     75
     76    """
     77    return isinstance(x,ChainComplexMorphism)
     78
     79class ChainComplexMorphism(SageObject):
     80    """
     81    An element of this class is a morphism of chain complexes.
     82    """
     83    def __init__(self,matrices,C,D):
     84        """
     85        Create a morphism from a dictionary of matrices.
     86
     87        EXAMPLES::
     88
     89            from sage.matrix.constructor import zero_matrix
     90            sage: S = simplicial_complexes.Sphere(1)
     91            sage: S
     92            Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
     93            sage: C = S.chain_complex()
     94            sage: C.differential()
     95            {0: [], 1: [ 1  1  0]
     96            [ 0 -1 -1]
     97            [-1  0  1]}
     98            sage: f = {0:zero_matrix(ZZ,3,3),1:zero_matrix(ZZ,3,3)}
     99            sage: G = Hom(C,C)
     100            sage: x = G(f)
     101            sage: x
     102            Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring
     103            sage: x._matrix_dictionary
     104            {0: [0 0 0]
     105            [0 0 0]
     106            [0 0 0], 1: [0 0 0]
     107            [0 0 0]
     108            [0 0 0]}
     109
     110        """
     111        if C._grading_group != ZZ:
     112            raise NotImplementedError, "Chain complex morphisms are not implemented over gradings other than ZZ."
     113        d = C._degree
     114        if d != D._degree:
     115            raise ValueError, "Chain complex morphisms are not defined for chain complexes of different degrees."
     116        if d != -1 and d != 1:
     117            raise NotImplementedError, "Chain complex morphisms are not implemented for degrees besides -1 and 1."
     118        dim_min = min(min(C.differential().keys()),min(D.differential().keys()))
     119        dim_max = max(max(C.differential().keys()),max(D.differential().keys()))
     120        if not C.base_ring()==D.base_ring():
     121            raise NotImplementedError, "Chain complex morphisms between chain complexes of different base rings are not implemented."
     122        for i in range(dim_min,dim_max):
     123            try:
     124                matrices[i]
     125            except KeyError:
     126                matrices[i] = matrix.zero_matrix(C.base_ring(),D.differential()[i].ncols(),C.differential()[i].ncols(),sparse=True)
     127            try:
     128                matrices[i+1]
     129            except KeyError:
     130                matrices[i+1] = matrix.zero_matrix(C.base_ring(),D.differential()[i+1].ncols(),C.differential()[i+1].ncols(),sparse=True)
     131            if d==-1:
     132                if (i+1) in C.differential().keys() and (i+1) in D.differential().keys():
     133                    if not matrices[i]*C.differential()[i+1]==D.differential()[i+1]*matrices[i+1]:
     134                        raise ValueError, "Matrices must define a chain complex morphism."
     135                elif (i+1) in C.differential().keys():
     136                    if not matrices[i]*C.differential()[i+1].is_zero():
     137                        raise ValueError, "Matrices must define a chain complex morphism."
     138                elif (i+1) in D.differential().keys():
     139                    if not D.differential()[i+1]*matrices[i+1].is_zero():
     140                        raise ValueError, "Matrices must define a chain complex morphism."
     141            else:
     142                if i in C.differential().keys() and i in D.differential().keys():
     143                    if not matrices[i+1]*C.differential()[i]==D.differential()[i]*matrices[i]:
     144                        raise ValueError, "Matrices must define a chain complex morphism."
     145                elif i in C.differential().keys():
     146                    if not matrices[i+1]*C.differential()[i].is_zero():
     147                        raise ValueError, "Matrices must define a chain complex morphism."
     148                elif i in D.differential().keys():
     149                    if not D.differential()[i]*matrices[i].is_zero():
     150                        raise ValueError, "Matrices must define a chain complex morphism."
     151        self._matrix_dictionary = matrices
     152        self._domain = C
     153        self._codomain = D
     154 
     155    def __neg__(self):
     156        """
     157        Returns -x.
     158
     159        EXAMPLES::
     160
     161            sage: S = simplicial_complexes.Sphere(2)
     162            sage: H = Hom(S,S)
     163            sage: i = H.identity()
     164            sage: x = i.associated_chain_complex_morphism()
     165            sage: w = -x
     166            sage: w._matrix_dictionary
     167            {0: [-1  0  0  0]
     168            [ 0 -1  0  0]
     169            [ 0  0 -1  0]
     170            [ 0  0  0 -1],
     171             1: [-1  0  0  0  0  0]
     172            [ 0 -1  0  0  0  0]
     173            [ 0  0 -1  0  0  0]
     174            [ 0  0  0 -1  0  0]
     175            [ 0  0  0  0 -1  0]
     176            [ 0  0  0  0  0 -1],
     177             2: [-1  0  0  0]
     178            [ 0 -1  0  0]
     179            [ 0  0 -1  0]
     180            [ 0  0  0 -1]}
     181       
     182        """
     183        f = dict()
     184        for i in self._matrix_dictionary.keys():
     185            f[i] = -self._matrix_dictionary[i]
     186        return ChainComplexMorphism(f,self._domain,self._codomain)
     187
     188    def __add__(self,x):
     189        """
     190        Returns self+x.
     191
     192        EXAMPLES::
     193
     194            sage: S = simplicial_complexes.Sphere(2)
     195            sage: H = Hom(S,S)
     196            sage: i = H.identity()
     197            sage: x = i.associated_chain_complex_morphism()
     198            sage: z = x+x
     199            sage: z._matrix_dictionary
     200            {0: [2 0 0 0]
     201            [0 2 0 0]
     202            [0 0 2 0]
     203            [0 0 0 2],
     204             1: [2 0 0 0 0 0]
     205            [0 2 0 0 0 0]
     206            [0 0 2 0 0 0]
     207            [0 0 0 2 0 0]
     208            [0 0 0 0 2 0]
     209            [0 0 0 0 0 2],
     210             2: [2 0 0 0]
     211            [0 2 0 0]
     212            [0 0 2 0]
     213            [0 0 0 2]}
     214
     215        """
     216        if not isinstance(x,ChainComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._matrix_dictionary.keys() != x._matrix_dictionary.keys():
     217            raise TypeError, "Unsupported operation."
     218        f = dict()
     219        for i in self._matrix_dictionary.keys():
     220            f[i] = self._matrix_dictionary[i] + x._matrix_dictionary[i]
     221        return ChainComplexMorphism(f,self._domain,self._codomain)
     222
     223    def __mul__(self,x):
     224        """
     225        Returns self*x if self and x are composable morphisms or if x is an element of the base_ring.
     226
     227        EXAMPLES::
     228
     229            sage: S = simplicial_complexes.Sphere(2)
     230            sage: H = Hom(S,S)
     231            sage: i = H.identity()
     232            sage: x = i.associated_chain_complex_morphism()
     233            sage: y = x*2
     234            sage: y._matrix_dictionary
     235            {0: [2 0 0 0]
     236            [0 2 0 0]
     237            [0 0 2 0]
     238            [0 0 0 2],
     239             1: [2 0 0 0 0 0]
     240            [0 2 0 0 0 0]
     241            [0 0 2 0 0 0]
     242            [0 0 0 2 0 0]
     243            [0 0 0 0 2 0]
     244            [0 0 0 0 0 2],
     245             2: [2 0 0 0]
     246            [0 2 0 0]
     247            [0 0 2 0]
     248            [0 0 0 2]}
     249            sage: z = y*y
     250            sage: z._matrix_dictionary
     251            {0: [4 0 0 0]
     252            [0 4 0 0]
     253            [0 0 4 0]
     254            [0 0 0 4],
     255             1: [4 0 0 0 0 0]
     256            [0 4 0 0 0 0]
     257            [0 0 4 0 0 0]
     258            [0 0 0 4 0 0]
     259            [0 0 0 0 4 0]
     260            [0 0 0 0 0 4],
     261             2: [4 0 0 0]
     262            [0 4 0 0]
     263            [0 0 4 0]
     264            [0 0 0 4]}
     265
     266        """
     267        if not isinstance(x,ChainComplexMorphism) or self._codomain != x._domain:
     268            try:
     269                y = self._domain.base_ring()(x)
     270            except TypeError:
     271                raise TypeError, "Multiplication is not defined."
     272            f = dict()
     273            for i in self._matrix_dictionary.keys():
     274                f[i] = self._matrix_dictionary[i] * y
     275            return ChainComplexMorphism(f,self._domain,self._codomain)
     276        f = dict()
     277        for i in self._matrix_dictionary.keys():
     278            f[i] = x._matrix_dictionary[i]*self._matrix_dictionary[i]
     279        return ChainComplexMorphism(f,self._domain,x._codomain)
     280
     281    def __rmul__(self,x):
     282        """
     283        Returns x*self if x is an element of the base_ring.
     284
     285        EXAMPLES::
     286
     287            sage: S = simplicial_complexes.Sphere(2)
     288            sage: H = Hom(S,S)
     289            sage: i = H.identity()
     290            sage: x = i.associated_chain_complex_morphism()
     291            sage: 2*x == x*2
     292            True
     293            sage: 3*x == x*2
     294            False
     295        """
     296        try:
     297            y = self._domain.base_ring()(x)
     298        except TypeError:
     299            raise TypeError, "Multiplication is not defined."
     300        f = dict()
     301        for i in self._matrix_dictionary.keys():
     302            f[i] = y * self._matrix_dictionary[i]
     303        return ChainComplexMorphism(f,self._domain,self._codomain)
     304
     305    def __sub__(self,x):
     306        """
     307        Returns self-x.
     308
     309        EXAMPLES::
     310
     311            sage: S = simplicial_complexes.Sphere(2)
     312            sage: H = Hom(S,S)
     313            sage: i = H.identity()
     314            sage: x = i.associated_chain_complex_morphism()
     315            sage: y = x-x
     316            sage: y._matrix_dictionary
     317            {0: [0 0 0 0]
     318            [0 0 0 0]
     319            [0 0 0 0]
     320            [0 0 0 0],
     321             1: [0 0 0 0 0 0]
     322            [0 0 0 0 0 0]
     323            [0 0 0 0 0 0]
     324            [0 0 0 0 0 0]
     325            [0 0 0 0 0 0]
     326            [0 0 0 0 0 0],
     327             2: [0 0 0 0]
     328            [0 0 0 0]
     329            [0 0 0 0]
     330            [0 0 0 0]}
     331
     332        """   
     333        return self + (-x)
     334
     335    def __eq__(self,x):
     336        """
     337        Returns True if and only if self==x.
     338
     339        EXAMPLES::
     340
     341            sage: S = SimplicialComplex(3)
     342            sage: H = Hom(S,S)
     343            sage: i = H.identity()
     344            sage: x = i.associated_chain_complex_morphism()
     345            sage: x
     346            Chain complex morphism from Chain complex with at most 0 nonzero terms over Integer Ring to Chain complex with at most 0 nonzero terms over Integer Ring
     347            sage: f = x._matrix_dictionary
     348            sage: C = S.chain_complex()
     349            sage: G = Hom(C,C)
     350            sage: y = G(f)
     351            sage: x==y
     352            True
     353
     354        """
     355        if not isinstance(x,ChainComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._matrix_dictionary != x._matrix_dictionary:
     356            return False
     357        else:
     358            return True
     359
     360    def _repr_(self):
     361        """
     362        Returns the string representation of self.
     363
     364        EXAMPLES::
     365
     366            sage: S = SimplicialComplex(3)
     367            sage: H = Hom(S,S)
     368            sage: i = H.identity()
     369            sage: x = i.associated_chain_complex_morphism()
     370            sage: x
     371            Chain complex morphism from Chain complex with at most 0 nonzero terms over Integer Ring to Chain complex with at most 0 nonzero terms over Integer Ring
     372            sage: x._repr_()
     373            'Chain complex morphism from Chain complex with at most 0 nonzero terms over Integer Ring to Chain complex with at most 0 nonzero terms over Integer Ring'
     374
     375        """
     376        return "Chain complex morphism from " + self._domain._repr_() + " to " + self._codomain._repr_()
  • sage/homology/simplicial_complex.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/simplicial_complex.py
    a b  
    11791179
    11801180            sage: circle = SimplicialComplex(2, [[0,1], [1,2], [0, 2]])
    11811181            sage: circle.chain_complex()
    1182             Chain complex with at most 2 nonzero terms over Integer Ring.
     1182            Chain complex with at most 2 nonzero terms over Integer Ring
    11831183            sage: circle.chain_complex()._latex_()
    11841184            '\\Bold{Z}^{3} \\xrightarrow{d_{1}} \\Bold{Z}^{3}'
    11851185            sage: circle.chain_complex(base_ring=QQ, augmented=True)
    1186             Chain complex with at most 3 nonzero terms over Rational Field.
     1186            Chain complex with at most 3 nonzero terms over Rational Field
    11871187        """
    11881188        # initialize subcomplex
    11891189        if subcomplex is None:
     
    17161716                faces.append(Simplex(list(f.set().difference(s.set()))))
    17171717        return SimplicialComplex(self.vertices(), faces)
    17181718
     1719    def effective_vertices(self):
     1720        """
     1721        The set of vertices belonging to some face. Returns a Simplex.
     1722
     1723        EXAMPLES::
     1724
     1725            sage: S = SimplicialComplex(15)
     1726            sage: S
     1727            Simplicial complex with 16 vertices and facets {()}
     1728            sage: S.effective_vertices()
     1729            ()
     1730
     1731            sage: S = SimplicialComplex(15,[[0,1,2,3],[6,7]])
     1732            sage: S
     1733            Simplicial complex with 16 vertices and facets {(6, 7), (0, 1, 2, 3)}
     1734            sage: S.effective_vertices()
     1735            (0, 1, 2, 3, 6, 7)
     1736
     1737            sage: type(S.effective_vertices())
     1738            <class 'sage.homology.simplicial_complex.Simplex'>
     1739
     1740        """
     1741        try:
     1742            v = self.faces()[0]
     1743        except KeyError:
     1744            return Simplex(-1)
     1745        f = []
     1746        for i in v:
     1747            f.append(i[0])
     1748        return Simplex(set(f))
     1749
     1750    def generated_subcomplex(self,sub_vertex_set):
     1751        """
     1752        Returns the largest sub-simplicial complex of self containing
     1753        exactly ``sub_vertex_set`` as vertices.
     1754
     1755        EXAMPLES::
     1756
     1757            sage: S = simplicial_complexes.Sphere(2)
     1758            sage: S
     1759            Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
     1760            sage: S.generated_subcomplex([0,1,2])
     1761            Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)}
     1762
     1763        """
     1764        if not self.vertices().set().issuperset(sub_vertex_set):
     1765            raise TypeError, "input must be a subset of the vertex set."
     1766        faces = []
     1767        for i in range(self.dimension()+1):
     1768            for j in self.faces()[i]:
     1769                if j.set().issubset(sub_vertex_set):
     1770                    faces.append(j)
     1771        return SimplicialComplex(sub_vertex_set,faces,maximality_check=True)
     1772
    17191773    def _complement(self, simplex):
    17201774        """
    17211775        Return the complement of a simplex in the vertex set of this
     
    22522306        import sage.categories.all
    22532307        return sage.categories.all.SimplicialComplexes()
    22542308
     2309    def _Hom_(self, other, category=None):
     2310        """
     2311        Return the set of simplicial maps between simplicial complexes
     2312        ``self`` and ``other``.
     2313
     2314        EXAMPLES::
     2315
     2316            sage: S = simplicial_complexes.Sphere(1)
     2317            sage: T = simplicial_complexes.Sphere(2)
     2318            sage: H = Hom(S,T)  # indirect doctest
     2319            sage: H
     2320            Set of Morphisms from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} in Category of simplicial complexes
     2321            sage: f = {0:0,1:1,2:3}
     2322            sage: x = H(f)
     2323            sage: x
     2324            Simplicial complex morphism {0: 0, 1: 1, 2: 3} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
     2325        """
     2326        from sage.homology.simplicial_complex_homset import SimplicialComplexHomset
     2327        return SimplicialComplexHomset(self, other)
     2328
     2329
    22552330    def _repr_(self):
    22562331        """
    22572332        Print representation. If there are only a few vertices or
  • new file sage/homology/simplicial_complex_homset.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/simplicial_complex_homset.py
    - +  
     1r"""
     2Homsets between simplicial complexes
     3
     4EXAMPLES:
     5
     6::
     7
     8    sage: S = simplicial_complexes.Sphere(1)
     9    sage: T = simplicial_complexes.Sphere(2)
     10    sage: H = Hom(S,T)
     11    sage: f = {0:0,1:1,2:3}
     12    sage: x = H(f)
     13    sage: x
     14    Simplicial complex morphism {0: 0, 1: 1, 2: 3} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
     15    sage: x.is_injective()
     16    True
     17    sage: x.is_surjective()
     18    False
     19    sage: x.image()
     20    Simplicial complex with vertex set (0, 1, 3) and facets {(1, 3), (0, 3), (0, 1)}
     21    sage: from sage.homology.simplicial_complex import Simplex
     22    sage: s = Simplex([1,2])
     23    sage: x(s)
     24    (1, 3)
     25
     26TESTS::
     27
     28    sage: S = simplicial_complexes.Sphere(1)
     29    sage: T = simplicial_complexes.Sphere(2)
     30    sage: H = Hom(S,T)
     31    sage: loads(dumps(H))==H
     32    True
     33
     34"""
     35
     36#*****************************************************************************
     37# Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com>
     38#
     39#  Distributed under the terms of the GNU General Public License (GPL)
     40#
     41#    This code is distributed in the hope that it will be useful,
     42#    but WITHOUT ANY WARRANTY; without even the implied warranty
     43#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     44#
     45#  See the GNU General Public License for more details; the full text
     46#  is available at:
     47#
     48#                  http://www.gnu.org/licenses/
     49#
     50#*****************************************************************************
     51
     52import sage.categories.homset
     53import sage.homology.simplicial_complex as simplicial_complex
     54import sage.homology.simplicial_complex_morphism as simplicial_complex_morphism
     55
     56def is_SimplicialComplexHomset(x):
     57    """
     58    Return True if and only if x is a simplicial complex homspace.
     59
     60    EXAMPLES::
     61
     62        sage: H = Hom(SimplicialComplex(2),SimplicialComplex(3))
     63        sage: H
     64        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
     65        sage: from sage.homology.simplicial_complex_homset import is_SimplicialComplexHomset
     66        sage: is_SimplicialComplexHomset(H)
     67        True
     68    """
     69    return isinstance(x, SimplicialComplexHomset)
     70
     71class SimplicialComplexHomset(sage.categories.homset.Homset):
     72    def __call__(self, f):
     73        """
     74        INPUT:
     75            f -- a dictionary with keys exactly the vertices of the domain and values vertices of the codomain
     76
     77        EXAMPLE::
     78
     79            sage: S = simplicial_complexes.Sphere(3)
     80            sage: T = simplicial_complexes.Sphere(2)
     81            sage: f = {0:0,1:1,2:2,3:2,4:2}
     82            sage: H = Hom(S,T)
     83            sage: x = H(f)
     84            sage: x
     85            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)}
     86
     87           
     88        """
     89        return simplicial_complex_morphism.SimplicialComplexMorphism(f,self.domain(),self.codomain())
     90
     91    def diagonal_morphism(self,rename_vertices=True):
     92        """
     93        Returns the diagonal morphism in Hom(S,SxS).
     94
     95        EXAMPLES::
     96
     97            sage: S = simplicial_complexes.Sphere(2)
     98            sage: H = Hom(S,S.product(S))
     99            sage: d = H.diagonal_morphism()
     100            sage: d
     101            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
     102       
     103            sage: T = SimplicialComplex(3)
     104            sage: U = T.product(T,rename_vertices = False)
     105            sage: G = Hom(T,U)
     106            sage: e = G.diagonal_morphism(rename_vertices = False)
     107            sage: e
     108            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 {()}
     109
     110        """
     111
     112        if self._codomain == self._domain.product(self._domain,rename_vertices=rename_vertices):
     113            X = self._domain.product(self._domain,rename_vertices=rename_vertices)
     114            f = dict()
     115            if rename_vertices:
     116                for i in self._domain.vertices().set():
     117                    f[i] = "L"+str(i)+"R"+str(i)
     118            else:
     119                for i in self._domain.vertices().set():
     120                    f[i] = (i,i)
     121            return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,X)
     122        else:
     123            raise TypeError, "Diagonal morphism is only defined for Hom(X,XxX)."
     124       
     125    def identity(self):
     126        """
     127        Returns the identity morphism of Hom(S,S).
     128
     129        EXAMPLES::
     130
     131            sage: S = simplicial_complexes.Sphere(2)
     132            sage: H = Hom(S,S)
     133            sage: i = H.identity()
     134            sage: i.is_identity()
     135            True
     136
     137            sage: T = SimplicialComplex(3,[[0,1]])
     138            sage: G = Hom(T,T)
     139            sage: G.identity()
     140            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)}
     141
     142        """
     143        if self.is_endomorphism_set():
     144            f = dict()
     145            for i in self._domain.vertices().set():
     146                f[i]=i
     147            return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain)
     148        else:
     149            raise TypeError, "Identity map is only defined for endomorphism sets."
     150
     151    def an_element(self):
     152        """
     153        Returns a (non-random) element of self.
     154
     155        EXAMPLES::
     156
     157            sage: S = simplicial_complexes.KleinBottle()
     158            sage: T = simplicial_complexes.Sphere(5)
     159            sage: H = Hom(S,T)
     160            sage: x = H.an_element()
     161            sage: x
     162            Simplicial complex morphism {0: 0, 1: 0, 2: 0, 'R3': 0, 'L4': 0, 'L5': 0, 'L3': 0, 'R5': 0, 'R4': 0} from Simplicial complex with 9 vertices and 18 facets to Simplicial complex with vertex set (0, 1, 2, 3, 4, 5, 6) and 7 facets
     163
     164        """
     165        X_vertices = self._domain.vertices().set()
     166        try:
     167            i = self._codomain.vertices().set().__iter__().next()
     168        except StopIteration:
     169            if len(X_vertices) == 0:
     170                return dict()
     171            else:
     172                raise TypeError, "There are no morphisms from a non-empty simplicial complex to an empty simplicial comples."
     173        f = dict()
     174        for x in X_vertices:
     175            f[x]=i
     176        return simplicial_complex_morphism.SimplicialComplexMorphism(f,self._domain,self._codomain)
  • new file sage/homology/simplicial_complex_morphism.py

    diff -r 44f70d431d43 -r e3035f8ac9b5 sage/homology/simplicial_complex_morphism.py
    - +  
     1r"""
     2Morphisms of simplicial complexes
     3
     4AUTHORS:
     5
     6- Benjamin Antieau <d.ben.antieau@gmail.com> (2009.06)
     7
     8This module implements morphisms of simplicial complexes. The input is given
     9by a dictionary on the vertex set or the effective vertex set of a simplicial complex.
     10The initialization checks that faces are sent to faces.
     11
     12There is also the capability to create the fiber product of two morphisms with the same codomain.
     13
     14EXAMPLES::
     15
     16    sage: S = SimplicialComplex(5,[[0,2],[1,5],[3,4]])
     17    sage: H = Hom(S,S.product(S))
     18    sage: H.diagonal_morphism()
     19    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
     20
     21    sage: S = SimplicialComplex(5,[[0,2],[1,5],[3,4]])
     22    sage: T = SimplicialComplex(4,[[0,2],[1,3]])
     23    sage: f = {0:0,1:1,2:2,3:1,4:3,5:3}
     24    sage: H = Hom(S,T)
     25    sage: x = H(f)
     26    sage: x.image()
     27    Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 3), (0, 2)}
     28    sage: x.is_surjective()
     29    False
     30    sage: x.is_injective()
     31    False
     32    sage: x.is_identity()
     33    False
     34
     35    sage: S = simplicial_complexes.Sphere(2)
     36    sage: H = Hom(S,S)
     37    sage: i = H.identity()
     38    sage: i.image()
     39    Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
     40    sage: i.is_surjective()
     41    True
     42    sage: i.is_injective()
     43    True
     44    sage: i.is_identity()
     45    True
     46
     47    sage: S = simplicial_complexes.Sphere(2)
     48    sage: H = Hom(S,S)
     49    sage: i = H.identity()
     50    sage: j = i.fiber_product(i)
     51    sage: j
     52    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)}
     53
     54    sage: S = simplicial_complexes.Sphere(2)
     55    sage: T = S.product(SimplicialComplex(1,[[0,1]]),rename_vertices = False)
     56    sage: H = Hom(T,S)
     57    sage: T
     58    Simplicial complex with 8 vertices and 12 facets
     59    sage: T.vertices()
     60    ((0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1))
     61    sage: f = {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1, (2, 0): 2, (2, 1): 2, (3, 0): 3, (3, 1): 3}
     62    sage: x = H(f)
     63    sage: U = simplicial_complexes.Sphere(1)
     64    sage: G = Hom(U,S)
     65    sage: U
     66    Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
     67    sage: g = {0:0,1:1,2:2}
     68    sage: y = G(g)
     69    sage: z = y.fiber_product(x)
     70    sage: z                                     # this is the mapping path space
     71    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)}
     72
     73
     74"""
     75
     76#*****************************************************************************
     77# Copyright (C) 2009 D. Benjamin Antieau <d.ben.antieau@gmail.com>
     78#
     79#  Distributed under the terms of the GNU General Public License (GPL)
     80#
     81#    This code is distributed in the hope that it will be useful,
     82#    but WITHOUT ANY WARRANTY; without even the implied warranty
     83#    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     84#
     85#  See the GNU General Public License for more details; the full text
     86#  is available at:
     87#
     88#                  http://www.gnu.org/licenses/
     89#
     90#*****************************************************************************
     91
     92import sage.homology.simplicial_complex as simplicial_complex
     93import sage.matrix.all as matrix
     94from sage.structure.sage_object import SageObject
     95from sage.rings.integer_ring import ZZ
     96from sage.homology.chain_complex_morphism import ChainComplexMorphism
     97from sage.combinat.permutation import Permutation
     98from sage.algebras.steenrod_algebra_element import convert_perm
     99
     100def is_SimplicialComplexMorphism(x):
     101    """
     102    Returns True if and only if x is a morphism of simplicial complexes.
     103
     104    EXAMPLES::
     105
     106        sage: from sage.homology.simplicial_complex_morphism import is_SimplicialComplexMorphism
     107        sage: S = SimplicialComplex(5,[[0,1],[3,4]])
     108        sage: H = Hom(S,S)
     109        sage: f = {0:0,1:1,2:2,3:3,4:4,5:5}
     110        sage: x = H(f)
     111        sage: is_SimplicialComplexMorphism(x)
     112        True
     113
     114    """
     115    return isinstance(x,SimplicialComplexMorphism)
     116
     117class SimplicialComplexMorphism(SageObject):
     118    """
     119    An element of this class is a morphism of simplicial complexes.
     120    """
     121    def __init__(self,f,X,Y):
     122        """
     123        Input is a dictionary f, the domain, and the codomain.
     124
     125        One can define the dictionary either on the vertices of X or on the effective vertices of X (X.effective_vertices()). Note that this
     126        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.
     127        This is because two SimplicialComplexes with the same faces but different vertex sets are not equal.
     128
     129        EXAMPLES::
     130
     131            sage: S = SimplicialComplex(5,[[0,1],[3,4]])
     132            sage: H = Hom(S,S)
     133            sage: f = {0:0,1:1,2:2,3:3,4:4,5:5}
     134            sage: g = {0:0,1:1,3:3,4:4}
     135            sage: x = H(f)
     136            sage: y = H(g)
     137            sage: x==y
     138            False
     139            sage: x.image()
     140            Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(3, 4), (0, 1)}
     141            sage: y.image()
     142            Simplicial complex with vertex set (0, 1, 3, 4) and facets {(3, 4), (0, 1)}
     143            sage: x.image()==y.image()
     144            False
     145
     146        """
     147        if not isinstance(X,simplicial_complex.SimplicialComplex) or not isinstance(Y,simplicial_complex.SimplicialComplex):
     148            raise ValueError, "X and Y must be SimplicialComplexes."
     149        if not set(f.keys())==X._vertex_set.set() and not set(f.keys())==X.effective_vertices().set():
     150            raise ValueError, "f must be a dictionary from the vertex set of X to single values in the vertex set of Y."
     151        dim = X.dimension()
     152        Y_faces = Y.faces()
     153        for k in range(dim+1):
     154            for i in X.faces()[k]:
     155                tup = i.tuple()
     156                fi = []
     157                for j in tup:
     158                    fi.append(f[j])
     159                v = simplicial_complex.Simplex(set(fi))
     160            if not v in Y_faces[v.dimension()]:
     161                raise ValueError, "f must be a dictionary from the vertices of X to the vertices of Y."
     162        self._vertex_dictionary = f
     163        self._domain = X
     164        self._codomain = Y
     165   
     166    def __eq__(self,x):
     167        """
     168        Returns True if and only if self == x.
     169       
     170        EXAMPLES::
     171
     172            sage: S = simplicial_complexes.Sphere(2)
     173            sage: H = Hom(S,S)
     174            sage: i = H.identity()
     175            sage: i
     176            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)}
     177            sage: f = {0:0,1:1,2:2,3:2}
     178            sage: j = H(f)
     179            sage: i==j
     180            False
     181           
     182            sage: T = SimplicialComplex(3,[[1,2]])
     183            sage: T
     184            Simplicial complex with vertex set (0, 1, 2, 3) and facets {(1, 2)}
     185            sage: G = Hom(T,T)
     186            sage: k = G.identity()
     187            sage: g = {0:0,1:1,2:2,3:3}
     188            sage: l = G(g)
     189            sage: k==l
     190            True
     191
     192        """
     193        if not isinstance(x,SimplicialComplexMorphism) or self._codomain != x._codomain or self._domain != x._domain or self._vertex_dictionary != x._vertex_dictionary:
     194            return False
     195        else:
     196            return True
     197
     198    def __call__(self,x,orientation=False):
     199        """
     200        Input is a simplex of the domain. Output is the image simplex.
     201       
     202        If optional argument ``orientation`` is True, return a pair
     203        ``(image simplex, oriented)`` where ``oriented`` is 1 or `-1`
     204        depending on whether the map preserves or reverses the
     205        orientation of the image simplex.
     206
     207        EXAMPLES::
     208
     209            sage: S = simplicial_complexes.Sphere(2)
     210            sage: T = simplicial_complexes.Sphere(3)
     211            sage: S
     212            Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
     213            sage: T
     214            Simplicial complex with vertex set (0, 1, 2, 3, 4) and 5 facets
     215            sage: f = {0:0,1:1,2:2,3:3}
     216            sage: H = Hom(S,T)
     217            sage: x = H(f)
     218            sage: from sage.homology.simplicial_complex import Simplex
     219            sage: x(Simplex([0,2,3]))
     220            (0, 2, 3)
     221
     222        An orientation-reversing example::
     223
     224            sage: X = SimplicialComplex(1, [[0,1]])
     225            sage: g = Hom(X,X)({0:1, 1:0})
     226            sage: g(Simplex([0,1]))
     227            (0, 1)
     228            sage: g(Simplex([0,1]), orientation=True)
     229            ((0, 1), -1)        """
     230        dim = self._domain.dimension()
     231        if not isinstance(x,simplicial_complex.Simplex) or x.dimension() > dim or not x in self._domain.faces()[x.dimension()]:
     232            raise ValueError, "x must be a simplex of the source of f"
     233        tup=x.tuple()
     234        fx=[]
     235        for j in tup:
     236            fx.append(self._vertex_dictionary[j])
     237        if orientation:
     238            if len(set(fx)) == len(tup):
     239                oriented = Permutation(convert_perm(fx)).signature()
     240            else:
     241                oriented = 1
     242            return (simplicial_complex.Simplex(set(fx)), oriented)
     243        else:
     244            return simplicial_complex.Simplex(set(fx))
     245
     246    def _repr_(self):
     247        """
     248        Print representation
     249
     250        EXAMPLES::
     251
     252            sage: S = simplicial_complexes.Sphere(2)
     253            sage: H = Hom(S,S)
     254            sage: i = H.identity()
     255            sage: i
     256            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)}
     257            sage: i._repr_()
     258            'Simplicial complex morphism {0: 0, 1: 1, 2: 2, 3: 3} from Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}'
     259 
     260
     261        """
     262        return "Simplicial complex morphism " + str(self._vertex_dictionary) + " from " + self._domain._repr_() + " to " + self._codomain._repr_()
     263
     264    def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False):
     265        """
     266        Returns the associated chain complex morphism of self.
     267
     268        EXAMPLES::
     269
     270            sage: S = simplicial_complexes.Sphere(1)
     271            sage: T = simplicial_complexes.Sphere(2)
     272            sage: H = Hom(S,T)
     273            sage: f = {0:0,1:1,2:2}
     274            sage: x = H(f)
     275            sage: x
     276            Simplicial complex morphism {0: 0, 1: 1, 2: 2} from Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)} to Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2, 3), (0, 1, 2), (1, 2, 3), (0, 1, 3)}
     277            sage: a = x.associated_chain_complex_morphism()
     278            sage: a
     279            Chain complex morphism from Chain complex with at most 2 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring
     280            sage: a._matrix_dictionary
     281            {0: [0 0 0]
     282            [0 1 0]
     283            [0 0 1]
     284            [1 0 0],
     285             1: [0 0 0]
     286            [0 1 0]
     287            [0 0 0]
     288            [1 0 0]
     289            [0 0 0]
     290            [0 0 1],
     291             2: []}
     292            sage: x.associated_chain_complex_morphism(augmented=True)
     293            Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 4 nonzero terms over Integer Ring
     294            sage: x.associated_chain_complex_morphism(cochain=True)
     295            Chain complex morphism from Chain complex with at most 3 nonzero terms over Integer Ring to Chain complex with at most 2 nonzero terms over Integer Ring
     296            sage: x.associated_chain_complex_morphism(augmented=True,cochain=True)
     297            Chain complex morphism from Chain complex with at most 4 nonzero terms over Integer Ring to Chain complex with at most 3 nonzero terms over Integer Ring
     298            sage: x.associated_chain_complex_morphism(base_ring=GF(11))
     299            Chain complex morphism from Chain complex with at most 2 nonzero terms over Finite Field of size 11 to Chain complex with at most 3 nonzero terms over Finite Field of size 11
     300
     301        Some simplicial maps which reverse the orientation of a few simplices::
     302
     303            sage: g = {0:1, 1:2, 2:0}
     304            sage: H(g).associated_chain_complex_morphism()._matrix_dictionary
     305            {0: [0 0 0]
     306             [1 0 0]
     307             [0 1 0]
     308             [0 0 1], 1: [ 0  0  0]
     309             [-1  0  0]
     310             [ 0  0  0]
     311             [ 0  0  1]
     312             [ 0  0  0]
     313             [ 0 -1  0], 2: []}
     314
     315            sage: X = SimplicialComplex(1, [[0, 1]])
     316            sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary
     317            {0: [0 1]
     318             [1 0], 1: [-1]}
     319        """
     320        max_dim = max(self._domain.dimension(),self._codomain.dimension())
     321        min_dim = min(self._domain.dimension(),self._codomain.dimension())
     322        matrices = {}
     323        if augmented is True:
     324            m = matrix.Matrix(base_ring,1,1,1)
     325            if not cochain:
     326                matrices[-1] = m
     327            else:
     328                matrices[-1] = m.transpose()
     329        for dim in range(min_dim+1):
     330            X_faces = list(self._domain.faces()[dim])
     331            Y_faces = list(self._codomain.faces()[dim])
     332            num_faces_X = len(X_faces)
     333            num_faces_Y = len(Y_faces)
     334            mval = [0 for i in range(num_faces_X*num_faces_Y)]
     335            for i in X_faces:
     336                y, oriented = self(i, orientation=True)
     337                if y.dimension() < dim:
     338                    pass
     339                else:
     340                    mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented
     341            m = matrix.Matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True)
     342            if not cochain:
     343                matrices[dim] = m
     344            else:
     345                matrices[dim] = m.transpose()
     346        for dim in range(min_dim+1,max_dim+1):
     347            try:
     348                l1 = len(self._codomain.faces()[dim])
     349            except KeyError:
     350                l1 = 0
     351            try:
     352                l2 = len(self._domain.faces()[dim])
     353            except KeyError:
     354                l2 = 0
     355            m = matrix.zero_matrix(base_ring,l1,l2,sparse=True)
     356            if not cochain:
     357                matrices[dim] = m
     358            else:
     359                matrices[dim] = m.transpose()
     360        if not cochain:
     361            return ChainComplexMorphism(matrices,\
     362                    self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
     363                    self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
     364        else:
     365            return ChainComplexMorphism(matrices,\
     366                    self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
     367                    self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
     368       
     369    def image(self):
     370        """
     371        Computes the image simplicial complex of f.
     372       
     373        EXAMPLES::
     374
     375            sage: S = SimplicialComplex(3,[[0,1],[2,3]])
     376            sage: T = SimplicialComplex(1,[[0,1]])
     377            sage: f = {0:0,1:1,2:0,3:1}
     378            sage: H = Hom(S,T)
     379            sage: x = H(f)
     380            sage: x.image()
     381            Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
     382
     383            sage: S = SimplicialComplex(2)
     384            sage: H = Hom(S,S)
     385            sage: i = H.identity()
     386            sage: i.image()
     387            Simplicial complex with vertex set (0, 1, 2) and facets {()}
     388            sage: i.is_surjective()
     389            True
     390            sage: S = SimplicialComplex(5,[[0,1]])
     391            sage: T = SimplicialComplex(3,[[0,1]])
     392            sage: f = {0:0,1:1}
     393            sage: g = {0:0,1:1,2:2,3:3,4:4,5:5}
     394            sage: H = Hom(S,T)
     395            sage: x = H(f)
     396            sage: y = H(g)
     397            sage: x == y
     398            False
     399            sage: x.image()
     400            Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
     401            sage: y.image()
     402            Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(0, 1)}
     403
     404        """
     405        fa = [self(i) for i in self._domain.facets()]
     406        return simplicial_complex.SimplicialComplex(set(self._vertex_dictionary.values()),fa,maximality_check=True)
     407
     408    def domain(self):
     409        """
     410        Returns the domain of the morphism.
     411
     412        EXAMPLES::
     413
     414            sage: S = SimplicialComplex(3,[[0,1],[2,3]])
     415            sage: T = SimplicialComplex(1,[[0,1]])
     416            sage: f = {0:0,1:1,2:0,3:1}
     417            sage: H = Hom(S,T)
     418            sage: x = H(f)
     419            sage: x.domain()
     420            Simplicial complex with vertex set (0, 1, 2, 3) and facets {(2, 3), (0, 1)}
     421
     422        """
     423        return self._domain
     424
     425    def codomain(self):
     426        """
     427        Returns the codomain of the morphism.
     428
     429        EXAMPLES::
     430
     431            sage: S = SimplicialComplex(3,[[0,1],[2,3]])
     432            sage: T = SimplicialComplex(1,[[0,1]])
     433            sage: f = {0:0,1:1,2:0,3:1}
     434            sage: H = Hom(S,T)
     435            sage: x = H(f)
     436            sage: x.codomain()
     437            Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
     438
     439        """
     440        return self._codomain
     441       
     442    def is_surjective(self):
     443        """
     444        Returns True if and only if self is surjective.
     445
     446        EXAMPLES::
     447
     448            sage: S = SimplicialComplex(3,[(0,1,2)])
     449            sage: S
     450            Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2)}
     451            sage: T = SimplicialComplex(2,[(0,1)])
     452            sage: T
     453            Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1)}
     454            sage: H = Hom(S,T)
     455            sage: x = H({0:0,1:1,2:1,3:2})
     456            sage: x.is_surjective()
     457            True
     458
     459            sage: S = SimplicialComplex(3,[[0,1],[2,3]])
     460            sage: T = SimplicialComplex(1,[[0,1]])
     461            sage: f = {0:0,1:1,2:0,3:1}
     462            sage: H = Hom(S,T)
     463            sage: x = H(f)
     464            sage: x.is_surjective()
     465            True
     466
     467        """   
     468        return self._codomain == self.image()
     469       
     470    def is_injective(self):
     471        """
     472        Returns True if and only if self is injective.
     473
     474        EXAMPLES::
     475
     476            sage: S = simplicial_complexes.Sphere(1)
     477            sage: T = simplicial_complexes.Sphere(2)
     478            sage: U = simplicial_complexes.Sphere(3)
     479            sage: H = Hom(T,S)
     480            sage: G = Hom(T,U)
     481            sage: f = {0:0,1:1,2:0,3:1}
     482            sage: x = H(f)
     483            sage: g = {0:0,1:1,2:2,3:3}
     484            sage: y = G(g)
     485            sage: x.is_injective()
     486            False
     487            sage: y.is_injective()
     488            True
     489
     490        """
     491        v = [self._vertex_dictionary[i[0]] for i in self._domain.faces()[0]]
     492        for i in v:
     493            if v.count(i) > 1:
     494                return False
     495        return True
     496
     497    def is_identity(self):
     498        """
     499        If x is an identity morphism, returns True. Otherwise, False.
     500
     501        EXAMPLES::
     502
     503            sage: T = simplicial_complexes.Sphere(1)
     504            sage: G = Hom(T,T)
     505            sage: T
     506            Simplicial complex with vertex set (0, 1, 2) and facets {(1, 2), (0, 2), (0, 1)}
     507            sage: j = G({0:0,1:1,2:2})
     508            sage: j.is_identity()
     509            True
     510
     511            sage: S = simplicial_complexes.Sphere(2)
     512            sage: T = simplicial_complexes.Sphere(3)
     513            sage: H = Hom(S,T)
     514            sage: f = {0:0,1:1,2:2,3:3}
     515            sage: x = H(f)
     516            sage: x
     517            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, 4) and 5 facets
     518            sage: x.is_identity()
     519            False
     520
     521        """
     522        if self._domain != self._codomain:
     523            return False
     524        else:
     525            f = dict()
     526            for i in self._domain.vertices().set():
     527                f[i] = i
     528            if self._vertex_dictionary != f:
     529                return False
     530            else:
     531                return True
     532
     533    def fiber_product(self,other,rename_vertices = True):
     534        """
     535        Fiber product of self and other. Both morphisms should have the same codomain. The method returns a morphism of simplicial complexes, which
     536        is the morphism from the space of the fiber product to the codomain.
     537
     538        EXAMPLES::
     539           
     540            sage: S = SimplicialComplex(2,[[0,1],[1,2]])
     541            sage: T = SimplicialComplex(2,[[0,2]])
     542            sage: U = SimplicialComplex(1,[[0,1]])
     543            sage: H = Hom(S,U)
     544            sage: G = Hom(T,U)
     545            sage: f = {0:0,1:1,2:0}
     546            sage: g = {0:0,1:1,2:1}
     547            sage: x = H(f)
     548            sage: y = G(g)
     549            sage: z = x.fiber_product(y)
     550            sage: z
     551            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)}
     552
     553        """
     554        if self._codomain != other._codomain:
     555            raise ValueError, "self and other must have the same codomain."
     556        X = self._domain.product(other._domain,rename_vertices = rename_vertices)
     557        v = []
     558        f = dict()
     559        eff1 = self._domain.effective_vertices()
     560        eff2 = other._domain.effective_vertices()
     561        for i in eff1:
     562            for j in eff2:
     563                if self(simplicial_complex.Simplex([i])) == other(simplicial_complex.Simplex([j])):
     564                    if rename_vertices:
     565                        v.append("L"+str(i)+"R"+str(j))
     566                        f["L"+str(i)+"R"+str(j)] = self._vertex_dictionary[i]
     567                    else:
     568                        v.append((i,j))
     569                        f[(i,j)] = self._vertex_dictionary[i]
     570        return SimplicialComplexMorphism(f,X.generated_subcomplex(v),self._codomain)