Exemple #1
0
    def __call__(self, f):
        """
        `f` is a dictionary of matrices in the basis of the chain complex.

        EXAMPLES::

            sage: S = simplicial_complexes.Sphere(5)
            sage: H = Hom(S,S)
            sage: i = H.identity()
            sage: C = S.chain_complex()
            sage: G = Hom(C,C)
            sage: x = i.associated_chain_complex_morphism()
            sage: f = x._matrix_dictionary
            sage: y = G(f)
            sage: x == y
            True

        """
        return ChainComplexMorphism(f, self.domain(), self.codomain())
Exemple #2
0
    def associated_chain_complex_morphism(self,
                                          base_ring=ZZ,
                                          augmented=False,
                                          cochain=False):
        """
        Returns the associated chain complex morphism of self.

        EXAMPLES::

            sage: S = simplicial_complexes.Sphere(1)
            sage: T = simplicial_complexes.Sphere(2)
            sage: H = Hom(S,T)
            sage: f = {0:0,1:1,2:2}
            sage: x = H(f)
            sage: x
            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)}
            sage: a = x.associated_chain_complex_morphism()
            sage: a
            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
            sage: a._matrix_dictionary
            {0: [0 0 0]
            [0 1 0]
            [0 0 1]
            [1 0 0],
             1: [0 0 0]
            [0 1 0]
            [0 0 0]
            [1 0 0]
            [0 0 0]
            [0 0 1],
             2: []}
            sage: x.associated_chain_complex_morphism(augmented=True)
            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
            sage: x.associated_chain_complex_morphism(cochain=True)
            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
            sage: x.associated_chain_complex_morphism(augmented=True,cochain=True)
            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
            sage: x.associated_chain_complex_morphism(base_ring=GF(11))
            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

        Some simplicial maps which reverse the orientation of a few simplices::

            sage: g = {0:1, 1:2, 2:0}
            sage: H(g).associated_chain_complex_morphism()._matrix_dictionary
            {0: [0 0 0]
             [1 0 0]
             [0 1 0]
             [0 0 1], 1: [ 0  0  0]
             [-1  0  0]
             [ 0  0  0]
             [ 0  0  1]
             [ 0  0  0]
             [ 0 -1  0], 2: []}

            sage: X = SimplicialComplex(1, [[0, 1]])
            sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary
            {0: [0 1]
             [1 0], 1: [-1]}
        """
        max_dim = max(self._domain.dimension(), self._codomain.dimension())
        min_dim = min(self._domain.dimension(), self._codomain.dimension())
        matrices = {}
        if augmented is True:
            m = matrix.Matrix(base_ring, 1, 1, 1)
            if not cochain:
                matrices[-1] = m
            else:
                matrices[-1] = m.transpose()
        for dim in range(min_dim + 1):
            #             X_faces = list(self._domain.faces()[dim])
            #             Y_faces = list(self._codomain.faces()[dim])
            X_faces = list(self._domain.n_cells(dim))
            Y_faces = list(self._codomain.n_cells(dim))
            num_faces_X = len(X_faces)
            num_faces_Y = len(Y_faces)
            mval = [0 for i in range(num_faces_X * num_faces_Y)]
            for i in X_faces:
                y, oriented = self(i, orientation=True)
                if y.dimension() < dim:
                    pass
                else:
                    mval[X_faces.index(i) +
                         (Y_faces.index(y) * num_faces_X)] = oriented
            m = matrix.Matrix(base_ring,
                              num_faces_Y,
                              num_faces_X,
                              mval,
                              sparse=True)
            if not cochain:
                matrices[dim] = m
            else:
                matrices[dim] = m.transpose()
        for dim in range(min_dim + 1, max_dim + 1):
            try:
                l1 = len(self._codomain.n_cells(dim))
            except KeyError:
                l1 = 0
            try:
                l2 = len(self._domain.n_cells(dim))
            except KeyError:
                l2 = 0
            m = matrix.zero_matrix(base_ring, l1, l2, sparse=True)
            if not cochain:
                matrices[dim] = m
            else:
                matrices[dim] = m.transpose()
        if not cochain:
            return ChainComplexMorphism(matrices,\
                    self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
                    self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
        else:
            return ChainComplexMorphism(matrices,\
                    self._codomain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
                    self._domain.chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
Exemple #3
0
    def __init__(self, matrices, f, g=None):
        r"""
        Create a chain homotopy between the given chain maps
        from a dictionary of matrices.

        EXAMPLES:

        If ``g`` is not specified, it is set equal to
        `f - (H \partial + \partial H)`. ::

            sage: from sage.homology.chain_homotopy import ChainHomotopy
            sage: C = ChainComplex({1: matrix(ZZ, 1, 2, (1,0)), 2: matrix(ZZ, 2, 1, (0, 2))}, degree_of_differential=-1)
            sage: D = ChainComplex({2: matrix(ZZ, 1, 1, (6,))}, degree_of_differential=-1)
            sage: f_d = {1: matrix(ZZ, 1, 2, (0,3)), 2: identity_matrix(ZZ, 1)}
            sage: f = Hom(C,D)(f_d)
            sage: H_d = {0: identity_matrix(ZZ, 1), 1: matrix(ZZ, 1, 2, (2,2))}
            sage: H = ChainHomotopy(H_d, f)
            sage: H._g.in_degree(0)
            []
            sage: H._g.in_degree(1)
            [-13  -9]
            sage: H._g.in_degree(2)
            [-3]

        TESTS:

        Try to construct a chain homotopy in which the maps do not
        have matching domains and codomains::

            sage: g = Hom(C,C)({}) # the zero chain map
            sage: H = ChainHomotopy(H_d, f, g)
            Traceback (most recent call last):
            ...
            ValueError: the chain maps are not compatible
        """
        domain = f.domain()
        codomain = f.codomain()
        deg = domain.degree_of_differential()
        # Check that the chain complexes are compatible. This should
        # never arise, because first there should be errors in
        # constructing the chain maps. But just in case...
        if domain.degree_of_differential() != codomain.degree_of_differential(
        ):
            raise ValueError('the chain complexes are not compatible')
        if g is not None:
            # Check that the chain maps are compatible.
            if not (domain == g.domain() and codomain == g.codomain()):
                raise ValueError('the chain maps are not compatible')
            # Check that the data define a chain homotopy.
            for i in domain.differential():
                if i in matrices and i + deg in matrices:
                    if not (codomain.differential(i - deg) * matrices[i] +
                            matrices[i + deg] * domain.differential(i)
                            == f.in_degree(i) - g.in_degree(i)):
                        raise ValueError(
                            'the data do not define a valid chain homotopy')
                elif i in matrices:
                    if not (codomain.differential(i - deg) * matrices[i]
                            == f.in_degree(i) - g.in_degree(i)):
                        raise ValueError(
                            'the data do not define a valid chain homotopy')
                elif i + deg in matrices:
                    if not (matrices[i + deg] * domain.differential(i)
                            == f.in_degree(i) - g.in_degree(i)):
                        raise ValueError(
                            'the data do not define a valid chain homotopy')
        else:
            # Define g.
            g_data = {}
            for i in domain.differential():
                if i in matrices and i + deg in matrices:
                    g_data[i] = f.in_degree(
                        i) - matrices[i + deg] * domain.differential(
                            i) - codomain.differential(i - deg) * matrices[i]
                elif i in matrices:
                    g_data[i] = f.in_degree(
                        i) - codomain.differential(i - deg) * matrices[i]
                elif i + deg in matrices:
                    g_data[i] = f.in_degree(
                        i) - matrices[i + deg] * domain.differential(i)
            g = ChainComplexMorphism(g_data, domain, codomain)
        self._matrix_dictionary = {}
        for i in matrices:
            m = matrices[i]
            # Use immutable matrices because they're hashable.
            m.set_immutable()
            self._matrix_dictionary[i] = m
        self._f = f
        self._g = g
        Morphism.__init__(self, Hom(domain, codomain))
Exemple #4
0
    def __init__(self, matrices, pi, iota):
        r"""
        Create a chain contraction from the given data.

        EXAMPLES::

            sage: from sage.homology.chain_homotopy import ChainContraction
            sage: C = ChainComplex({0: zero_matrix(ZZ, 1), 1: identity_matrix(ZZ, 1)})
            sage: D = ChainComplex({0: matrix(ZZ, 0, 1)})

        The chain complex `C` is chain homotopy equivalent to `D`,
        which is just a copy of `\ZZ` in degree 0, and we try
        construct a chain contraction, but get the map `\iota` wrong::

            sage: pi = Hom(C,D)({0: identity_matrix(ZZ, 1)})
            sage: iota = Hom(D,C)({0: zero_matrix(ZZ, 1)})
            sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota)
            Traceback (most recent call last):
            ...
            ValueError: the composite 'pi iota' is not the identity

        Another bad `\iota`::

            sage: iota = pi  # wrong domain, codomain
            sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: zero_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota)
            Traceback (most recent call last):
            ...
            ValueError: the chain maps are not composable

        `\iota` is okay, but wrong data defining `H`::

            sage: iota = Hom(D,C)({0: identity_matrix(ZZ, 1)})
            sage: H = ChainContraction({0: zero_matrix(ZZ, 0, 1), 1: identity_matrix(ZZ, 1), 2: identity_matrix(ZZ, 1)}, pi, iota)
            Traceback (most recent call last):
            ...
            ValueError: not an algebraic gradient vector field
        """
        from sage.matrix.constructor import identity_matrix
        from .chain_complex_morphism import ChainComplexMorphism

        if not (pi.domain() == iota.codomain()
                and pi.codomain() == iota.domain()):
            raise ValueError('the chain maps are not composable')
        C = pi.domain()
        D = pi.codomain()
        base_ring = C.base_ring()

        # Check that the composite 'pi iota' is 1.
        for i in D.nonzero_degrees():
            if pi.in_degree(i) * iota.in_degree(i) != identity_matrix(
                    base_ring, D.free_module_rank(i)):
                raise ValueError("the composite 'pi iota' is not the identity")

        # Construct the chain map 'id_C'.
        id_C_dict = {}
        for i in C.nonzero_degrees():
            id_C_dict[i] = identity_matrix(base_ring, C.free_module_rank(i))
        id_C = ChainComplexMorphism(id_C_dict, C, C)

        # Now check that
        # - `H` is a chain homotopy between `id_C` and `\iota \pi`
        # - `HH = 0`
        ChainHomotopy.__init__(self, matrices, id_C, iota * pi)
        if not self.is_algebraic_gradient_vector_field():
            raise ValueError('not an algebraic gradient vector field')
        # Check that `\pi H = 0`:
        deg = C.degree_of_differential()
        for i in matrices:
            if pi.in_degree(i - deg) * matrices[i] != 0:
                raise ValueError(
                    'the data do not define a valid chain contraction: pi H != 0'
                )
        # Check that `H \iota = 0`:
        for i in iota._matrix_dictionary:
            if i in matrices:
                if matrices[i] * iota.in_degree(i) != 0:
                    raise ValueError(
                        'the data do not define a valid chain contraction: H iota != 0'
                    )
        self._pi = pi
        self._iota = iota
    def associated_chain_complex_morphism(self,base_ring=ZZ,augmented=False,cochain=False):
        """
        Returns the associated chain complex morphism of ``self``.

        EXAMPLES::

            sage: S = simplicial_complexes.Sphere(1)
            sage: T = simplicial_complexes.Sphere(2)
            sage: H = Hom(S,T)
            sage: f = {0:0,1:1,2:2}
            sage: x = H(f)
            sage: x
            Simplicial complex morphism:
              From: Minimal triangulation of the 1-sphere
              To:   Minimal triangulation of the 2-sphere
              Defn: 0 |--> 0
                    1 |--> 1
                    2 |--> 2
            sage: a = x.associated_chain_complex_morphism()
            sage: a
            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
            sage: a._matrix_dictionary
            {0: [1 0 0]
             [0 1 0]
             [0 0 1]
             [0 0 0], 1: [1 0 0]
             [0 1 0]
             [0 0 0]
             [0 0 1]
             [0 0 0]
             [0 0 0], 2: []}
            sage: x.associated_chain_complex_morphism(augmented=True)
            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
            sage: x.associated_chain_complex_morphism(cochain=True)
            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
            sage: x.associated_chain_complex_morphism(augmented=True,cochain=True)
            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
            sage: x.associated_chain_complex_morphism(base_ring=GF(11))
            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

        Some simplicial maps which reverse the orientation of a few simplices::

            sage: g = {0:1, 1:2, 2:0}
            sage: H(g).associated_chain_complex_morphism()._matrix_dictionary
            {0: [0 0 1]
             [1 0 0]
             [0 1 0]
             [0 0 0], 1: [ 0 -1  0]
             [ 0  0 -1]
             [ 0  0  0]
             [ 1  0  0]
             [ 0  0  0]
             [ 0  0  0], 2: []}
            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]}
        """
        max_dim = max(self.domain().dimension(),self.codomain().dimension())
        min_dim = min(self.domain().dimension(),self.codomain().dimension())
        matrices = {}
        if augmented is True:
            m = matrix(base_ring,1,1,1)
            if not cochain:
                matrices[-1] = m
            else:
                matrices[-1] = m.transpose()
        for dim in range(min_dim+1):
            X_faces = list(self.domain().n_cells(dim))
            Y_faces = list(self.codomain().n_cells(dim))
            num_faces_X = len(X_faces)
            num_faces_Y = len(Y_faces)
            mval = [0 for i in range(num_faces_X*num_faces_Y)]
            for i in X_faces:
                y, oriented = self(i, orientation=True)
                if y.dimension() < dim:
                    pass
                else:
                    mval[X_faces.index(i)+(Y_faces.index(y)*num_faces_X)] = oriented
            m = matrix(base_ring,num_faces_Y,num_faces_X,mval,sparse=True)
            if not cochain:
                matrices[dim] = m
            else:
                matrices[dim] = m.transpose()
        for dim in range(min_dim+1,max_dim+1):
            try:
                l1 = len(self.codomain().n_cells(dim))
            except KeyError:
                l1 = 0
            try:
                l2 = len(self.domain().n_cells(dim))
            except KeyError:
                l2 = 0
            m = zero_matrix(base_ring,l1,l2,sparse=True)
            if not cochain:
                matrices[dim] = m
            else:
                matrices[dim] = m.transpose()
        if not cochain:
            return ChainComplexMorphism(matrices,\
                    self.domain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
                    self.codomain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))
        else:
            return ChainComplexMorphism(matrices,\
                    self.codomain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain),\
                    self.domain().chain_complex(base_ring=base_ring,augmented=augmented,cochain=cochain))