Пример #1
0
    def __init__(self,
                 parent,
                 matrix,
                 inhomogeneous,
                 is_zero=lambda p: False,
                 relations=[]):
        ## Checking the input of matrix and vector
        if (not SAGE_element.is_Matrix(matrix)):
            matrix = Matrix(matrix)

        if (not SAGE_element.is_Vector(inhomogeneous)):
            inhomogeneous = vector(inhomogeneous)

        if (isinstance(parent, Wrap_w_Sequence_Ring)):
            parent = parent.base()

        ## Building the parent of the matrix and the vector
        pmatrix = matrix.parent().base()
        pinhom = inhomogeneous.parent().base()

        ## Setting the variables for the matrix, the parent and the vector
        self.__parent = pushout(pmatrix, pinhom)
        self.__matrix = matrix.change_ring(self.__parent)
        self.__inhomogeneous = inhomogeneous.change_ring(self.__parent)

        ## Setting the parent for the solutions
        if (not pushout(parent, self.__parent) == parent):
            try:
                self.__matrix = self.__matrix.change_ring(parent)
                self.__inhomogeneous = self.__inhomogeneous.change_ring(parent)
                self.__parent = parent
            except:
                raise TypeError(
                    "The parent for the solutions must be an extension of the parent for the input"
                )
        self.__solution_parent = parent

        ## Setting other variables
        if (relations is None):
            relations = []
        self.__relations = [self.__parent(el) for el in relations]
        try:
            self.__gb = ideal(self.parent(), self.__relations).groebner_basis()
        except AttributeError:
            try:
                self.__gb = [ideal(self.parent(), self.__relations).gen()]
            except:
                self.__gb = [0]

        self.__is_zero = is_zero

        ## Creating the variables for the echelon form
        self.__echelon = None
        self.__transformation = None

        ## Creating the variables for the solutions
        self.__solution = None
        self.__syzygy = None
Пример #2
0
    def __call__(self, K) :
        r"""
        Apply a ``self`` to a coefficient domain `A`.
        
        INPUT:
            - `A` -- A ring or module. The domain of coefficients for
                     a ring or module of equivariant monoid power series.
        
        OUTPUT:
            An instance of :class:`~from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.EquivariantMonoidPowerSeriesAmbient_abstract`.
            A ring if the representation's extension by `A` is a ring, a module if this extension is a module.
            
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_functor import EquivariantMonoidPowerSeriesModuleFunctor
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import NNMonoid, TrivialRepresentation, TrivialCharacterMonoid
            sage: F = EquivariantMonoidPowerSeriesModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(ZZ, 1)))
            sage: emps = F(QQ)
            sage: emps.action() == NNMonoid()
            True
            sage: emps.characters()
            Character monoid over Trivial monoid
            sage: F = EquivariantMonoidPowerSeriesModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(ZZ, 3)))
            sage: emps = F(QQ)
            sage: emps.coefficient_domain()
            Vector space of dimension 3 over Rational Field
            """
        if not self.__R.base_ring().has_coerce_map_from(K) : 
            R = self.__R.base_extend( pushout(self.__R.base_ring(), K) )
        else :
            R = self.__R
        
        from monoidpowerseries_module import EquivariantMonoidPowerSeriesModule

        return EquivariantMonoidPowerSeriesModule( self.__O, self.__C, R )
Пример #3
0
    def local_diffop(self):  # ?
        r"""
        TESTS::

            sage: from ore_algebra import DifferentialOperators
            sage: from ore_algebra.analytic.path import Point
            sage: Dops, x, Dx = DifferentialOperators()
            sage: Point(1, x*Dx - 1).local_diffop()
            (x + 1)*Dx - 1
            sage: Point(RBF(1/2), x*Dx - 1).local_diffop()
            (x + 1/2)*Dx - 1
        """
        Pols_dop = self.dop.base_ring()
        # NOTE: pushout(QQ[x], K) doesn't handle embeddings well, and creates
        # an L equal but not identical to K. But then other constructors like
        # PolynomialRing(L, x) sometimes return objects over K found in cache,
        # leading to endless headaches with slow coercions. But the version here
        # may be closer to what I really want in any case.
        # XXX: This seems to work in the usual trivial case where we are looking
        # for a scalar domain containing QQ and QQ[i], but probably won't be
        # enough if we really have two different number fields with embeddings
        ex = self.exact()
        Scalars = pushout.pushout(Pols_dop.base_ring(), ex.value.parent())
        Pols = Pols_dop.change_ring(Scalars)
        A, B = self.dop.base_ring().base_ring(), ex.value.parent()
        C = Pols.base_ring()
        assert C is A or C != A
        assert C is B or C != B
        dop_P = self.dop.change_ring(Pols)
        return dop_P.annihilator_of_composition(Pols([ex.value, 1]))
Пример #4
0
    def __call__(self, P) :
        r"""
        Map a monoid power series to a symmetrisation extending the associated representation.

        INPUT:
            - `P` -- An instance of :class:`~from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.MonoidPowerSeriesAmbient_abstract`.
        
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_functor import MonoidPowerSeriesSymmetrisationModuleFunctor, MonoidPowerSeriesModuleFunctor
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import NNMonoid, TrivialRepresentation, TrivialCharacterMonoid
            sage: mps = MonoidPowerSeriesModuleFunctor(ZZ, NNMonoid(False))(FreeModule(QQ, 1))
            sage: F = MonoidPowerSeriesSymmetrisationModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(ZZ, 1)))
            sage: emps = F(mps)
            sage: emps.representation() == TrivialRepresentation("1", FreeModule(QQ, 1))
            True
            sage: mps = MonoidPowerSeriesModuleFunctor(ZZ, NNMonoid(False))(FreeModule(ZZ, 1))
            sage: F = MonoidPowerSeriesSymmetrisationModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(QQ, 1)))
            sage: emps = F(mps)
            sage: emps.representation() == TrivialRepresentation("1", FreeModule(QQ, 1))
            True
        """
        if self.__O.monoid() != P.monoid() :
            raise ValueError( "Action has to be defined on the monoid associated to P." )
        
        PR = self.__R.from_module(P.coefficient_domain())
        
        if not self.__R.base_ring().has_coerce_map_from(PR.base_ring()) : 
            R = self.__R.base_extend( pushout(self.__R.base_ring(), PR.base_ring()) )
        else :
            R = self.__R
        
        from monoidpowerseries_module import EquivariantMonoidPowerSeriesModule

        return EquivariantMonoidPowerSeriesModule( self.__O, self.__C, R )
Пример #5
0
    def fourier_ring(self):
        r"""
        The ring that Fourier expansions of all elements of this
        ring will be contained in.
        
        OUTPUT:
            An ambient of (equivariant) monoid power series.
        
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *
            sage: mps = MonoidPowerSeriesRing(ZZ, NNMonoid(False))
            sage: ger = GradedExpansionRing_class(None, Sequence([mps(1)]), PolynomialRing(QQ, 'a').ideal(0), DegreeGrading((1,)))
            sage: ger.fourier_ring()
            Ring of monoid power series over NN
            sage: ger = GradedExpansionRing_class(Sequence([MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(2))]), Sequence([MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), PolynomialRing(ZZ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: ger.fourier_ring()
            Ring of monoid power series over NN
        """
        if self.__gen_expansions.universe().base_ring() == self.base_ring():
            return self.__gen_expansions.universe()
        else:
            from sage.categories.pushout import pushout

            if self.nbasegens() == 0:
                scalar_ring = self.base_ring()
            else:
                scalar_ring = self.base_ring().base_ring()

            return pushout(self.__gen_expansions.universe(), scalar_ring)
Пример #6
0
    def __call__(self, P) :
        r"""
        Map a monoid power series to a symmetrisation extending the associated representation.

        INPUT:
            - `P` -- An instance of :class:`~from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.MonoidPowerSeriesAmbient_abstract`.
        
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_functor import MonoidPowerSeriesSymmetrisationModuleFunctor, MonoidPowerSeriesModuleFunctor
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import NNMonoid, TrivialRepresentation, TrivialCharacterMonoid
            sage: mps = MonoidPowerSeriesModuleFunctor(ZZ, NNMonoid(False))(FreeModule(QQ, 1))
            sage: F = MonoidPowerSeriesSymmetrisationModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(ZZ, 1)))
            sage: emps = F(mps)
            sage: emps.representation() == TrivialRepresentation("1", FreeModule(QQ, 1))
            True
            sage: mps = MonoidPowerSeriesModuleFunctor(ZZ, NNMonoid(False))(FreeModule(ZZ, 1))
            sage: F = MonoidPowerSeriesSymmetrisationModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(QQ, 1)))
            sage: emps = F(mps)
            sage: emps.representation() == TrivialRepresentation("1", FreeModule(QQ, 1))
            True
        """
        if self.__O.monoid() != P.monoid() :
            raise ValueError( "Action has to be defined on the monoid associated to P." )
        
        PR = self.__R.from_module(P.coefficient_domain())
        
        if not self.__R.base_ring().has_coerce_map_from(PR.base_ring()) : 
            R = self.__R.base_extend( pushout(self.__R.base_ring(), PR.base_ring()) )
        else :
            R = self.__R
        
        from .monoidpowerseries_module import EquivariantMonoidPowerSeriesModule

        return EquivariantMonoidPowerSeriesModule( self.__O, self.__C, R )
    def fourier_ring(self):
        r"""
        The ring that Fourier expansions of all elements of this
        ring will be contained in.
        
        OUTPUT:
            An ambient of (equivariant) monoid power series.
        
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_ring import *
            sage: mps = MonoidPowerSeriesRing(ZZ, NNMonoid(False))
            sage: ger = GradedExpansionRing_class(None, Sequence([mps(1)]), PolynomialRing(QQ, 'a').ideal(0), DegreeGrading((1,)))
            sage: ger.fourier_ring()
            Ring of monoid power series over NN
            sage: ger = GradedExpansionRing_class(Sequence([MonoidPowerSeries(mps, {1 : 1}, mps.monoid().filter(2))]), Sequence([MonoidPowerSeries(mps, {1 : 1, 2 : 3}, mps.monoid().filter(4))]), PolynomialRing(ZZ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: ger.fourier_ring()
            Ring of monoid power series over NN
        """
        if self.__gen_expansions.universe().base_ring() == self.base_ring():
            return self.__gen_expansions.universe()
        else:
            from sage.categories.pushout import pushout

            if self.nbasegens() == 0:
                scalar_ring = self.base_ring()
            else:
                scalar_ring = self.base_ring().base_ring()

            return pushout(self.__gen_expansions.universe(), scalar_ring)
Пример #8
0
    def __call__(self, K):
        r"""
        Apply a ``self`` to a coefficient domain `A`.
        
        INPUT:
            - `A` -- A ring or module. The domain of coefficients for
                     a ring or module of equivariant monoid power series.
        
        OUTPUT:
            An instance of :class:`~from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ambient.EquivariantMonoidPowerSeriesAmbient_abstract`.
            A ring if the representation's extension by `A` is a ring, a module if this extension is a module.
            
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_functor import EquivariantMonoidPowerSeriesModuleFunctor
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import NNMonoid, TrivialRepresentation, TrivialCharacterMonoid
            sage: F = EquivariantMonoidPowerSeriesModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(ZZ, 1)))
            sage: emps = F(QQ)
            sage: emps.action() == NNMonoid()
            True
            sage: emps.characters()
            Character monoid over Trivial monoid
            sage: F = EquivariantMonoidPowerSeriesModuleFunctor(NNMonoid(), TrivialCharacterMonoid("1", ZZ), TrivialRepresentation("1", FreeModule(ZZ, 3)))
            sage: emps = F(QQ)
            sage: emps.coefficient_domain()
            Vector space of dimension 3 over Rational Field
            """
        if not self.__R.base_ring().has_coerce_map_from(K):
            R = self.__R.base_extend(pushout(self.__R.base_ring(), K))
        else:
            R = self.__R

        from monoidpowerseries_module import EquivariantMonoidPowerSeriesModule

        return EquivariantMonoidPowerSeriesModule(self.__O, self.__C, R)
Пример #9
0
    def scale(self,left):
        r"""
        Scales the moments of the distribution by `left`

        INPUT:

        - ``left`` -- scalar

        OUTPUT:

        - Scales the moments by `left`

        EXAMPLES::

            sage: from sage.modular.pollack_stevens.distributions import Distributions
            sage: D = Distributions(5, 7, 15)
            sage: v = D([1,2,3,4,5]); v
            (1 + O(7^5), 2 + O(7^4), 3 + O(7^3), 4 + O(7^2), 5 + O(7))
            sage: v.scale(2)
            (2 + O(7^5), 4 + O(7^4), 6 + O(7^3), 1 + 7 + O(7^2), 3 + O(7))
        """
        if isinstance(self, Dist_long) and isinstance(left, (Integer, pAdicCappedRelativeElement, pAdicCappedAbsoluteElement, pAdicFixedModElement)):
            return self._lmul_(left)
        R = left.parent()
        base = self.parent().base_ring()
        if base is R:
            return self._lmul_(left)
        elif base.has_coerce_map_from(R):
            return self._lmul_(base(left))
        else:
            from sage.categories.pushout import pushout
            new_base = pushout(base, R)
            V = self.parent().change_ring(new_base)
            scalar = new_base(left)
            return V([scalar * new_base(self.moment(i)) for i in range(self.precision_absolute())])
Пример #10
0
 def _element_constructor_(self, x) :
     """
     TESTS::
         sage: from psage.modform.fourier_expansion_framework.modularforms.modularform_ambient import *
         sage: from psage.modform.fourier_expansion_framework.modularforms.modularform_testtype import *
         sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
         sage: ma = ModularFormsAmbient( QQ, ModularFormTestType_scalar(), NNFilter(5) )
         sage: ma2 = ModularFormsAmbient( ZZ, ModularFormTestType_scalar(), NNFilter(5) )
         sage: ma(ma2.0)
         Graded expansion g1
     """
     if isinstance(x, Element) :
         P = x.parent()
         if isinstance(P, ModularFormsRing_generic) :
             try :
                 if self.type().is_vector_valued() and \
                    self.type().non_vector_values() == P.type() and \
                    self.base_ring().has_coerce_map_from(P.base_ring()) :
                     if self.base_ring() != P.base_ring() :
                         from sage.categories.pushout import pushout
                         x = pushout(P, self.base_ring())(x)
                     
                     return self._element_class( self,
                             self.relations().ring()( x.polynomial(). \
                              subs(self.type()._hom_to_vector_valued(self.base_ring())) )
                            )
             except NotImplementedError :
                 pass
             
     return ModularFormsAmbient_abstract._element_constructor_(self, x)
Пример #11
0
def mypushout(X, Y):
    if X.has_coerce_map_from(Y):
        return X
    elif Y.has_coerce_map_from(X):
        return Y
    else:
        Z = pushout(X, Y)
        assert (is_NumberField(Z) if is_NumberField(X) and is_NumberField(Y)
                                  else True)
        return Z
Пример #12
0
    def __call__(self, R):
        r"""
        The graded expansion ring with the given generators over the base
        ring `R`.
                
        INPUT:
            - `R` -- A ring.
        
        OUTPUT:
            An instance of :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_ambient.GradedExpansion_abstract`.
        
        NOTE:
            The ring of Fourier expansions given by the generators associated
            with this functor must admit a base extension to `R`.

        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *
            sage: K.<rho> = CyclotomicField(6)
            sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))
            sage: funct = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: funct(K)
            Graded expansion ring with generators b
            sage: m = FreeModule(QQ, 3)
            sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False))
            sage: mps = mpsm.base_ring()
            sage: funct = GradedExpansionFunctor(None, Sequence([MonoidPowerSeries(mpsm, {1 : m([1,2,3]), 2 : m([3,-3,2])}, mpsm.monoid().filter(4)), MonoidPowerSeries(mpsm, {1 : m([2,-1,-1]), 2 : m([1,0,0])}, mpsm.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: funct(K)
            Graded expansion module with generators a, b
        """
        from gradedexpansion_ring import GradedExpansionRing_class
        from gradedexpansion_module import GradedExpansionModule_class

        R = pushout(self.__relations.ring(), R)
        rel = R.ideal(self.__relations.gens())

        if isinstance(self.__gen_expansions.universe(), Algebra):
            return GradedExpansionRing_class(self.__base_gen_expansions,
                                             self.__gen_expansions, rel,
                                             self.__grading,
                                             self.__all_relations,
                                             self.__reduce_before_evaluating)
        elif isinstance(self.__gen_expansions.universe(), Module):
            return GradedExpansionModule_class(self.__base_gen_expansions,
                                               self.__gen_expansions, rel,
                                               self.__grading,
                                               self.__all_relations,
                                               self.__reduce_before_evaluating)

        raise RuntimeError(
            "The generators' universe must be an algebra or a module.")
Пример #13
0
def matrix_of_dMovement(M, v, D, cols):
    r'''
        Method to construct a matrix where the columns are iterative derivations of a vector.

        When we have a vector space `V` over a differential field `(F,D)`, we can define
        "derivations" over `V` as those maps `\partial: V \rightarrow V` such that for all `v, w \in V`
        and all `f \in F`:

        * `\partial(v+w) = \partial(v) + \partial(w)`.
        * `\partial(fv) = D(f)v + f\partial(v)`.

        It can be shown (see Appendix A of the thesis by the author of the file) that, fixed a basis,
        this derivation is uniquely determined by a matrix `M` in such a way that, for all `v \in V`,
        the derivation can be computed with a matrix-vector multiplication:

        .. MATH::

            \partial(v) = Mv + \kappa_D(v),

        where this `\kappa_D` is the terminwise derivation of the coordinates.

        This method computes several derivations of a particular vector and arrange the return as a matrix
        where these derivatives are in the columns of the matrix.

        INPUT:
            * ``M``: matrix defining the specific derivation for the fixed basis.
            * ``v``: starig vector which will be derivated several times.
            * ``D``: derivation over the ground field.
            * ``cols``: number of columns (i.e., derivations) that we will return.

        OUTPUT:
            A matrix `N=(n_{i,j})` where the columns are the derivations of `v`, i.e.,
            `(n_{0,j},n_{1,j},\ldots) = \partial^j(v)`.

        EXAMPLES::

            sage: from ajpastor.misc.matrix import *
            sage: M = vandermonde_matrix(QQ[x], [1,x,x^2]); v = vector(QQ[x], [1+x, 1, x^2])
            sage: D = lambda p : p.derivative(x)
            sage: matrix_of_dMovement(M, v, D, 3)
            [                                               x + 1                                          x^2 + x + 3                          x^6 + x^4 + 2*x^2 + 8*x + 6]
            [                                                   1                                        x^4 + 2*x + 1            x^8 + x^5 + x^4 + 7*x^3 + 4*x^2 + 2*x + 5]
            [                                                 x^2                                  x^6 + x^2 + 3*x + 1 x^10 + 2*x^6 + 9*x^5 + x^4 + 2*x^3 + 2*x^2 + 3*x + 6]

        We can check that the second column of that matrix is the derivative of the vector `v`::

            sage: [matrix_of_dMovement(M, v, D, 3)[i][1] for i in range(3)] == [el for el in vector_derivative(M, v, D)]
            True
    '''
    from sage.categories.pushout import pushout
    parent = pushout(M.parent().base(), v.parent().base())
    res = [v]
    for _ in range(1, cols):
        res += [vector_derivative(M, res[-1], D)]
    return Matrix(parent, res).transpose()
Пример #14
0
def EquivariantMonoidPowerSeriesRing(O, C, R):
    r"""
    Return the globally unique ring of equivariant monoid power
    over the monoid with action `O` with coefficients in the codomain `R`
    with a representation and a set of virtual characters `C`.
    
    INPUT:
        - `O` -- A monoid with an action of a group; As implemented in
                 :class:~`fourier_expansion_framework.monoidpowerseries.NNMonoid`.
        - `C` -- A monoid of characters; As implemented in ::class:~`fourier_expansion_framework.monoidpowerseries.CharacterMonoid_class`.
        - `R` -- A representation on an algebra; As implemented
                 in :class:~`fourier_expansion_framework.monoidpowerseries.TrivialRepresentation`.
        
    EXAMPLES::
        sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
        sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import EquivariantMonoidPowerSeriesRing
        sage: emps = EquivariantMonoidPowerSeriesRing(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ))
        sage: emps is EquivariantMonoidPowerSeriesRing(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ))
        True
    """

    ## TODO: Implement optional checking of the relations of the characters
    if O.group() != C.group():
        raise ValueError(
            "The action on S and the characters must have the same group")
    if R.base_ring() != C.codomain():
        if C.codomain().has_coerce_map_from(R.base_ring()):
            K = C.codomain()
            R = R.base_extend(K)
        elif R.base_ring().has_coerce_map_from(C.codomain()):
            K = R.base_ring()
        else:
            from sage.categories.pushout import pushout

            try:
                K = pushout(C.codomain(), R.base_ring())
                R = R.base_extend(K)
            except:
                raise ValueError(
                    "character codomain and representation base ring have no common extension"
                )

    global _equivariantmonoidpowerseries_ring_cache
    key = (O, C, R)

    try:
        return _equivariantmonoidpowerseries_ring_cache[key]
    except KeyError:
        P = EquivariantMonoidPowerSeriesRing_generic(O, C, R)
        _equivariantmonoidpowerseries_ring_cache[key] = P

        return P
def EquivariantMonoidPowerSeriesRing(O, C, R) :
    """
    Return the globally unique ring of equivariant monoid power
    over the monoid with action `O` with coefficients in the codomain `R`
    with a representation and a set of virtual characters `C`.
    
    INPUT:
        - `O` -- A monoid with an action of a group; As implemented in
                 :class:~`fourier_expansion_framework.monoidpowerseries.NNMonoid`.
        - `C` -- A monoid of characters; As implemented in ::class:~`fourier_expansion_framework.monoidpowerseries.CharacterMonoid_class`.
        - `R` -- A representation on an algebra; As implemented
                 in :class:~`fourier_expansion_framework.monoidpowerseries.TrivialRepresentation`.
        
    EXAMPLES::
        sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
        sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import EquivariantMonoidPowerSeriesRing
        sage: emps = EquivariantMonoidPowerSeriesRing(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ))
        sage: emps is EquivariantMonoidPowerSeriesRing(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ))
        True
    """

    ## TODO: Implement optional checking of the relations of the characters
    if O.group() != C.group() :
        raise ValueError, "The action on S and the characters must have the same group"
    if R.base_ring() != C.codomain() :
        if C.codomain().has_coerce_map_from(R.base_ring()) :
            K = C.codomain()
            R = R.base_extend(K)
        elif R.base_ring().has_coerce_map_from(C.codomain()) :
            K = R.base_ring()
        else :
            from sage.categories.pushout import pushout
            
            try :
                K = pushout(C.codomain(), R.base_ring())
                R = R.base_extend(K)
            except :
                raise ValueError, "character codomain and representation base ring have no common extension"
    
    global _equivariantmonoidpowerseries_ring_cache
    key = (O, C, R)
    
    try :
        return _equivariantmonoidpowerseries_ring_cache[key]
    except KeyError :
        P = EquivariantMonoidPowerSeriesRing_generic(O, C, R)
        _equivariantmonoidpowerseries_ring_cache[key] = P
        
        return P
Пример #16
0
    def _pushout_(self, R):
        """
        Return the pushout of this Tate algebra with ``R``.

        This is only implemented when ``R`` is a p-adic ring or
        a p-adic field.

        EXAMPLES::

            sage: from sage.categories.pushout import pushout
            sage: R = Zp(2)
            sage: R1.<a> = Zq(4)
            sage: R2.<pi> = R.extension(x^2 - 2)

            sage: A.<u,v> = TateAlgebra(R, log_radii=[1,2])
            sage: A1 = pushout(A, R1); A1
            Tate Algebra in u (val >= -1), v (val >= -2) over 2-adic Unramified Extension Field in a defined by x^2 + x + 1
            sage: A2 = pushout(A, R2); A2
            Tate Algebra in u (val >= -2), v (val >= -4) over 2-adic Eisenstein Extension Field in pi defined by x^2 - 2

            sage: Ao = A.integer_ring()
            sage: pushout(Ao, R1)
            Integer ring of the Tate Algebra in u (val >= -1), v (val >= -2) over 2-adic Unramified Extension Field in a defined by x^2 + x + 1
            sage: pushout(Ao, R2.fraction_field())
            Tate Algebra in u (val >= -2), v (val >= -4) over 2-adic Eisenstein Extension Field in pi defined by x^2 - 2

        TESTS::

            sage: a*u
            (a + O(2^20))*u
            sage: (a*u).parent() is A1
            True

            sage: pi*v
            (pi + O(pi^41))*v
            sage: (pi*v).parent() is A2
            True

        """
        if isinstance(R, pAdicGeneric):
            base = pushout(self._base, R)
            ratio = base.absolute_e() // self._base.absolute_e()
            cap = ratio * self._cap
            log_radii = [ratio * r for r in self._log_radii]
            A = TateAlgebra(base, cap, log_radii, self._names, self._order)
            if base.is_field():
                return A
            else:
                return A.integer_ring()
Пример #17
0
    def evaluate_at_poly(self, P, R=None, depth=None):
        r"""
        Evaluate ``self`` at a polynomial. The polynomial can be defined over ZZ or Zp.

        By default, this function picks the ring R to be a ring that coerces to both the 
        base ring of the polynomial and the Bianchi distribution.

        You can specify depth, but this currently does nothing at all.

        EXAMPLES::

            sage: from darmonpoints.ocbianchi import BianchiDistributions
            sage: D = BianchiDistributions(11,4)
            sage: x,y = D.analytic_vars()
            sage: mu = D.basis_vector((2,1)) + D.basis_vector((1,0))
            sage: mu(x^2*y)
            1
            sage: mu(y)
            0
            sage: mu(x^2*y + x)
            2
        """
        p = self._parent._p

        ## Currently empty functionality
        if depth is None:
            depth = self._depth

        # Define the ring R, if not specified
        if R is None:
            try:
                R = pushout(P.parent().base_ring(), self.parent().base_ring())
            except AttributeError:
                R = self.parent().base_ring()

        ## Attempt to coerce the input into a form we can evaluate
        P = self.parent().analytic_functions()(P)

        ## For each monomial x^iy^j in the polynomial, multip] ly the coefficient of X^iY^j (in mu) by the
        ## coefficient of x^iy^j (in f) and take the sum. This is our final value
        ##          --> P.coefficients is a dictionary which has monomials as keys; we generate monomials using exponents.
        ##         --> self._moments takes as input an index and spits out the cofficient. So generate the index from the exponent.

        coefficient_list = []
        for polx in P.padded_list(self._depth):
            coefficient_list.extend(polx.padded_list(self._depth))

        return ZZ((Matrix(coefficient_list) * self.moments())[0, 0])
def SiegelModularFormG2SatohBracket(f, g, f_weight=None, g_weight=None):
    r"""
    INPUT:
    
    - `f` -- Fourier expansion of a classical Siegel modular form.
    
    - `g` -- Fourier expansion of a classical Siegel modular form.
    
    - ``f_weight`` -- the weight of `f` (default: ``None``).
     
    - ``g_weight`` -- the weight of `g` (default: ``None``).
    
    OUTPUT:
    
    - The Fourier expansion of a vector-valued Siegel modular form.
    """
    if f_weight is None:
        f_weight = f.weight()
    if g_weight is None:
        g_weight = g.weight()

    if not isinstance(f.parent(),
                      EquivariantMonoidPowerSeriesAmbient_abstract):
        f = f.fourier_expansion()
    if not isinstance(g.parent(),
                      EquivariantMonoidPowerSeriesAmbient_abstract):
        g = g.fourier_expansion()

    if f.parent() != g.parent():
        if f.parent().has_coerce_map_from(g.parent()):
            g = f.parent()(g)
        elif g.parent().has_coerce_map_from(f.parent()):
            f = g.parent()(f)
        else:
            from sage.categories.pushout import pushout
            parent = pushout(f.parent(), g.parent())
            f = parent(f)
            g = parent(g)

    precision = min(f.precision(), g.precision())

    expansion_ring = SiegelModularFormG2VVFourierExpansionRing(
        f.parent().coefficient_domain().fraction_field())
    coefficients_factory = DelayedFactory_SMFG2_satohbracket(
        f, g, f_weight, g_weight, expansion_ring.coefficient_domain())

    return EquivariantMonoidPowerSeries_lazy(expansion_ring, precision,
                                             coefficients_factory.getcoeff)
Пример #19
0
    def __call__(self, R) :
        r"""
        The graded expansion ring with the given generators over the base
        ring `R`.
                
        INPUT:
            - `R` -- A ring.
        
        OUTPUT:
            An instance of :class:~`fourier_expansion_framework.gradedexpansions.gradedexpansion_ambient.GradedExpansion_abstract`.
        
        NOTE:
            The ring of Fourier expansions given by the generators associated
            with this functor must admit a base extension to `R`.

        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_module import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_element import *
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_grading import DegreeGrading
            sage: from psage.modform.fourier_expansion_framework.gradedexpansions.gradedexpansion_functor import *
            sage: K.<rho> = CyclotomicField(6)
            sage: mps = MonoidPowerSeriesRing(QQ, NNMonoid(False))
            sage: funct = GradedExpansionFunctor(Sequence([MonoidPowerSeries(mps, {1: 1}, mps.monoid().filter(4))]), Sequence([MonoidPowerSeries(mps, {1: 1, 2: 3}, mps.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: funct(K)
            Graded expansion ring with generators b
            sage: m = FreeModule(QQ, 3)
            sage: mpsm = MonoidPowerSeriesModule(m, NNMonoid(False))
            sage: mps = mpsm.base_ring()
            sage: funct = GradedExpansionFunctor(None, Sequence([MonoidPowerSeries(mpsm, {1 : m([1,2,3]), 2 : m([3,-3,2])}, mpsm.monoid().filter(4)), MonoidPowerSeries(mpsm, {1 : m([2,-1,-1]), 2 : m([1,0,0])}, mpsm.monoid().filter(4))]), PolynomialRing(QQ, ['a', 'b']).ideal(0), DegreeGrading((1,2)))
            sage: funct(K)
            Graded expansion module with generators a, b
        """
        from gradedexpansion_ring import GradedExpansionRing_class
        from gradedexpansion_module import GradedExpansionModule_class
        
        R = pushout(self.__relations.ring(), R)
        rel = R.ideal(self.__relations.gens())
        
        if isinstance(self.__gen_expansions.universe(), Algebra) :
            return GradedExpansionRing_class( self.__base_gen_expansions, self.__gen_expansions,
                                              rel, self.__grading, self.__all_relations, self.__reduce_before_evaluating )
        elif isinstance(self.__gen_expansions.universe(), Module) :
            return GradedExpansionModule_class( self.__base_gen_expansions, self.__gen_expansions,
                                                rel, self.__grading, self.__all_relations, self.__reduce_before_evaluating )

        raise RuntimeError( "The generators' universe must be an algebra or a module." )
def SiegelModularFormG2SatohBracket(f, g, f_weight = None, g_weight = None) :
    r"""
    INPUT:
    
    - `f` -- Fourier expansion of a classical Siegel modular form.
    
    - `g` -- Fourier expansion of a classical Siegel modular form.
    
    - ``f_weight`` -- the weight of `f` (default: ``None``).
     
    - ``g_weight`` -- the weight of `g` (default: ``None``).
    
    OUTPUT:
    
    - The Fourier expansion of a vector-valued Siegel modular form.
    """        
    if f_weight is None :
        f_weight = f.weight()
    if g_weight is None :
        g_weight = g.weight()
    
    if not isinstance(f.parent(), EquivariantMonoidPowerSeriesAmbient_abstract) :
        f = f.fourier_expansion()
    if not isinstance(g.parent(), EquivariantMonoidPowerSeriesAmbient_abstract) :
        g = g.fourier_expansion()
        
    if f.parent() != g.parent() :
        if f.parent().has_coerce_map_from(g.parent()) :
            g = f.parent()(g)
        elif g.parent().has_coerce_map_from(f.parent()) :
            f = g.parent()(f)
        else :
            from sage.categories.pushout import pushout
            parent = pushout(f.parent(), g.parent())
            f = parent(f)
            g = parent(g)
            
    precision = min(f.precision(), g.precision())
    
    expansion_ring = SiegelModularFormG2VVFourierExpansionRing(
                                            f.parent().coefficient_domain().fraction_field() )
    coefficients_factory = DelayedFactory_SMFG2_satohbracket(
                             f, g, f_weight, g_weight, expansion_ring.coefficient_domain() )

    return EquivariantMonoidPowerSeries_lazy( expansion_ring, precision,
                                              coefficients_factory.getcoeff )
Пример #21
0
def direct_sum(*matrices):
    r'''
        Method to compute the direct sum of several matrices.

        This method computes the direct sum of several matrices, i.e., it computes a diagonal
        matrix where the elements in the diagonal are the matrices that we have as input.

        This method is just a generic alias for the method :func:`diagonal_matrix`. However,
        it performs the checking of compatibility between the parents of the matrices.
    '''
    from sage.categories.pushout import pushout
    #Computation of a common parent
    try:
        R = reduce(lambda p, q: pushout(p, q),
                   [el.parent().base() for el in matrices])
    except AttributeError:
        raise TypeError("All the elements must be matrices")
    return diagonal_matrix(R, matrices)
Пример #22
0
 def evaluate_at_poly(self,P,R = None,depth = None):
     r"""
     Evaluate ``self`` at a polynomial
     """
     p = self._parent._p
     if R is None:
         try:
             R = pushout(P.parent().base_ring(),self.parent().base_ring())
         except AttributeError:
             R = self.parent().base_ring()
     if depth is None and hasattr(P,'degree'):
         try:
             depth = min([P.degree()+1,self._depth])
             return sum(R(self._val[ii,0])*P[ii] for ii in xrange(depth))
         except NotImplementedError: pass
         return R(self._val[0,0])*P
     else:
         return sum(R(self._val[ii,0])*P[ii] for ii in xrange(depth))
Пример #23
0
 def evaluate_at_poly(self, P, R=None, depth=None):
     r"""
     Evaluate ``self`` at a polynomial
     """
     p = self._parent._p
     if R is None:
         try:
             R = pushout(P.parent().base_ring(), self.parent().base_ring())
         except AttributeError:
             R = self.parent().base_ring()
     if depth is None and hasattr(P, 'degree'):
         try:
             depth = min([P.degree() + 1, self._depth])
             return sum(R(self._val[ii, 0]) * P[ii] for ii in xrange(depth))
         except NotImplementedError:
             pass
         return R(self._val[0, 0]) * P
     else:
         return sum(R(self._val[ii, 0]) * P[ii] for ii in xrange(depth))
Пример #24
0
    def shift(self, delta):
        r"""
        TESTS::

            sage: from ore_algebra import DifferentialOperators
            sage: from ore_algebra.analytic.path import Point
            sage: from ore_algebra.analytic.differential_operator import DifferentialOperator
            sage: Dops, x, Dx = DifferentialOperators()
            sage: DifferentialOperator(x*Dx - 1).shift(Point(1))
            (x + 1)*Dx - 1
            sage: dop = DifferentialOperator(x*Dx - 1)
            sage: dop.shift(Point(RBF(1/2), dop))
            (2*x + 1)*Dx - 2
        """
        Pols_dop = self.base_ring()
        # NOTE: pushout(QQ[x], K) doesn't handle embeddings well, and creates
        # an L equal but not identical to K. But then other constructors like
        # PolynomialRing(L, x) sometimes return objects over K found in cache,
        # leading to endless headaches with slow coercions. But the version here
        # may be closer to what I really want in any case.
        # XXX: This seems to work in the usual trivial case where we are looking
        # for a scalar domain containing QQ and QQ[i], but probably won't be
        # enough if we really have two different number fields with embeddings
        ex = delta.exact()
        Scalars = pushout.pushout(Pols_dop.base_ring(), ex.value.parent())
        Pols = Pols_dop.change_ring(Scalars)
        A, B = self.base_ring().base_ring(), ex.value.parent()
        C = Pols.base_ring()
        assert C is A or C != A
        assert C is B or C != B
        dop_P = self.change_ring(Pols)
        # Gcd-avoiding shift by an algebraic delta
        deg = dop_P.degree()
        den = ex.value.denominator()
        num = den*ex.value
        lin = Pols([num, den])
        x = Pols.gen()
        def shift_poly(pol):
            pol = (pol.reverse(deg)(den*x)).reverse(deg)
            return pol(lin)
        shifted = dop_P.map_coefficients(shift_poly)
        return ShiftedDifferentialOperator(shifted, self, delta)
Пример #25
0
    def evaluate_at_poly(self,P):
        r"""

        EXAMPLES:

        This example illustrates ...

        ::

        """
        p = self._parent._R.prime()
        try:
            R = pushout(P.parent().base_ring(),self.parent().base_ring())
        except AttributeError:
            R = self.parent().base_ring()

        if hasattr(P,'degree'):
            try:
                r = min([P.degree()+1,self._depth])
                return sum([R(self._val[ii,0])*P[ii] for ii in range(r)])
            except NotImplementedError: pass
        return R(self._val[0,0])*P
def log_series(ini, bwrec, order):
    Coeffs = pushout(bwrec.base_ring.base_ring(), ini.universe)
    log_prec = sum(len(v) for v in ini.shift.itervalues())
    precomp_len = max(1, bwrec.order)  # hack for recurrences of order zero
    bwrec_nplus = collections.deque(
        (bwrec.eval_series(Coeffs, i, log_prec) for i in xrange(precomp_len)),
        maxlen=precomp_len)
    series = []
    for n in xrange(order):
        new_term = vector(Coeffs, log_prec)
        mult = len(ini.shift.get(n, ()))
        for p in xrange(log_prec - mult - 1, -1, -1):
            combin = sum(bwrec_nplus[0][i][j] * series[-i][p + j]
                         for j in xrange(log_prec - p)
                         for i in xrange(min(bwrec.order, n), 0, -1))
            combin += sum(bwrec_nplus[0][0][j] * new_term[p + j]
                          for j in xrange(mult + 1, log_prec - p))
            new_term[mult + p] = -~bwrec_nplus[0][0][mult] * combin
        for p in xrange(mult - 1, -1, -1):
            new_term[p] = ini.shift[n][p]
        series.append(new_term)
        bwrec_nplus.append(bwrec.eval_series(Coeffs, n + precomp_len,
                                             log_prec))
    return series
Пример #27
0
    def _pushout_(self, other):
        r"""
        Construct the pushout of this and the other growth group. This is called by
        :func:`sage.categories.pushout.pushout`.

        TESTS::

            sage: from sage.rings.asymptotic.growth_group import GrowthGroup
            sage: from sage.categories.pushout import pushout
            sage: cm = sage.structure.element.get_coercion_model()
            sage: A = GrowthGroup('QQ^x * x^ZZ')
            sage: B = GrowthGroup('x^ZZ * log(x)^ZZ')
            sage: A._pushout_(B)
            Growth Group QQ^x * x^ZZ * log(x)^ZZ
            sage: pushout(A, B)
            Growth Group QQ^x * x^ZZ * log(x)^ZZ
            sage: cm.discover_coercion(A, B)
            ((map internal to coercion system -- copy before use)
             Conversion map:
               From: Growth Group QQ^x * x^ZZ
               To:   Growth Group QQ^x * x^ZZ * log(x)^ZZ,
             (map internal to coercion system -- copy before use)
             Conversion map:
               From: Growth Group x^ZZ * log(x)^ZZ
               To:   Growth Group QQ^x * x^ZZ * log(x)^ZZ)
            sage: cm.common_parent(A, B)
            Growth Group QQ^x * x^ZZ * log(x)^ZZ

        ::

            sage: C = GrowthGroup('QQ^x * x^QQ * y^ZZ')
            sage: D = GrowthGroup('x^ZZ * log(x)^QQ * QQ^z')
            sage: C._pushout_(D)
            Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z
            sage: cm.common_parent(C, D)
            Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z
            sage: A._pushout_(D)
            Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z
            sage: cm.common_parent(A, D)
            Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z
            sage: cm.common_parent(B, D)
            Growth Group x^ZZ * log(x)^QQ * QQ^z
            sage: cm.common_parent(A, C)
            Growth Group QQ^x * x^QQ * y^ZZ
            sage: E = GrowthGroup('log(x)^ZZ * y^ZZ')
            sage: cm.common_parent(A, E)
            Traceback (most recent call last):
            ...
            TypeError: no common canonical parent for objects with parents:
            'Growth Group QQ^x * x^ZZ' and 'Growth Group log(x)^ZZ * y^ZZ'

        ::

            sage: F = GrowthGroup('z^QQ')
            sage: pushout(C, F)
            Growth Group QQ^x * x^QQ * y^ZZ * z^QQ

        ::

            sage: pushout(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ'))
            Growth Group QQ^x * x^QQ
            sage: cm.common_parent(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ'))
            Growth Group QQ^x * x^QQ

        ::

            sage: pushout(GrowthGroup('QQ^n * n^QQ'), GrowthGroup('SR^n'))
            Growth Group SR^n * n^QQ
        """
        from growth_group import GenericGrowthGroup, AbstractGrowthGroupFunctor
        from misc import merge_overlapping
        from misc import underlying_class

        Sfactors = self.cartesian_factors()
        if isinstance(other, GenericProduct):
            Ofactors = other.cartesian_factors()
        elif isinstance(other, GenericGrowthGroup):
            Ofactors = (other, )
        elif (other.construction() is not None and isinstance(
                other.construction()[0], AbstractGrowthGroupFunctor)):
            Ofactors = (other, )
        else:
            return

        def pushout_univariate_factors(self, other, var, Sfactors, Ofactors):
            try:
                return merge_overlapping(
                    Sfactors, Ofactors, lambda f:
                    (underlying_class(f), f._var_.var_repr))
            except ValueError:
                pass

            cm = sage.structure.element.get_coercion_model()
            try:
                Z = cm.common_parent(*Sfactors + Ofactors)
                return (Z, ), (Z, )
            except TypeError:
                pass

            def subfactors(F):
                for f in F:
                    if isinstance(f, GenericProduct):
                        for g in subfactors(f.cartesian_factors()):
                            yield g
                    else:
                        yield f

            try:
                return merge_overlapping(
                    tuple(subfactors(Sfactors)), tuple(subfactors(Ofactors)),
                    lambda f: (underlying_class(f), f._var_.var_repr))
            except ValueError:
                pass

            from sage.structure.coerce_exceptions import CoercionException
            raise CoercionException(
                'Cannot construct the pushout of %s and %s: The factors '
                'with variables %s are not overlapping, '
                'no common parent was found, and '
                'splitting the factors was unsuccessful.' % (self, other, var))

        class it:
            def __init__(self, it):
                self.it = it
                self.var = None
                self.factors = None

            def next(self):
                try:
                    self.var, factors = next(self.it)
                    self.factors = tuple(factors)
                except StopIteration:
                    self.var = None
                    self.factors = tuple()

        from itertools import groupby
        S = it(groupby(Sfactors, key=lambda k: k.variable_names()))
        O = it(groupby(Ofactors, key=lambda k: k.variable_names()))

        newS = []
        newO = []

        S.next()
        O.next()
        while S.var is not None or O.var is not None:
            if S.var is not None and S.var < O.var:
                newS.extend(S.factors)
                newO.extend(S.factors)
                S.next()
            elif O.var is not None and S.var > O.var:
                newS.extend(O.factors)
                newO.extend(O.factors)
                O.next()
            else:
                SL, OL = pushout_univariate_factors(self, other, S.var,
                                                    S.factors, O.factors)
                newS.extend(SL)
                newO.extend(OL)
                S.next()
                O.next()

        assert (len(newS) == len(newO))

        if (len(Sfactors) == len(newS) and len(Ofactors) == len(newO)):
            # We had already all factors in each of self and
            # other, thus splitting it in subproblems (one for
            # each factor) is the strategy to use. If a pushout is
            # possible :func:`sage.categories.pushout.pushout`
            # will manage this by itself.
            return

        from sage.categories.pushout import pushout
        from sage.categories.cartesian_product import cartesian_product
        return pushout(cartesian_product(newS), cartesian_product(newO))
Пример #28
0
    def _tate(self, proof = None, globally = False):
        r"""
        Tate's algorithm for an elliptic curve over a number field.

        Computes both local reduction data at a prime ideal and a
        local minimal model.

        The model is not required to be integral on input.  If `P` is
        principal, uses a generator as uniformizer, so it will not
        affect integrality or minimality at other primes.  If `P` is not
        principal, the minimal model returned will preserve
        integrality at other primes, but not minimality.

        The optional argument globally, when set to True, tells the algorithm to use the generator of the prime ideal if it is principal. Otherwise just any uniformizer will be used.

        .. note:: 

           Called only by ``EllipticCurveLocalData.__init__()``.

        OUTPUT:

        (tuple) ``(Emin, p, val_disc, fp, KS, cp)`` where:

        - ``Emin`` (EllipticCurve) is a model (integral and) minimal at P
        - ``p`` (int) is the residue characteristic
        - ``val_disc`` (int) is the valuation of the local minimal discriminant
        - ``fp`` (int) is the valuation of the conductor
        - ``KS`` (string) is the Kodaira symbol
        - ``cp`` (int) is the Tamagawa number


        EXAMPLES (this raised a type error in sage prior to 4.4.4, see :trac:`7930`) ::

            sage: E = EllipticCurve('99d1')

            sage: R.<X> = QQ[]
            sage: K.<t> = NumberField(X^3 + X^2 - 2*X - 1)
            sage: L.<s> = NumberField(X^3 + X^2 - 36*X - 4)

            sage: EK = E.base_extend(K)
            sage: toK = EK.torsion_order()
            sage: da = EK.local_data()  # indirect doctest

            sage: EL = E.base_extend(L)
            sage: da = EL.local_data()  # indirect doctest

        EXAMPLES:

        The following example shows that the bug at :trac:`9324` is fixed::

            sage: K.<a> = NumberField(x^2-x+6)
            sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006])
            sage: E.conductor() # indirect doctest
            Fractional ideal (18, 6*a)

        The following example shows that the bug at :trac:`9417` is fixed::

            sage: K.<a> = NumberField(x^2+18*x+1)
            sage: E = EllipticCurve(K, [0, -36, 0, 320, 0])
            sage: E.tamagawa_number(K.ideal(2))
            4

        This is to show that the bug :trac:`11630` is fixed. (The computation of the class group would produce a warning)::
        
            sage: K.<t> = NumberField(x^7-2*x+177)
            sage: E = EllipticCurve([0,1,0,t,t])
            sage: P = K.ideal(2,t^3 + t + 1)
            sage: E.local_data(P).kodaira_symbol()
            II

        """
        E = self._curve
        P = self._prime
        K = E.base_ring()
        OK = K.maximal_order()
        t = verbose("Running Tate's algorithm with P = %s"%P, level=1)
        F = OK.residue_field(P)
        p = F.characteristic()

        # In case P is not principal we mostly use a uniformiser which
        # is globally integral (with positive valuation at some other
        # primes); for this to work, it is essential that we can
        # reduce (mod P) elements of K which are not integral (but are
        # P-integral).  However, if the model is non-minimal and we
        # end up dividing a_i by pi^i then at that point we use a
        # uniformiser pi which has non-positive valuation at all other
        # primes, so that we can divide by it without losing
        # integrality at other primes.
           
        if globally:
            principal_flag = P.is_principal()
        else: 
            principal_flag = False
            
        if (K is QQ) or principal_flag :
            pi = P.gens_reduced()[0]
            verbose("P is principal, generator pi = %s"%pi, t, 1)
        else:
            pi = K.uniformizer(P, 'positive')
            verbose("uniformizer pi = %s"%pi, t, 1)
        pi2 = pi*pi; pi3 = pi*pi2; pi4 = pi*pi3
        pi_neg = None
        prime = pi if K is QQ else P

        pval = lambda x: x.valuation(prime)
        pdiv = lambda x: x.is_zero() or pval(x) > 0
        # Since ResidueField is cached in a way that
        # does not care much about embeddings of number
        # fields, it can happen that F.p.ring() is different
        # from K. This is a problem: If F.p.ring() has no
        # embedding but K has, then there is no coercion
        # from F.p.ring().maximal_order() to K. But it is
        # no problem to do an explicit conversion in that
        # case (Simon King, trac ticket #8800).

        from sage.categories.pushout import pushout, CoercionException
        try:
            if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ
                _tmp_ = pushout(F.p.ring().maximal_order(),K)
            pinv = lambda x: F.lift(~F(x))
            proot = lambda x,e: F.lift(F(x).nth_root(e, extend = False, all = True)[0])
            preduce = lambda x: F.lift(F(x))
        except CoercionException: # the pushout does not exist, we need conversion
            pinv = lambda x: K(F.lift(~F(x)))
            proot = lambda x,e: K(F.lift(F(x).nth_root(e, extend = False, all = True)[0]))
            preduce = lambda x: K(F.lift(F(x)))

        def _pquadroots(a, b, c):
            r"""
            Local function returning True iff `ax^2 + bx + c` has roots modulo `P`
            """
            (a, b, c) = (F(a), F(b), F(c))
            if a == 0:
                return (b != 0) or (c == 0)
            elif p == 2:
                return len(PolynomialRing(F, "x")([c,b,a]).roots()) > 0
            else:
                return (b**2 - 4*a*c).is_square()
        def _pcubicroots(b, c, d):
            r"""
            Local function returning the number of roots of `x^3 +
            b*x^2 + c*x + d` modulo `P`, counting multiplicities
            """

            return sum([rr[1] for rr in PolynomialRing(F, 'x')([F(d), F(c), F(b), F(1)]).roots()],0)

        if p == 2:
            halfmodp = OK(Integer(0))
        else:
            halfmodp = pinv(Integer(2))

        A = E.a_invariants()
        A = [0, A[0], A[1], A[2], A[3], 0, A[4]]
        indices = [1,2,3,4,6]
        if min([pval(a) for a in A if a != 0]) < 0:
            verbose("Non-integral model at P: valuations are %s; making integral"%([pval(a) for a in A if a != 0]), t, 1)
            e = 0
            for i in range(7):
                if A[i] != 0:
                    e = max(e, (-pval(A[i])/i).ceil())
            pie = pi**e
            for i in range(7):
                if A[i] != 0:
                    A[i] *= pie**i
            verbose("P-integral model is %s, with valuations %s"%([A[i] for i in indices], [pval(A[i]) for i in indices]), t, 1)

        split = None # only relevant for multiplicative reduction

        (a1, a2, a3, a4, a6) = (A[1], A[2], A[3], A[4], A[6])
        while True:
            C = EllipticCurve([a1, a2, a3, a4, a6]);
            (b2, b4, b6, b8) = C.b_invariants()
            (c4, c6) = C.c_invariants()
            delta = C.discriminant()
            val_disc = pval(delta)

            if val_disc == 0:
                ## Good reduction already
                cp = 1
                fp = 0
                KS = KodairaSymbol("I0")
                break #return

            # Otherwise, we change coordinates so that p | a3, a4, a6
            if p == 2:
                if pdiv(b2):
                    r = proot(a4, 2)
                    t = proot(((r + a2)*r + a4)*r + a6, 2)
                else:
                    temp = pinv(a1)
                    r = temp * a3
                    t = temp * (a4 + r*r)
            elif p == 3:
                if pdiv(b2):
                    r = proot(-b6, 3)
                else:
                    r = -pinv(b2) * b4
                t = a1 * r + a3
            else:
                if pdiv(c4):
                    r = -pinv(12) * b2
                else:
                    r = -pinv(12*c4) * (c6 + b2 * c4)
                t = -halfmodp * (a1 * r + a3)
            r = preduce(r)
            t = preduce(t)
            verbose("Before first transform C = %s"%C)
            verbose("[a1,a2,a3,a4,a6] = %s"%([a1, a2, a3, a4, a6]))
            C = C.rst_transform(r, 0, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            if min([pval(a) for a in (a1, a2, a3, a4, a6) if a != 0]) < 0:
                raise RuntimeError("Non-integral model after first transform!")
            verbose("After first transform %s\n, [a1,a2,a3,a4,a6] = %s\n, valuations = %s"%([r, 0, t], [a1, a2, a3, a4, a6], [pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)]), t, 2)
            if pval(a3) == 0:
                raise RuntimeError("p does not divide a3 after first transform!")
            if pval(a4) == 0:
                raise RuntimeError("p does not divide a4 after first transform!")
            if pval(a6) == 0:
                raise RuntimeError("p does not divide a6 after first transform!")

            # Now we test for Types In, II, III, IV
            # NB the c invariants never change.

            if not pdiv(c4):
                # Multiplicative reduction: Type In (n = val_disc)
                split = False
                if _pquadroots(1, a1, -a2):
                    cp = val_disc
                    split = True
                elif Integer(2).divides(val_disc):
                    cp = 2
                else:
                    cp = 1
                KS = KodairaSymbol("I%s"%val_disc)
                fp = 1
                break #return

            # Additive reduction

            if pval(a6) < 2:
                ## Type II
                KS = KodairaSymbol("II")
                fp = val_disc
                cp = 1
                break #return
            if pval(b8) < 3:
                ## Type III
                KS = KodairaSymbol("III")
                fp = val_disc - 1
                cp = 2
                break #return
            if pval(b6) < 3:
                ## Type IV
                cp = 1
                a3t = preduce(a3/pi)
                a6t = preduce(a6/pi2)
                if _pquadroots(1, a3t, -a6t): cp = 3
                KS = KodairaSymbol("IV")
                fp = val_disc - 2
                break #return

            # If our curve is none of these types, we change coords so that
            # p | a1, a2;  p^2 | a3, a4;  p^3 | a6
            if p == 2:
                s = proot(a2, 2)        # so s^2=a2 (mod pi)
                t = pi*proot(a6/pi2, 2) # so t^2=a6 (mod pi^3)
            elif p == 3:
                s = a1       # so a1'=2s+a1=3a1=0 (mod pi)
                t = a3       # so a3'=2t+a3=3a3=0 (mod pi^2)
            else:
                s = -a1*halfmodp   # so a1'=2s+a1=0 (mod pi)
                t = -a3*halfmodp   # so a3'=2t+a3=0 (mod pi^2)
            C = C.rst_transform(0, s, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            verbose("After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s"%([0, s, t], [a1,a2,a3,a4,a6],[pval(a1),pval(a2),pval(a3),pval(a4),pval(a6)]), t, 2)
            if pval(a1) == 0:
                raise RuntimeError("p does not divide a1 after second transform!")
            if pval(a2) == 0:
                raise RuntimeError("p does not divide a2 after second transform!")
            if pval(a3) < 2:
                raise RuntimeError("p^2 does not divide a3 after second transform!")
            if pval(a4) < 2:
                raise RuntimeError("p^2 does not divide a4 after second transform!")
            if pval(a6) < 3:
                raise RuntimeError("p^3 does not divide a6 after second transform!")
            if min(pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)) < 0:
                raise RuntimeError("Non-integral model after second transform!")

            # Analyze roots of the cubic T^3 + bT^2 + cT + d = 0 mod P, where
            # b = a2/p, c = a4/p^2, d = a6/p^3
            b = preduce(a2/pi)
            c = preduce(a4/pi2)
            d = preduce(a6/pi3)
            bb = b*b
            cc = c*c
            bc = b*c
            w = 27*d*d - bb*cc + 4*b*bb*d - 18*bc*d + 4*c*cc
            x = 3*c - bb
            if pdiv(w):
                if pdiv(x):
                    sw = 3
                else:
                    sw = 2
            else:
                sw = 1
            verbose("Analyzing roots of cubic T^3 + %s*T^2 + %s*T + %s, case %s"%(b, c, d, sw), t, 1)
            if sw == 1:
                ## Three distinct roots - Type I*0
                verbose("Distinct roots", t, 1)
                KS = KodairaSymbol("I0*")
                cp = 1 + _pcubicroots(b, c, d)
                fp = val_disc - 4
                break #return
            elif sw == 2:
                ## One double root - Type I*m for some m
                verbose("One double root", t, 1)
                ## Change coords so that the double root is T = 0 mod p
                if p == 2:
                    r = proot(c, 2)
                elif p == 3:
                    r = c * pinv(b)
                else:
                    r = (bc - 9*d)*pinv(2*x)
                r = pi * preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # The rest of this branch is just to compute cp, fp, KS.
                # We use pi to keep transforms integral.
                ix = 3; iy = 3; mx = pi2; my = mx
                while True:
                    a2t = preduce(a2 / pi)
                    a3t = preduce(a3 / my)
                    a4t = preduce(a4 / (pi*mx))
                    a6t = preduce(a6 / (mx*my))
                    if pdiv(a3t*a3t + 4*a6t):
                        if p == 2:
                            t = my*proot(a6t, 2)
                        else:
                            t = my*preduce(-a3t*halfmodp)
                        C = C.rst_transform(0, 0, t)
                        (a1, a2, a3, a4, a6) = C.a_invariants()
                        (b2, b4, b6, b8) = C.b_invariants()
                        my *= pi
                        iy += 1
                        a2t = preduce(a2 / pi)
                        a3t = preduce(a3/my)
                        a4t = preduce(a4/(pi*mx))
                        a6t = preduce(a6/(mx*my))
                        if pdiv(a4t*a4t - 4*a6t*a2t):
                            if p == 2:
                                r = mx*proot(a6t*pinv(a2t), 2)
                            else:
                                r = mx*preduce(-a4t*pinv(2*a2t))
                            C = C.rst_transform(r, 0, 0)
                            (a1, a2, a3, a4, a6) = C.a_invariants()
                            (b2, b4, b6, b8) = C.b_invariants()
                            mx *= pi
                            ix += 1 # and stay in loop
                        else:
                            if _pquadroots(a2t, a4t, a6t):
                                cp = 4
                            else:
                                cp = 2
                            break # exit loop
                    else:
                        if _pquadroots(1, a3t, -a6t):
                            cp = 4
                        else:
                            cp = 2
                        break
                KS = KodairaSymbol("I%s*"%(ix+iy-5))
                fp = val_disc - ix - iy + 1
                break #return
            else: # sw == 3
                ## The cubic has a triple root
                verbose("Triple root", t, 1)
                ## First we change coordinates so that T = 0 mod p
                if p == 2:
                    r = b
                elif p == 3:
                    r = proot(-d, 3)
                else:
                    r = -b * pinv(3)
                r = pi*preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                verbose("After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s"%([r,0,0],[a1,a2,a3,a4,a6],[pval(ai) for ai in [a1,a2,a3,a4,a6]]), t, 2)
                if min(pval(ai) for ai in [a1,a2,a3,a4,a6]) < 0:
                    raise RuntimeError("Non-integral model after third transform!")
                if pval(a2) < 2 or pval(a4) < 3 or pval(a6) < 4:
                    raise RuntimeError("Cubic after transform does not have a triple root at 0")
                a3t = preduce(a3/pi2)
                a6t = preduce(a6/pi4)
                # We test for Type IV*
                if not pdiv(a3t*a3t + 4*a6t):
                    cp = 3 if _pquadroots(1, a3t, -a6t) else 1
                    KS = KodairaSymbol("IV*")
                    fp = val_disc - 6
                    break #return
                # Now change coordinates so that p^3|a3, p^5|a6
                if p==2:
                    t = -pi2*proot(a6t, 2)
                else:
                    t = pi2*preduce(-a3t*halfmodp)
                C = C.rst_transform(0, 0, t)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # We test for types III* and II*
                if pval(a4) < 4:
                    ## Type III*
                    KS = KodairaSymbol("III*")
                    fp = val_disc - 7
                    cp = 2
                    break #return
                if pval(a6) < 6:
                    ## Type II*
                    KS = KodairaSymbol("II*")
                    fp = val_disc - 8
                    cp = 1
                    break #return
                if pi_neg is None:
                    if principal_flag:
                        pi_neg = pi
                    else:
                        pi_neg = K.uniformizer(P, 'negative')
                    pi_neg2 = pi_neg*pi_neg
                    pi_neg3 = pi_neg*pi_neg2
                    pi_neg4 = pi_neg*pi_neg3
                    pi_neg6 = pi_neg4*pi_neg2
                a1 /= pi_neg
                a2 /= pi_neg2
                a3 /= pi_neg3
                a4 /= pi_neg4
                a6 /= pi_neg6
                verbose("Non-minimal equation, dividing out...\nNew model is %s"%([a1, a2, a3, a4, a6]), t, 1)
        return (C, p, val_disc, fp, KS, cp, split)
Пример #29
0
    def _pushout_(self, other):
        r"""
        Construct the pushout of this and the other growth group. This is called by
        :func:`sage.categories.pushout.pushout`.

        TESTS::

            sage: from sage.rings.asymptotic.growth_group import GrowthGroup
            sage: from sage.categories.pushout import pushout
            sage: cm = sage.structure.element.get_coercion_model()
            sage: A = GrowthGroup('QQ^x * x^ZZ')
            sage: B = GrowthGroup('x^ZZ * log(x)^ZZ')
            sage: A._pushout_(B)
            Growth Group QQ^x * x^ZZ * log(x)^ZZ
            sage: pushout(A, B)
            Growth Group QQ^x * x^ZZ * log(x)^ZZ
            sage: cm.discover_coercion(A, B)
            ((map internal to coercion system -- copy before use)
             Conversion map:
               From: Growth Group QQ^x * x^ZZ
               To:   Growth Group QQ^x * x^ZZ * log(x)^ZZ,
             (map internal to coercion system -- copy before use)
             Conversion map:
               From: Growth Group x^ZZ * log(x)^ZZ
               To:   Growth Group QQ^x * x^ZZ * log(x)^ZZ)
            sage: cm.common_parent(A, B)
            Growth Group QQ^x * x^ZZ * log(x)^ZZ

        ::

            sage: C = GrowthGroup('QQ^x * x^QQ * y^ZZ')
            sage: D = GrowthGroup('x^ZZ * log(x)^QQ * QQ^z')
            sage: C._pushout_(D)
            Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z
            sage: cm.common_parent(C, D)
            Growth Group QQ^x * x^QQ * log(x)^QQ * y^ZZ * QQ^z
            sage: A._pushout_(D)
            Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z
            sage: cm.common_parent(A, D)
            Growth Group QQ^x * x^ZZ * log(x)^QQ * QQ^z
            sage: cm.common_parent(B, D)
            Growth Group x^ZZ * log(x)^QQ * QQ^z
            sage: cm.common_parent(A, C)
            Growth Group QQ^x * x^QQ * y^ZZ
            sage: E = GrowthGroup('log(x)^ZZ * y^ZZ')
            sage: cm.common_parent(A, E)
            Traceback (most recent call last):
            ...
            TypeError: no common canonical parent for objects with parents:
            'Growth Group QQ^x * x^ZZ' and 'Growth Group log(x)^ZZ * y^ZZ'

        ::

            sage: F = GrowthGroup('z^QQ')
            sage: pushout(C, F)
            Growth Group QQ^x * x^QQ * y^ZZ * z^QQ

        ::

            sage: pushout(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ'))
            Growth Group QQ^x * x^QQ
            sage: cm.common_parent(GrowthGroup('QQ^x * x^ZZ'), GrowthGroup('ZZ^x * x^QQ'))
            Growth Group QQ^x * x^QQ
        """
        from growth_group import GenericGrowthGroup, AbstractGrowthGroupFunctor
        from misc import merge_overlapping
        from misc import underlying_class

        if isinstance(other, GenericProduct):
            Ofactors = other.cartesian_factors()
        elif isinstance(other, GenericGrowthGroup):
            Ofactors = (other,)
        elif other.construction() is not None and isinstance(other.construction()[0], AbstractGrowthGroupFunctor):
            Ofactors = (other,)
        else:
            return

        def pushout_univariate_factors(self, other, var, Sfactors, Ofactors):
            try:
                return merge_overlapping(Sfactors, Ofactors, lambda f: (underlying_class(f), f._var_.var_repr))
            except ValueError:
                pass

            cm = sage.structure.element.get_coercion_model()
            try:
                Z = cm.common_parent(*Sfactors + Ofactors)
                return (Z,), (Z,)
            except TypeError:
                pass

            def subfactors(F):
                for f in F:
                    if isinstance(f, GenericProduct):
                        for g in subfactors(f.cartesian_factors()):
                            yield g
                    else:
                        yield f

            try:
                return merge_overlapping(
                    tuple(subfactors(Sfactors)),
                    tuple(subfactors(Ofactors)),
                    lambda f: (underlying_class(f), f._var_.var_repr),
                )
            except ValueError:
                pass

            from sage.structure.coerce_exceptions import CoercionException

            raise CoercionException(
                "Cannot construct the pushout of %s and %s: The factors "
                "with variables %s are not overlapping, "
                "no common parent was found, and "
                "splitting the factors was unsuccessful." % (self, other, var)
            )

        class it:
            def __init__(self, it):
                self.it = it
                self.var = None
                self.factors = None

            def next(self):
                try:
                    self.var, factors = next(self.it)
                    self.factors = tuple(factors)
                except StopIteration:
                    self.var = None
                    self.factors = tuple()

        from itertools import groupby

        S = it(groupby(self.cartesian_factors(), key=lambda k: k.variable_names()))
        O = it(groupby(Ofactors, key=lambda k: k.variable_names()))

        newS = []
        newO = []

        S.next()
        O.next()
        while S.var is not None or O.var is not None:
            if S.var is not None and S.var < O.var:
                newS.extend(S.factors)
                newO.extend(S.factors)
                S.next()
            elif O.var is not None and S.var > O.var:
                newS.extend(O.factors)
                newO.extend(O.factors)
                O.next()
            else:
                SL, OL = pushout_univariate_factors(self, other, S.var, S.factors, O.factors)
                newS.extend(SL)
                newO.extend(OL)
                S.next()
                O.next()

        assert len(newS) == len(newO)

        if len(self.cartesian_factors()) == len(newS) and len(other.cartesian_factors()) == len(newO):
            # We had already all factors in each of the self and
            # other, thus splitting it in subproblems (one for
            # each factor) is the strategy to use. If a pushout is
            # possible :func:`sage.categories.pushout.pushout`
            # will manage this by itself.
            return

        from sage.categories.pushout import pushout
        from sage.categories.cartesian_product import cartesian_product

        return pushout(cartesian_product(newS), cartesian_product(newO))
Пример #30
0
    def _tate(self, proof = None, globally = False):
        r"""
        Tate's algorithm for an elliptic curve over a number field.

        Computes both local reduction data at a prime ideal and a
        local minimal model.

        The model is not required to be integral on input.  If `P` is
        principal, uses a generator as uniformizer, so it will not
        affect integrality or minimality at other primes.  If `P` is not
        principal, the minimal model returned will preserve
        integrality at other primes, but not minimality.

        The optional argument globally, when set to True, tells the algorithm to use the generator of the prime ideal if it is principal. Otherwise just any uniformizer will be used.

        .. note:: 

           Called only by ``EllipticCurveLocalData.__init__()``.

        OUTPUT:

        (tuple) ``(Emin, p, val_disc, fp, KS, cp)`` where:

        - ``Emin`` (EllipticCurve) is a model (integral and) minimal at P
        - ``p`` (int) is the residue characteristic
        - ``val_disc`` (int) is the valuation of the local minimal discriminant
        - ``fp`` (int) is the valuation of the conductor
        - ``KS`` (string) is the Kodaira symbol
        - ``cp`` (int) is the Tamagawa number


        EXAMPLES (this raised a type error in sage prior to 4.4.4, see :trac:`7930`) ::

            sage: E = EllipticCurve('99d1')

            sage: R.<X> = QQ[]
            sage: K.<t> = NumberField(X^3 + X^2 - 2*X - 1)
            sage: L.<s> = NumberField(X^3 + X^2 - 36*X - 4)

            sage: EK = E.base_extend(K)
            sage: toK = EK.torsion_order()
            sage: da = EK.local_data()  # indirect doctest

            sage: EL = E.base_extend(L)
            sage: da = EL.local_data()  # indirect doctest

        EXAMPLES:

        The following example shows that the bug at :trac:`9324` is fixed::

            sage: K.<a> = NumberField(x^2-x+6)
            sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006])
            sage: E.conductor() # indirect doctest
            Fractional ideal (18, 6*a)

        The following example shows that the bug at :trac:`9417` is fixed::

            sage: K.<a> = NumberField(x^2+18*x+1)
            sage: E = EllipticCurve(K, [0, -36, 0, 320, 0])
            sage: E.tamagawa_number(K.ideal(2))
            4

        This is to show that the bug :trac: `11630` is fixed. (The computation of the class group would produce a warning)::
        
            sage: K.<t> = NumberField(x^7-2*x+177)
            sage: E = EllipticCurve([0,1,0,t,t])
            sage: P = K.ideal(2,t^3 + t + 1)
            sage: E.local_data(P).kodaira_symbol()
            II

        """
        E = self._curve
        P = self._prime
        K = E.base_ring()
        OK = K.maximal_order()
        t = verbose("Running Tate's algorithm with P = %s"%P, level=1)
        F = OK.residue_field(P)
        p = F.characteristic()

        # In case P is not principal we mostly use a uniformiser which
        # is globally integral (with positive valuation at some other
        # primes); for this to work, it is essential that we can
        # reduce (mod P) elements of K which are not integral (but are
        # P-integral).  However, if the model is non-minimal and we
        # end up dividing a_i by pi^i then at that point we use a
        # uniformiser pi which has non-positive valuation at all other
        # primes, so that we can divide by it without losing
        # integrality at other primes.
           
        if globally:
            principal_flag = P.is_principal()
        else: 
            principal_flag = False
            
        if (K is QQ) or principal_flag :
            pi = P.gens_reduced()[0]
            verbose("P is principal, generator pi = %s"%pi, t, 1)
        else:
            pi = K.uniformizer(P, 'positive')
            verbose("uniformizer pi = %s"%pi, t, 1)
        pi2 = pi*pi; pi3 = pi*pi2; pi4 = pi*pi3
        pi_neg = None
        prime = pi if K is QQ else P

        pval = lambda x: x.valuation(prime)
        pdiv = lambda x: x.is_zero() or pval(x) > 0
        # Since ResidueField is cached in a way that
        # does not care much about embeddings of number
        # fields, it can happen that F.p.ring() is different
        # from K. This is a problem: If F.p.ring() has no
        # embedding but K has, then there is no coercion
        # from F.p.ring().maximal_order() to K. But it is
        # no problem to do an explicit conversion in that
        # case (Simon King, trac ticket #8800).

        from sage.categories.pushout import pushout, CoercionException
        try:
            if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ
                _tmp_ = pushout(F.p.ring().maximal_order(),K)
            pinv = lambda x: F.lift(~F(x))
            proot = lambda x,e: F.lift(F(x).nth_root(e, extend = False, all = True)[0])
            preduce = lambda x: F.lift(F(x))
        except CoercionException: # the pushout does not exist, we need conversion
            pinv = lambda x: K(F.lift(~F(x)))
            proot = lambda x,e: K(F.lift(F(x).nth_root(e, extend = False, all = True)[0]))
            preduce = lambda x: K(F.lift(F(x)))

        def _pquadroots(a, b, c):
            r"""
            Local function returning True iff `ax^2 + bx + c` has roots modulo `P`
            """
            (a, b, c) = (F(a), F(b), F(c))
            if a == 0:
                return (b != 0) or (c == 0)
            elif p == 2:
                return len(PolynomialRing(F, "x")([c,b,a]).roots()) > 0
            else:
                return (b**2 - 4*a*c).is_square()
        def _pcubicroots(b, c, d):
            r"""
            Local function returning the number of roots of `x^3 +
            b*x^2 + c*x + d` modulo `P`, counting multiplicities
            """

            return sum([rr[1] for rr in PolynomialRing(F, 'x')([F(d), F(c), F(b), F(1)]).roots()],0)

        if p == 2:
            halfmodp = OK(Integer(0))
        else:
            halfmodp = pinv(Integer(2))

        A = E.a_invariants()
        A = [0, A[0], A[1], A[2], A[3], 0, A[4]]
        indices = [1,2,3,4,6]
        if min([pval(a) for a in A if a != 0]) < 0:
            verbose("Non-integral model at P: valuations are %s; making integral"%([pval(a) for a in A if a != 0]), t, 1)
            e = 0
            for i in range(7):
                if A[i] != 0:
                    e = max(e, (-pval(A[i])/i).ceil())
            pie = pi**e
            for i in range(7):
                if A[i] != 0:
                    A[i] *= pie**i
            verbose("P-integral model is %s, with valuations %s"%([A[i] for i in indices], [pval(A[i]) for i in indices]), t, 1)

        split = None # only relevant for multiplicative reduction

        (a1, a2, a3, a4, a6) = (A[1], A[2], A[3], A[4], A[6])
        while True:
            C = EllipticCurve([a1, a2, a3, a4, a6]);
            (b2, b4, b6, b8) = C.b_invariants()
            (c4, c6) = C.c_invariants()
            delta = C.discriminant()
            val_disc = pval(delta)

            if val_disc == 0:
                ## Good reduction already
                cp = 1
                fp = 0
                KS = KodairaSymbol("I0")
                break #return

            # Otherwise, we change coordinates so that p | a3, a4, a6
            if p == 2:
                if pdiv(b2):
                    r = proot(a4, 2)
                    t = proot(((r + a2)*r + a4)*r + a6, 2)
                else:
                    temp = pinv(a1)
                    r = temp * a3
                    t = temp * (a4 + r*r)
            elif p == 3:
                if pdiv(b2):
                    r = proot(-b6, 3)
                else:
                    r = -pinv(b2) * b4
                t = a1 * r + a3
            else:
                if pdiv(c4):
                    r = -pinv(12) * b2
                else:
                    r = -pinv(12*c4) * (c6 + b2 * c4)
                t = -halfmodp * (a1 * r + a3)
            r = preduce(r)
            t = preduce(t)
            verbose("Before first transform C = %s"%C)
            verbose("[a1,a2,a3,a4,a6] = %s"%([a1, a2, a3, a4, a6]))
            C = C.rst_transform(r, 0, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            if min([pval(a) for a in (a1, a2, a3, a4, a6) if a != 0]) < 0:
                raise RuntimeError("Non-integral model after first transform!")
            verbose("After first transform %s\n, [a1,a2,a3,a4,a6] = %s\n, valuations = %s"%([r, 0, t], [a1, a2, a3, a4, a6], [pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)]), t, 2)
            if pval(a3) == 0:
                raise RuntimeError("p does not divide a3 after first transform!")
            if pval(a4) == 0:
                raise RuntimeError("p does not divide a4 after first transform!")
            if pval(a6) == 0:
                raise RuntimeError("p does not divide a6 after first transform!")

            # Now we test for Types In, II, III, IV
            # NB the c invariants never change.

            if not pdiv(c4):
                # Multiplicative reduction: Type In (n = val_disc)
                split = False
                if _pquadroots(1, a1, -a2):
                    cp = val_disc
                    split = True
                elif Integer(2).divides(val_disc):
                    cp = 2
                else:
                    cp = 1
                KS = KodairaSymbol("I%s"%val_disc)
                fp = 1
                break #return

            # Additive reduction

            if pval(a6) < 2:
                ## Type II
                KS = KodairaSymbol("II")
                fp = val_disc
                cp = 1
                break #return
            if pval(b8) < 3:
                ## Type III
                KS = KodairaSymbol("III")
                fp = val_disc - 1
                cp = 2
                break #return
            if pval(b6) < 3:
                ## Type IV
                cp = 1
                a3t = preduce(a3/pi)
                a6t = preduce(a6/pi2)
                if _pquadroots(1, a3t, -a6t): cp = 3
                KS = KodairaSymbol("IV")
                fp = val_disc - 2
                break #return

            # If our curve is none of these types, we change coords so that
            # p | a1, a2;  p^2 | a3, a4;  p^3 | a6
            if p == 2:
                s = proot(a2, 2)        # so s^2=a2 (mod pi)
                t = pi*proot(a6/pi2, 2) # so t^2=a6 (mod pi^3)
            elif p == 3:
                s = a1       # so a1'=2s+a1=3a1=0 (mod pi)
                t = a3       # so a3'=2t+a3=3a3=0 (mod pi^2)
            else:
                s = -a1*halfmodp   # so a1'=2s+a1=0 (mod pi)
                t = -a3*halfmodp   # so a3'=2t+a3=0 (mod pi^2)
            C = C.rst_transform(0, s, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            verbose("After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s"%([0, s, t], [a1,a2,a3,a4,a6],[pval(a1),pval(a2),pval(a3),pval(a4),pval(a6)]), t, 2)
            if pval(a1) == 0:
                raise RuntimeError("p does not divide a1 after second transform!")
            if pval(a2) == 0:
                raise RuntimeError("p does not divide a2 after second transform!")
            if pval(a3) < 2:
                raise RuntimeError("p^2 does not divide a3 after second transform!")
            if pval(a4) < 2:
                raise RuntimeError("p^2 does not divide a4 after second transform!")
            if pval(a6) < 3:
                raise RuntimeError("p^3 does not divide a6 after second transform!")
            if min(pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)) < 0:
                raise RuntimeError("Non-integral model after second transform!")

            # Analyze roots of the cubic T^3 + bT^2 + cT + d = 0 mod P, where
            # b = a2/p, c = a4/p^2, d = a6/p^3
            b = preduce(a2/pi)
            c = preduce(a4/pi2)
            d = preduce(a6/pi3)
            bb = b*b
            cc = c*c
            bc = b*c
            w = 27*d*d - bb*cc + 4*b*bb*d - 18*bc*d + 4*c*cc
            x = 3*c - bb
            if pdiv(w):
                if pdiv(x):
                    sw = 3
                else:
                    sw = 2
            else:
                sw = 1
            verbose("Analyzing roots of cubic T^3 + %s*T^2 + %s*T + %s, case %s"%(b, c, d, sw), t, 1)
            if sw == 1:
                ## Three distinct roots - Type I*0
                verbose("Distinct roots", t, 1)
                KS = KodairaSymbol("I0*")
                cp = 1 + _pcubicroots(b, c, d)
                fp = val_disc - 4
                break #return
            elif sw == 2:
                ## One double root - Type I*m for some m
                verbose("One double root", t, 1)
                ## Change coords so that the double root is T = 0 mod p
                if p == 2:
                    r = proot(c, 2)
                elif p == 3:
                    r = c * pinv(b)
                else:
                    r = (bc - 9*d)*pinv(2*x)
                r = pi * preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # The rest of this branch is just to compute cp, fp, KS.
                # We use pi to keep transforms integral.
                ix = 3; iy = 3; mx = pi2; my = mx
                while True:
                    a2t = preduce(a2 / pi)
                    a3t = preduce(a3 / my)
                    a4t = preduce(a4 / (pi*mx))
                    a6t = preduce(a6 / (mx*my))
                    if pdiv(a3t*a3t + 4*a6t):
                        if p == 2:
                            t = my*proot(a6t, 2)
                        else:
                            t = my*preduce(-a3t*halfmodp)
                        C = C.rst_transform(0, 0, t)
                        (a1, a2, a3, a4, a6) = C.a_invariants()
                        (b2, b4, b6, b8) = C.b_invariants()
                        my *= pi
                        iy += 1
                        a2t = preduce(a2 / pi)
                        a3t = preduce(a3/my)
                        a4t = preduce(a4/(pi*mx))
                        a6t = preduce(a6/(mx*my))
                        if pdiv(a4t*a4t - 4*a6t*a2t):
                            if p == 2:
                                r = mx*proot(a6t*pinv(a2t), 2)
                            else:
                                r = mx*preduce(-a4t*pinv(2*a2t))
                            C = C.rst_transform(r, 0, 0)
                            (a1, a2, a3, a4, a6) = C.a_invariants()
                            (b2, b4, b6, b8) = C.b_invariants()
                            mx *= pi
                            ix += 1 # and stay in loop
                        else:
                            if _pquadroots(a2t, a4t, a6t):
                                cp = 4
                            else:
                                cp = 2
                            break # exit loop
                    else:
                        if _pquadroots(1, a3t, -a6t):
                            cp = 4
                        else:
                            cp = 2
                        break
                KS = KodairaSymbol("I%s*"%(ix+iy-5))
                fp = val_disc - ix - iy + 1
                break #return
            else: # sw == 3
                ## The cubic has a triple root
                verbose("Triple root", t, 1)
                ## First we change coordinates so that T = 0 mod p
                if p == 2:
                    r = b
                elif p == 3:
                    r = proot(-d, 3)
                else:
                    r = -b * pinv(3)
                r = pi*preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                verbose("After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s"%([r,0,0],[a1,a2,a3,a4,a6],[pval(ai) for ai in [a1,a2,a3,a4,a6]]), t, 2)
                if min(pval(ai) for ai in [a1,a2,a3,a4,a6]) < 0:
                    raise RuntimeError("Non-integral model after third transform!")
                if pval(a2) < 2 or pval(a4) < 3 or pval(a6) < 4:
                    raise RuntimeError("Cubic after transform does not have a triple root at 0")
                a3t = preduce(a3/pi2)
                a6t = preduce(a6/pi4)
                # We test for Type IV*
                if not pdiv(a3t*a3t + 4*a6t):
                    cp = 3 if _pquadroots(1, a3t, -a6t) else 1
                    KS = KodairaSymbol("IV*")
                    fp = val_disc - 6
                    break #return
                # Now change coordinates so that p^3|a3, p^5|a6
                if p==2:
                    t = -pi2*proot(a6t, 2)
                else:
                    t = pi2*preduce(-a3t*halfmodp)
                C = C.rst_transform(0, 0, t)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # We test for types III* and II*
                if pval(a4) < 4:
                    ## Type III*
                    KS = KodairaSymbol("III*")
                    fp = val_disc - 7
                    cp = 2
                    break #return
                if pval(a6) < 6:
                    ## Type II*
                    KS = KodairaSymbol("II*")
                    fp = val_disc - 8
                    cp = 1
                    break #return
                if pi_neg is None:
                    if principal_flag:
                        pi_neg = pi
                    else:
                        pi_neg = K.uniformizer(P, 'negative')
                    pi_neg2 = pi_neg*pi_neg
                    pi_neg3 = pi_neg*pi_neg2
                    pi_neg4 = pi_neg*pi_neg3
                    pi_neg6 = pi_neg4*pi_neg2
                a1 /= pi_neg
                a2 /= pi_neg2
                a3 /= pi_neg3
                a4 /= pi_neg4
                a6 /= pi_neg6
                verbose("Non-minimal equation, dividing out...\nNew model is %s"%([a1, a2, a3, a4, a6]), t, 1)
        return (C, p, val_disc, fp, KS, cp, split)
    def eval(self, element, *args, **kwds):
        r'''
            Method to evaluate elements in the ring of differential polynomials.

            Since the differential polynomials have an intrinsic meaning (namely, the 
            variables are related by derivation), evaluating a differential polynomial
            is a straight-forward computation once the objects for the ``*_0`` term is given.

            This method evaluates elements in ``self`` following that rule.

            INPUT:

            * ``element``: element (that must be in ``self``) to be evaluated
            * ``args``: list of arguments that will be linearly related with the generators
              of ``self`` (like they are given by ``self.gens()``)
            * ``kwds``: dictionary for providing values to the generators of ``self``. The 
              name of the keys must be the names of the generators (as they can be got using 
              the attribute ``_name``).

            We allow a mixed used of ``args`` and ``kwds`` but an error will be raised if

            * There are too many arguments in ``args``,
            * An input in ``kwds`` is not a valid name of a generator,
            * There are duplicate entries for a generator.

            OUTPUT:

            The resulting element after evaluating the variable `\alpha_n = \partial^n(\alpha)`,
            where `\alpha` is the name of the generator.

            EXAMPLES::

                sage: from dalgebra.differential_polynomial.differential_polynomial_ring import * 
                sage: R.<y> = DiffPolynomialRing(QQ['x']); x = R.base().gens()[0]
                sage: R.eval(y[1], 0)
                0
                sage: R.eval(y[0] + y[1], x)
                x + 1
                sage: R.eval(y[0] + y[1], y=x)
                x + 1

            This method commutes with the use of :func:`derivation`::

                sage: R.eval(R.derivation(x^2*y[1]^2 - y[2]*y[1]), y=x) == R.derivation(R.eval(x^2*y[1]^2 - y[2]*y[1], y=x))
                True

            This evaluation also works naturally with several infinite variables::

                sage: S = DiffPolynomialRing(R, 'a'); a,y = S.gens()
                sage: S.eval(a[1] + y[0]*a[0], a=x, y=x^2)
                x^3 + 1
                sage: in_eval = S.eval(a[1] + y[0]*a[0], y=x); in_eval
                a_1 + x*a_0
                sage: parent(in_eval)
                Ring of differential polynomials in (a) over [Univariate Polynomial Ring in x over Rational Field]
        '''
        if (not element in self):
            raise TypeError("Impossible to evaluate %s as an element of %s" %
                            (element, self))
        g = self.gens()
        final_input = {}
        names = [el._name for el in g]
        if (len(args) > self.ngens()):
            raise ValueError(
                "Too many argument for evaluation: given %d, expected (at most) %d"
                % (len(args), self.ngens()))
        for i in range(len(args)):
            final_input[g[i]] = args[i]
        for key in kwds:
            if (not key in names):
                raise TypeError("Invalid name for argument %s" % key)
            gen = g[names.index(key)]
            if (gen in final_input):
                raise TypeError("Duplicated value for generator %s" % gen)
            final_input[gen] = kwds[key]

        max_derivation = {gen: 0 for gen in final_input}
        for v in element.variables():
            for gen in max_derivation:
                if (gen.contains(v)):
                    max_derivation[gen] = max(max_derivation[gen],
                                              gen.index(v))
                    break

        to_evaluate = {}
        for gen in max_derivation:
            for i in range(max_derivation[gen] + 1):
                to_evaluate[str(gen[i])] = diff(final_input[gen], i)

        ## Computing the final ring
        values = list(final_input.values())
        R = parent(values[0])
        for i in range(1, len(values)):
            R = pushout(R, parent(values[i]))

        poly = element.polynomial()
        ## Adding all the non-appearing variables on element
        if (len(final_input) == len(g)):
            for v in poly.parent().gens():
                if (v not in poly.variables()) and (not str(v) in to_evaluate):
                    to_evaluate[str(v)] = 0
        else:
            left_gens = [gen for gen in g if gen not in final_input]
            R = DiffPolynomialRing(R, [el._name for el in left_gens])
            for v in poly.parent().gens():
                if (not any(gen.contains(v)
                            for gen in left_gens)) and (not str(v)
                                                        in to_evaluate):
                    to_evaluate[str(v)] = 0

        return R(poly(**to_evaluate))
Пример #32
0
 def jet(self, Intervals):
     base_ring = (Intervals if self.is_numeric
                  else pushout(self.pt.parent(), Intervals))
     Pol = PolynomialRing(base_ring, 'eta')
     return Pol([self.pt, 1]).truncate(self.jet_order)