Example #1
0
    def apply_morphism(self, phi):
        r"""
        Apply the morphism ``phi`` to every element of this ideal.
        Returns an ideal in the domain of ``phi``.

        EXAMPLES::

            sage: psi = CC['x'].hom([-CC['x'].0])
            sage: J = ideal([CC['x'].0 + 1]); J
            Principal ideal (x + 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
            sage: psi(J)
            Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
            sage: J.apply_morphism(psi)
            Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision

        ::

            sage: psi = ZZ['x'].hom([-ZZ['x'].0])
            sage: J = ideal([ZZ['x'].0, 2]); J
            Ideal (x, 2) of Univariate Polynomial Ring in x over Integer Ring
            sage: psi(J)
            Ideal (-x, 2) of Univariate Polynomial Ring in x over Integer Ring
            sage: J.apply_morphism(psi)
            Ideal (-x, 2) of Univariate Polynomial Ring in x over Integer Ring

        TESTS::

            sage: K.<a> = NumberField(x^2 + 1)
            sage: A = K.ideal(a)
            sage: taus = K.embeddings(K)
            sage: A.apply_morphism(taus[0]) # identity
            Fractional ideal (a)
            sage: A.apply_morphism(taus[1]) # complex conjugation
            Fractional ideal (-a)
            sage: A.apply_morphism(taus[0]) == A.apply_morphism(taus[1])
            True

        ::

            sage: K.<a> = NumberField(x^2 + 5)
            sage: B = K.ideal([2, a + 1]); B
            Fractional ideal (2, a + 1)
            sage: taus = K.embeddings(K)
            sage: B.apply_morphism(taus[0]) # identity
            Fractional ideal (2, a + 1)

        Since 2 is totally ramified, complex conjugation fixes it::

            sage: B.apply_morphism(taus[1]) # complex conjugation
            Fractional ideal (2, a + 1)
            sage: taus[1](B)
            Fractional ideal (2, a + 1)
        """
        from sage.categories.morphism import is_Morphism
        if not is_Morphism(phi):
            raise TypeError("phi must be a morphism")
        # delegate: morphisms know how to apply themselves to ideals
        return phi(self)
Example #2
0
    def apply_morphism(self, phi):
        r"""
        Apply the morphism ``phi`` to every element of this ideal.
        Returns an ideal in the domain of ``phi``.

        EXAMPLES::

            sage: psi = CC['x'].hom([-CC['x'].0])
            sage: J = ideal([CC['x'].0 + 1]); J
            Principal ideal (x + 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
            sage: psi(J)
            Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision
            sage: J.apply_morphism(psi)
            Principal ideal (x - 1.00000000000000) of Univariate Polynomial Ring in x over Complex Field with 53 bits of precision

        ::

            sage: psi = ZZ['x'].hom([-ZZ['x'].0])
            sage: J = ideal([ZZ['x'].0, 2]); J
            Ideal (x, 2) of Univariate Polynomial Ring in x over Integer Ring
            sage: psi(J)
            Ideal (-x, 2) of Univariate Polynomial Ring in x over Integer Ring
            sage: J.apply_morphism(psi)
            Ideal (-x, 2) of Univariate Polynomial Ring in x over Integer Ring

        TESTS::

            sage: K.<a> = NumberField(x^2 + 1)
            sage: A = K.ideal(a)
            sage: taus = K.embeddings(K)
            sage: A.apply_morphism(taus[0]) # identity
            Fractional ideal (a)
            sage: A.apply_morphism(taus[1]) # complex conjugation
            Fractional ideal (-a)
            sage: A.apply_morphism(taus[0]) == A.apply_morphism(taus[1])
            True

        ::

            sage: K.<a> = NumberField(x^2 + 5)
            sage: B = K.ideal([2, a + 1]); B
            Fractional ideal (2, a + 1)
            sage: taus = K.embeddings(K)
            sage: B.apply_morphism(taus[0]) # identity
            Fractional ideal (2, a + 1)

        Since 2 is totally ramified, complex conjugation fixes it::

            sage: B.apply_morphism(taus[1]) # complex conjugation
            Fractional ideal (2, a + 1)
            sage: taus[1](B)
            Fractional ideal (2, a + 1)
        """
        from sage.categories.morphism import is_Morphism
        if not is_Morphism(phi):
            raise TypeError("phi must be a morphism")
        # delegate: morphisms know how to apply themselves to ideals
        return phi(self)
Example #3
0
    def __init__(self, parent, phi, check=True):
        """
        A morphism between finitely generated modules over a PID.

        EXAMPLES::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (4, 12)
            sage: phi = Q.hom([Q.0+3*Q.1, -Q.1]); phi
            Morphism from module over Integer Ring with invariants (4, 12) to module with invariants (4, 12) that sends the generators to [(1, 3), (0, 11)]
            sage: phi(Q.0) == Q.0 + 3*Q.1
            True
            sage: phi(Q.1) == -Q.1
            True

        For full documentation, see :class:`FGP_Morphism`.
        """
        Morphism.__init__(self, parent)
        M = parent.domain()
        N = parent.codomain()
        if isinstance(phi, FGP_Morphism):
            if check:
                if phi.parent() != parent:
                    raise TypeError
            phi = phi._phi
            check = False  # no need

        # input: phi is a morphism from MO = M.optimized().V() to N.V()
        # that sends MO.W() to N.W()
        if check:
            if not is_Morphism(phi) and M == N:
                A = M.optimized()[0].V()
                B = N.V()
                s = M.base_ring()(phi) * B.coordinate_module(A).basis_matrix()
                phi = A.Hom(B)(s)

            MO, _ = M.optimized()
            if phi.domain() != MO.V():
                raise ValueError(
                    "domain of phi must be the covering module for the optimized covering module of the domain"
                )
            if phi.codomain() != N.V():
                raise ValueError(
                    "codomain of phi must be the covering module the codomain."
                )
            # check that MO.W() gets sent into N.W()
            # todo (optimize): this is slow:
            for x in MO.W().basis():
                if phi(x) not in N.W():
                    raise ValueError(
                        "phi must send optimized submodule of M.W() into N.W()"
                    )
        self._phi = phi
Example #4
0
    def __init__(self, parent, phi, check=True):
        """
        A morphism between finitely generated modules over a PID.

        EXAMPLES::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (4, 12)
            sage: phi = Q.hom([Q.0+3*Q.1, -Q.1]); phi
            Morphism from module over Integer Ring with invariants (4, 12) to module with invariants (4, 12) that sends the generators to [(1, 3), (0, 11)]
            sage: phi(Q.0) == Q.0 + 3*Q.1
            True
            sage: phi(Q.1) == -Q.1
            True

        For full documentation, see :class:`FGP_Morphism`.
        """
        Morphism.__init__(self, parent)
        M = parent.domain()
        N = parent.codomain()
        if isinstance(phi, FGP_Morphism):
            if check:
                if phi.parent() != parent:
                    raise TypeError
            phi = phi._phi
            check = False # no need

        # input: phi is a morphism from MO = M.optimized().V() to N.V()
        # that sends MO.W() to N.W()
        if check:
            if not is_Morphism(phi) and M == N:
                A = M.optimized()[0].V()
                B = N.V()
                s = M.base_ring()(phi) * B.coordinate_module(A).basis_matrix()
                phi = A.Hom(B)(s)

            MO, _ = M.optimized()
            if phi.domain() != MO.V():
                raise ValueError("domain of phi must be the covering module for the optimized covering module of the domain")
            if phi.codomain() != N.V():
                raise ValueError("codomain of phi must be the covering module the codomain.")
            # check that MO.W() gets sent into N.W()
            # todo (optimize): this is slow:
            for x in MO.W().basis():
                if phi(x) not in N.W():
                    raise ValueError("phi must send optimized submodule of M.W() into N.W()")
        self._phi = phi
Example #5
0
    def __init__(self, domain, codomain, data={}):
        """
        Initialize ``self``. Type ``QuiverRepHom?`` for more information.

        TESTS::

            sage: Q = DiGraph({1:{2:['a', 'b']}, 2:{3:['c']}}).path_semigroup()
            sage: spaces = {1: QQ^2, 2: QQ^2, 3:QQ^1}
            sage: maps = {(1, 2, 'a'): [[1, 0], [0, 0]], (1, 2, 'b'): [[0, 0], [0, 1]], (2, 3, 'c'): [[1], [1]]}
            sage: M = Q.representation(QQ, spaces, maps)
            sage: spaces2 = {2: QQ^1, 3: QQ^1}
            sage: S = Q.representation(QQ, spaces2)
            sage: f = S.hom(M)
            sage: f.is_zero()
            True
            sage: maps2 = {2:[1, -1], 3:1}
            sage: g = S.hom(maps2, M)
            sage: x = M({2: (1, -1)})
            sage: y = M({3: (1,)})
            sage: h = S.hom([x, y], M)
            sage: g == h
            True
            sage: Proj = Q.P(GF(7), 3)
            sage: Simp = Q.S(GF(7), 3)
            sage: im = Simp({3: (1,)})
            sage: Proj.hom(im, Simp).is_surjective()
            True

        TESTS::

            sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
            sage: H1 = Q.P(GF(3), 2).Hom(Q.S(GF(3), 2))
            sage: H2 = Q.P(GF(3), 2).Hom(Q.S(GF(3), 1))
            sage: H1.an_element() in H1   # indirect doctest
            True
        """
        # The data of a representation is held in the following private
        # variables:
        #
        # * _quiver
        #      The quiver of the representation.
        # * _base_ring
        #      The base ring of the representation.
        # * _domain
        #      The QuiverRep object that is the domain of the homomorphism.
        # * _codomain
        #      The QuiverRep object that is the codomain of the homomorphism.
        # * _vector
        #      A vector in some free module over the base ring of a length such
        #      that each coordinate corresponds to an entry in the matrix of a
        #      homomorphism attached to a vertex.
        #
        # The variable data can also be a vector of appropriate length.  When
        # this is the case it will be loaded directly into _vector and then
        # _assert_valid_hom is called.

        from sage.quivers.representation import QuiverRepElement, QuiverRep_with_path_basis

        self._domain = domain
        self._codomain = codomain
        self._quiver = domain._quiver
        self._base_ring = domain.base_ring()

        # Check that the quiver and base ring match
        if codomain._quiver != self._quiver:
            raise ValueError(
                "the quivers of the domain and codomain must be equal")
        if codomain.base_ring() != self._base_ring:
            raise ValueError(
                "the base ring of the domain and codomain must be equal")

        # Get the dimensions of the spaces
        mat_dims = {}
        domain_dims = {}
        codomain_dims = {}
        for v in self._quiver:
            domain_dims[v] = domain._spaces[v].dimension()
            codomain_dims[v] = codomain._spaces[v].dimension()
            mat_dims[v] = domain_dims[v] * codomain_dims[v]
        total_dim = sum(mat_dims.values())

        # Handle the case when data is a vector
        if data in self._base_ring**total_dim:
            self._vector = data
            self._assert_valid_hom()
            super(QuiverRepHom, self).__init__(domain.Hom(codomain))
            return

        # If data is not a dict, create one
        if isinstance(data, dict):
            maps_dict = data
        else:
            # If data is not a list create one, then create a dict from it
            if isinstance(data, list):
                im_list = data
            else:
                # If data is a QuiverRepHom, create a list from it
                if isinstance(data, QuiverRepHom):
                    f = data._domain.coerce_map_from(domain)
                    g = self._codomain.coerce_map_from(data._codomain)
                    im_list = [g(data(f(x))) for x in domain.gens()]

                # The only case left is that data is a QuiverRepElement
                else:
                    if not isinstance(data, QuiverRepElement):
                        raise TypeError("input data must be dictionary, list, "
                                        "QuiverRepElement or vector")
                    if not isinstance(domain, QuiverRep_with_path_basis):
                        raise TypeError(
                            "if data is a QuiverRepElement then domain "
                            "must be a QuiverRep_with_path_basis.")
                    if data not in codomain:
                        raise ValueError(
                            "if data is a QuiverRepElement then it must "
                            "be an element of codomain")
                    im_list = [
                        codomain.right_edge_action(data, p)
                        for v in domain._quiver for p in domain._bases[v]
                    ]

            # WARNING: This code assumes that the function QuiverRep.gens() returns
            # the generators ordered first by vertex and then by the order of the
            # gens() method of the space associated to that vertex.  In particular
            # this is the order that corresponds to how maps are represented via
            # matrices

            # Get the gens of the domain and check that im_list is the right length
            dom_gens = domain.gens()
            if len(im_list) != len(dom_gens):
                raise ValueError(
                    ("domain is dimension {} but only {} images"
                     " were supplied").format(len(dom_gens), len(im_list)))

            # Get the matrices of the maps
            start_index = 0
            maps_dict = {}
            for v in self._quiver:
                maps_dict[v] = []
                dim = domain._spaces[v].dimension()
                for i in range(start_index, start_index + dim):
                    if len(im_list[i].support()) != 0 and im_list[i].support(
                    ) != [v]:
                        # If the element doesn't have the correct support raise
                        # an error here, otherwise we might create a valid hom
                        # that does not map the generators to the supplied
                        # images
                        raise ValueError(
                            ("generator supported at vertex {} cannot"
                             " map to element with support {}").format(
                                 v, im_list[i].support()))
                    else:
                        # If the support works out add the images coordinates
                        # as a row of the matrix
                        maps_dict[v].append(codomain._spaces[v].coordinates(
                            im_list[i]._elems[v]))

                start_index += dim

        # Get the coordinates of the vector
        from sage.categories.morphism import is_Morphism
        vector = []
        for v in self._quiver:
            if v in maps_dict:
                if is_Morphism(maps_dict[v]):
                    if hasattr(maps_dict[v], 'matrix'):
                        m = maps_dict[v].matrix()
                    else:
                        gens_images = [
                            codomain._spaces[v].coordinate_vector(
                                maps_dict[v](x))
                            for x in domain._spaces[v].gens()
                        ]
                        m = Matrix(self._base_ring, domain_dims[v],
                                   codomain_dims[v], gens_images)
                else:
                    m = Matrix(self._base_ring, domain_dims[v],
                               codomain_dims[v], maps_dict[v])
            else:
                m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v])
            for i in range(0, domain_dims[v]):
                vector += list(m[i])

        # Wrap as a vector, check it, and return
        self._vector = (self._base_ring**total_dim)(vector)
        self._assert_valid_hom()
        super(QuiverRepHom, self).__init__(domain.Hom(codomain))
Example #6
0
    def __init__(self, domain, codomain, data={}):
        """
        Initialize ``self``. Type ``QuiverRepHom?`` for more information.

        TESTS::

            sage: Q = DiGraph({1:{2:['a', 'b']}, 2:{3:['c']}}).path_semigroup()
            sage: spaces = {1: QQ^2, 2: QQ^2, 3:QQ^1}
            sage: maps = {(1, 2, 'a'): [[1, 0], [0, 0]], (1, 2, 'b'): [[0, 0], [0, 1]], (2, 3, 'c'): [[1], [1]]}
            sage: M = Q.representation(QQ, spaces, maps)
            sage: spaces2 = {2: QQ^1, 3: QQ^1}
            sage: S = Q.representation(QQ, spaces2)
            sage: f = S.hom(M)
            sage: f.is_zero()
            True
            sage: maps2 = {2:[1, -1], 3:1}
            sage: g = S.hom(maps2, M)
            sage: x = M({2: (1, -1)})
            sage: y = M({3: (1,)})
            sage: h = S.hom([x, y], M)
            sage: g == h
            True
            sage: Proj = Q.P(GF(7), 3)
            sage: Simp = Q.S(GF(7), 3)
            sage: im = Simp({3: (1,)})
            sage: Proj.hom(im, Simp).is_surjective()
            True

        TESTS::

            sage: Q = DiGraph({1:{2:['a']}}).path_semigroup()
            sage: H1 = Q.P(GF(3), 2).Hom(Q.S(GF(3), 2))
            sage: H2 = Q.P(GF(3), 2).Hom(Q.S(GF(3), 1))
            sage: H1.an_element() in H1   # indirect doctest
            True
        """
        # The data of a representation is held in the following private
        # variables:
        #
        # * _quiver
        #      The quiver of the representation.
        # * _base_ring
        #      The base ring of the representation.
        # * _domain
        #      The QuiverRep object that is the domain of the homomorphism.
        # * _codomain
        #      The QuiverRep object that is the codomain of the homomorphism.
        # * _vector
        #      A vector in some free module over the base ring of a length such
        #      that each coordinate corresponds to an entry in the matrix of a
        #      homomorphism attached to a vertex.
        #
        # The variable data can also be a vector of appropriate length.  When
        # this is the case it will be loaded directly into _vector and then
        # _assert_valid_hom is called.

        from sage.quivers.representation import QuiverRepElement, QuiverRep_with_path_basis

        self._domain = domain
        self._codomain = codomain
        self._quiver = domain._quiver
        self._base_ring = domain.base_ring()

        # Check that the quiver and base ring match
        if codomain._quiver != self._quiver:
            raise ValueError("the quivers of the domain and codomain must be equal")
        if codomain.base_ring() != self._base_ring:
            raise ValueError("the base ring of the domain and codomain must be equal")

        # Get the dimensions of the spaces
        mat_dims = {}
        domain_dims = {}
        codomain_dims = {}
        for v in self._quiver:
            domain_dims[v] = domain._spaces[v].dimension()
            codomain_dims[v] = codomain._spaces[v].dimension()
            mat_dims[v] = domain_dims[v]*codomain_dims[v]
        total_dim = sum(mat_dims.values())

        # Handle the case when data is a vector
        if data in self._base_ring**total_dim:
            self._vector = data
            self._assert_valid_hom()
            super(QuiverRepHom, self).__init__(domain.Hom(codomain))
            return

        # If data is not a dict, create one
        if isinstance(data, dict):
            maps_dict = data
        else:
            # If data is not a list create one, then create a dict from it
            if isinstance(data, list):
                im_list = data
            else:
                # If data is a QuiverRepHom, create a list from it
                if isinstance(data, QuiverRepHom):
                    f = data._domain.coerce_map_from(domain)
                    g = self._codomain.coerce_map_from(data._codomain)
                    im_list = [g(data(f(x))) for x in domain.gens()]

                # The only case left is that data is a QuiverRepElement
                else:
                    if not isinstance(data, QuiverRepElement):
                        raise TypeError("input data must be dictionary, list, "
                                        "QuiverRepElement or vector")
                    if not isinstance(domain, QuiverRep_with_path_basis):
                        raise TypeError("if data is a QuiverRepElement then domain "
                                        "must be a QuiverRep_with_path_basis.")
                    if data not in codomain:
                        raise ValueError("if data is a QuiverRepElement then it must "
                                         "be an element of codomain")
                    im_list = [codomain.right_edge_action(data, p) for v in domain._quiver for p in domain._bases[v]]

            # WARNING: This code assumes that the function QuiverRep.gens() returns
            # the generators ordered first by vertex and then by the order of the
            # gens() method of the space associated to that vertex.  In particular
            # this is the order that corresponds to how maps are represented via
            # matrices

            # Get the gens of the domain and check that im_list is the right length
            dom_gens = domain.gens()
            if len(im_list) != len(dom_gens):
                raise ValueError(("domain is dimension {} but only {} images"
                                  " were supplied").format(len(dom_gens), len(im_list)))

            # Get the matrices of the maps
            start_index = 0
            maps_dict = {}
            for v in self._quiver:
                maps_dict[v] = []
                dim = domain._spaces[v].dimension()
                for i in range(start_index, start_index + dim):
                    if len(im_list[i].support()) != 0 and im_list[i].support() != [v]:
                        # If the element doesn't have the correct support raise
                        # an error here, otherwise we might create a valid hom
                        # that does not map the generators to the supplied
                        # images
                        raise ValueError(("generator supported at vertex {} cannot"
                                          " map to element with support {}").format(
                                          v, im_list[i].support()))
                    else:
                        # If the support works out add the images coordinates
                        # as a row of the matrix
                        maps_dict[v].append(codomain._spaces[v].coordinates(im_list[i]._elems[v]))

                start_index += dim

        # Get the coordinates of the vector
        from sage.categories.morphism import is_Morphism
        vector = []
        for v in self._quiver:
            if v in maps_dict:
                if is_Morphism(maps_dict[v]):
                    if hasattr(maps_dict[v], 'matrix'):
                        m = maps_dict[v].matrix()
                    else:
                        gens_images = [codomain._spaces[v].coordinate_vector(maps_dict[v](x))
                                       for x in domain._spaces[v].gens()]
                        m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v], gens_images)
                else:
                    m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v], maps_dict[v])
            else:
                m = Matrix(self._base_ring, domain_dims[v], codomain_dims[v])
            for i in range(0, domain_dims[v]):
                vector += list(m[i])

        # Wrap as a vector, check it, and return
        self._vector = (self._base_ring**total_dim)(vector)
        self._assert_valid_hom()
        super(QuiverRepHom, self).__init__(domain.Hom(codomain))