Exemple #1
0
    def riemann_sum(self,f,center=1,level=0,E=None):
        r"""
        This function evaluates the integral of the funtion ``f`` with respect to the measure determined by ``self``.

        EXAMPLES:

        This example illustrates ...

        ::
        """
        R1=LaurentSeriesRing(f.base_ring(),'r1')
        R1.set_default_prec(self._parent._k-1)
        R2=PolynomialRing(f.base_ring(),'r2')

        if E is None:
            E=self._parent._X._BT.get_balls(center,level)
        else:
            E=self._parent._X._BT.subdivide(E,level)
        value=0
        ii=0
        for e in E:
            ii+=1
            exp=R1([e[1,1],e[1,0]])**(self._parent._k-2)*e.determinant()**(-(self._parent._k-2)/2)*f(R1([e[0,1],e[0,0]])/R1([e[1,1],e[1,0]])).truncate(self._parent._k-1)
            new=self.evaluate(e).l_act_by(e.inverse()).evaluate(exp)
            value+=new
        return value
Exemple #2
0
def compute_wp_pari(E,prec):
    r"""
    Computes the Weierstrass `\wp`-function via calling the corresponding function in pari.

    EXAMPLES::

        sage: E = EllipticCurve([0,1])
        sage: E.weierstrass_p(algorithm='pari')
        z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20)

        sage: E = EllipticCurve(GF(101),[5,4])
        sage: E.weierstrass_p(prec=30, algorithm='pari')
        z^-2 + 100*z^2 + 86*z^4 + 34*z^6 + 50*z^8 + 82*z^10 + 45*z^12 + 70*z^14 + 33*z^16 + 87*z^18 + 33*z^20 + 36*z^22 + 45*z^24 + 40*z^26 + 12*z^28 + O(z^30)

        sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari
        sage: compute_wp_pari(E, prec= 20)
        z^-2 + 100*z^2 + 86*z^4 + 34*z^6 + 50*z^8 + 82*z^10 + 45*z^12 + 70*z^14 + 33*z^16 + 87*z^18 + O(z^20)

    """
    ep = E._pari_()
    wpp = ep.ellwp(n=prec)
    k = E.base_ring()
    R = LaurentSeriesRing(k,'z')
    z = R.gen()
    wp = z**(-2)
    for i in xrange(prec):
        wp += k(wpp[i]) * z**i
    wp = wp.add_bigoh(prec)
    return wp
Exemple #3
0
def compute_wp_quadratic(k, A, B, prec):
    r"""
    Computes the truncated Weierstrass function of an elliptic curve
    defined by short Weierstrass model: `y^2 = x^3 + Ax + B`. Uses an
    algorithm that is of complexity `O(prec^2)`.

    Let p be the characteristic of the underlying field. Then we must
    have either p = 0, or p > prec + 2.

    INPUT:

     - ``k`` - the field of definition of the curve
     - ``A`` - and
     - ``B`` - the coefficients of the elliptic curve
     - ``prec`` - the precision to which we compute the series.

    OUTPUT:
    A Laurent series aproximating the Weierstrass `\wp`-function to precision ``prec``.

    ALGORITHM:
    This function uses the algorithm described in section 3.2 of [BMSS].

    REFERENCES:
    [BMSS] Boston, Morain, Salvy, Schost, "Fast Algorithms for Isogenies."

    EXAMPLES::

        sage: E = EllipticCurve([7,0])
        sage: E.weierstrass_p(prec=10, algorithm='quadratic')
        z^-2 - 7/5*z^2 + 49/75*z^6 + O(z^10)

        sage: E = EllipticCurve(GF(103),[1,2])
        sage: E.weierstrass_p(algorithm='quadratic')
        z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + 55*z^10 + 73*z^12 + 11*z^14 + 17*z^16 + 50*z^18 + O(z^20)

        sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_quadratic
        sage: compute_wp_quadratic(E.base_ring(), E.a4(), E.a6(), prec=10)
        z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + O(z^10)

    """
    m = (prec + 1)//2
    c = [0 for j in range(m)]
    c[0] = -A/5
    c[1] = -B/7

    # first Z represent z^2
    R = LaurentSeriesRing(k,'z')
    Z = R.gen()
    pe = Z**-1 + c[0]*Z + c[1]*Z**2

    for i in range(3, m):
        t = 0
        for j in range(1, i - 1):
            t += c[j-1]*c[i-2-j]
        ci = (3*t)/((i-2)*(2*i+3))
        pe += ci * Z**i
        c[i-1] = ci

    return pe(Z**2).add_bigoh(prec)
Exemple #4
0
    def integrate(self,f,center=1,level=0,method='moments'):
        r"""
        Calculate
        .. MATH::

            \int_{\PP^1(\QQ_p)} f(x)d\mu(x)

        were `\mu` is the measure associated to ``self``.

        INPUT:

         - ``f`` - An analytic function.

         - ``center`` - 2x2 matrix over Qp (default: 1)

         - ``level`` - integer (default: 0)

         - ``method`` - string (default: 'moments'). Which method of integration to use. Either 'moments' or 'riemann_sum'.


        EXAMPLES:

        ::


        AUTHORS:

        - Marc Masdeu (2012-02-20)
        - Cameron Franc (2012-02-20)

        """
        E=self._parent._X._BT.get_balls(center,level)
        R1=LaurentSeriesRing(f.base_ring(),'r1')
        R2=PolynomialRing(f.base_ring(),'r2')
        value=0
        ii=0
        if(method=='riemann_sum'):
            R1.set_default_prec(self._parent._U.weight()+1)
            for e in E:
                ii+=1
                #print ii,"/",len(E)
                exp=((R1([e[1,1],e[1,0]]))**(self._parent._U.weight())*e.determinant()**(-(self._parent._U.weight())/2))*f(R1([e[0,1],e[0,0]])/R1([e[1,1],e[1,0]]))
                #exp=R2([tmp[jj] for jj in range(self._parent._k-1)])
                new=self.evaluate(e).evaluate(exp.truncate(self._parent._U.weight()+1))
                value+=new
        elif(method=='moments'):
            R1.set_default_prec(self._parent._U.dimension())
            for e in E:
                ii+=1
                #print ii,"/",len(E)
                tmp=((R2([e[1,1],e[1,0]]))**(self._parent._U.weight())*e.determinant()**(-(self._parent._U.weight())/2))*f(R2([e[0,1],e[0,0]])/R2([e[1,1],e[1,0]]))
                exp=R1(tmp.numerator())/R1(tmp.denominator())
                new=self.evaluate(e).evaluate(exp)
                value+=new
        else:
            print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should never be used.'
            return False
        return value
def _sa_coefficients_lambda_(K, beta=0):
    r"""
    Return the coefficients `\lambda_{k, \ell}(\beta)` used in singularity analysis.

    INPUT:

    - ``K`` -- an integer.

    - ``beta`` -- (default: `0`) the order of the logarithmic
      singularity.

    OUTPUT:

    A dictionary mapping pairs of indices to rationals.

    .. SEEALSO::

        :meth:`~AsymptoticExpansionGenerators.SingularityAnalysis`

    TESTS::

        sage: from sage.rings.asymptotic.asymptotic_expansion_generators \
        ....:     import _sa_coefficients_lambda_
        sage: _sa_coefficients_lambda_(3)
        {(0, 0): 1,
         (1, 1): -1,
         (1, 2): 1/2,
         (2, 2): 1,
         (2, 3): -5/6,
         (2, 4): 1/8,
         (3, 3): -1,
         (3, 4): 13/12,
         (4, 4): 1}
        sage: _sa_coefficients_lambda_(3, beta=1)
        {(0, 0): 1,
         (1, 1): -2,
         (1, 2): 1/2,
         (2, 2): 3,
         (2, 3): -4/3,
         (2, 4): 1/8,
         (3, 3): -4,
         (3, 4): 29/12,
         (4, 4): 5}
    """
    from sage.rings.laurent_series_ring import LaurentSeriesRing
    from sage.rings.power_series_ring import PowerSeriesRing
    from sage.rings.rational_field import QQ

    V = LaurentSeriesRing(QQ, names='v', default_prec=K)
    v = V.gen()
    T = PowerSeriesRing(V, names='t', default_prec=2*K-1)
    t = T.gen()

    S = (t - (1+1/v+beta) * (1+v*t).log()).exp()
    return dict(((k + L.valuation(), ell), c)
                for ell, L in enumerate(S.list())
                for k, c in enumerate(L.list()))
Exemple #6
0
    def __init__(self, f, x0, singular_data, order=None):
        r"""Initialize a PuiseuxTSeries using a set of :math:`\pi = \{\tau\}`
        data.

        Parameters
        ----------
        f, x, y : polynomial
            A plane algebraic curve.
        x0 : complex
            The x-center of the Puiseux series expansion.
        singular_data : list
            The output of :func:`singular`.
        t : variable
            The variable in which the Puiseux t series is represented.

        """
        R = f.parent()
        x,y = R.gens()
        extension_polynomial, xpart, ypart = singular_data
        L = LaurentSeriesRing(ypart.base_ring(), 't')
        t = L.gen()

        self.f = f
        self.t = t
        self._xpart = xpart
        self._ypart = ypart

        # store x-part attributes. handle the centered at infinity case
        self.x0 = x0
        if x0 == infinity:
            x0 = QQ(0)
        self.center = x0

        # extract and store information about the x-part of the puiseux series
        xpart = xpart(t,0)
        xpartshift = xpart - x0
        ramification_index, xcoefficient = xpartshift.laurent_polynomial().dict().popitem()
        self.xcoefficient = xcoefficient
        self.ramification_index = QQ(ramification_index).numerator()
        self.xpart = xpart

        # extract and store information about the y-part of the puiseux series
        self.ypart = L(ypart(t,0))
        self._initialize_extension(extension_polynomial)

        # determine the initial order. See the order property
        val = L(ypart(t,O(t))).prec()
        self._singular_order = 0 if val == infinity else val
        self._regular_order = self._p.degree(x)

        # extend to have at least two elements
        self.extend(nterms=1)

        # the curve, x-part, and terms output by puiseux make the puiseux
        # series unique. any mutability only adds terms
        self.__parent = self.ypart.parent()
        self._hash = hash((self.f, self.xpart, self.ypart))
    def local_coordinates_at_infinity(self, prec = 20, name = 't'):
        """
        For the genus `g` hyperelliptic curve `y^2 = f(x)`, return
        `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is
        the local parameter at infinity

        INPUT:

        - ``prec`` -- desired precision of the local coordinates
        - ``name`` -- generator of the power series ring (default: ``t``)

        OUTPUT:

        `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x^g/y`
        is the local parameter at infinity

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-5*x^2+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12)
            sage: y
            t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12)

        ::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^3-x+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12)
            sage: y
            t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12)

        AUTHOR:

        - Jennifer Balakrishnan (2007-12)
        """
        g = self.genus()
        pol = self.hyperelliptic_polynomials()[0]
        K = LaurentSeriesRing(self.base_ring(), name, default_prec=prec+2)
        t = K.gen()
        L = PolynomialRing(K,'x')
        x = L.gen()
        i = 0
        w = (x**g/t)**2-pol
        wprime = w.derivative(x)
        x = t**-2
        for i in range((RR(log(prec+2)/log(2))).ceil()):
            x = x - w(x)/wprime(x)
        y = x**g/t
        return x+O(t**(prec+2)) , y+O(t**(prec+2))
    def test_LaurentSeries_V(self):
        L = LaurentSeriesRing(QQ,'t')
        t = L.gen()

        l = 1*t**(-3) + 2 + 3*t**1 + 4*t**2 + 5*t**9
        m = LaurentSeries_V(l,1)
        self.assertEqual(l, m)

        m = LaurentSeries_V(l, 2)
        self.assertEqual(m.exponents(), [-6,0,2,4,18])
        self.assertEqual(m.coefficients(), [1,2,3,4,5])

        m = LaurentSeries_V(l, -1)
        self.assertEqual(m.exponents(), [-9,-2,-1,0,3])
        self.assertEqual(m.coefficients(), [5,4,3,2,1])

        m = LaurentSeries_V(l, -3)
        self.assertEqual(m.exponents(), [-27,-6,-3,0,9])
        self.assertEqual(m.coefficients(), [5,4,3,2,1])
Exemple #9
0
    def series(self, n):
        """
        Return the Laurent power series associated with the CFiniteSequence, with precision `n`.
        
        INPUT:

        - ``n`` -- a nonnegative integer

        EXAMPLES::

            sage: r = CFiniteSequence.from_recurrence([-1,2],[0,1])
            sage: s = r.series(4); s
            x + 2*x^2 + 3*x^3 + 4*x^4 + O(x^5)
            sage: type(s)
            <type 'sage.rings.laurent_series_ring_element.LaurentSeries'>
        """

        R = LaurentSeriesRing(QQ, 'x')
        R.set_default_prec(n)
        return R(self.ogf())
Exemple #10
0
def compute_wp_pari(E, prec):
    r"""
    Computes the Weierstrass `\wp`-function with the ``ellwp`` function
    from PARI.

    EXAMPLES::

        sage: E = EllipticCurve([0,1])
        sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari
        sage: compute_wp_pari(E, prec=20)
        z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20)
        sage: compute_wp_pari(E, prec=30)
        z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + 3/38548055*z^22 - 4/8364927935*z^28 + O(z^30)
    """
    ep = E.__pari__()
    wpp = ep.ellwp(n=prec)
    k = E.base_ring()
    R = LaurentSeriesRing(k, 'z')
    z = R.gen()
    wp = z**(-2)
    for i in range(prec):
        wp += k(wpp[i]) * z**i
    wp = wp.add_bigoh(prec)
    return wp
Exemple #11
0
def compute_wp_pari(E,prec):
    r"""
    Computes the Weierstrass `\wp`-function with the ``ellwp`` function
    from PARI.

    EXAMPLES::

        sage: E = EllipticCurve([0,1])
        sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari
        sage: compute_wp_pari(E, prec=20)
        z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20)
        sage: compute_wp_pari(E, prec=30)
        z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + 3/38548055*z^22 - 4/8364927935*z^28 + O(z^30)
    """
    ep = E._pari_()
    wpp = ep.ellwp(n=prec)
    k = E.base_ring()
    R = LaurentSeriesRing(k,'z')
    z = R.gen()
    wp = z**(-2)
    for i in range(prec):
        wp += k(wpp[i]) * z**i
    wp = wp.add_bigoh(prec)
    return wp
Exemple #12
0
    def __init__(self,
                 base_ring,
                 name=None,
                 default_prec=None,
                 sparse=False,
                 category=None):
        CommutativeRing.__init__(self,
                                 base_ring,
                                 names=name,
                                 category=getattr(self, '_default_category',
                                                  Fields()))

        # If self is R(( x^(1/e) )) then the corresponding Laurent series
        # ring will be R(( x ))
        self._laurent_series_ring = LaurentSeriesRing(
            base_ring, name=name, default_prec=default_prec, sparse=sparse)
Exemple #13
0
 def linear_relation(self, List, Psi, verbose=True, prec=None):
     for Phi in List:
         assert Phi.valuation() >= 0, "Symbols must be integral"
     assert Psi.valuation() >= 0
     R = self.base()
     Rbase = R.base()
     w = R.gen()
     d = len(List)
     if d == 0:
         if Psi.is_zero():
             return [None, R(1)]
         else:
             return [None, 0]
     if prec is None:
         M, var_prec = Psi.precision_absolute()
     else:
         M, var_prec = prec
     p = self.prime()
     V = R**d
     RSR = LaurentSeriesRing(Rbase, R.variable_name())
     VSR = RSR**self.source().ngens()
     List_TMs = [VSR(Phi.list_of_total_measures()) for Phi in List]
     Psi_TMs = VSR(Psi.list_of_total_measures())
     A = Matrix(RSR, List_TMs).transpose()
     try:
         sol = V([vv.power_series() for vv in A.solve_right(Psi_TMs)])
     except ValueError:
         #try "least squares"
         if verbose:
             print "Trying least squares."
         sol = (A.transpose() * A).solve_right(A.transpose() * Psi_TMs)
         #check precision (could make this better, checking each power of w)
         p_prec = M
         diff = Psi_TMs - sum([sol[i] * List_TMs[i] for i in range(len(List_TMs))])
         for i in diff:
             for j in i.list():
                 if p_prec > j.valuation():
                     p_prec = j.valuation()
         if verbose:
             print "p-adic precision is now", p_prec
         #Is this right?
         sol = V([R([j.add_bigoh(p_prec) for j in i.list()]) for i in sol])
     return [sol, R(-1)]
Exemple #14
0
    def series(self, n):
        """
        Return the Laurent power series associated with the
        CFiniteSequence, with precision `n`.

        INPUT:

        - `n` -- a nonnegative integer

        EXAMPLES::

            sage: C.<x> = CFiniteSequences(QQ)
            sage: r = C.from_recurrence([-1,2],[0,1])
            sage: s = r.series(4); s
            x + 2*x^2 + 3*x^3 + 4*x^4 + O(x^5)
            sage: type(s)
            <class 'sage.rings.laurent_series_ring_element.LaurentSeries'>
        """
        R = LaurentSeriesRing(QQ, 'x', default_prec=n)
        return R(self.ogf())
    def completion(self, p, prec=20, extras=None):
        """
        EXAMPLES::

            sage: P.<x>=LaurentPolynomialRing(QQ)
            sage: P
            Univariate Laurent Polynomial Ring in x over Rational Field
            sage: PP=P.completion(x)
            sage: PP
            Laurent Series Ring in x over Rational Field
            sage: f=1-1/x
            sage: PP(f)
            -x^-1 + 1
            sage: 1/PP(f)
            -x - x^2 - x^3 - x^4 - x^5 - x^6 - x^7 - x^8 - x^9 - x^10 - x^11 - x^12 - x^13 - x^14 - x^15 - x^16 - x^17 - x^18 - x^19 - x^20 + O(x^21)
        """
        if str(p) == self._names[0] and self._n == 1:
            from sage.rings.laurent_series_ring import LaurentSeriesRing
            return LaurentSeriesRing(self.base_ring(), name=self._names[0])
        else:
            raise TypeError("Cannot complete %s with respect to %s" %
                            (self, p))
Exemple #16
0
    def __init__(self, ogf, *args, **kwargs):

        """
    Create a C-finite sequence given its ordinary generating function.

    INPUT:

    - ``ogf`` -- the ordinary generating function, a fraction of polynomials over the rationals


    OUTPUT:

    - A CFiniteSequence object

    EXAMPLES::

        sage: R.<x> = QQ[]
        sage: CFiniteSequence((2-x)/(1-x-x^2))     # the Lucas sequence
        C-finite sequence, generated by (-x + 2)/(-x^2 - x + 1)
        sage: CFiniteSequence(x/(1-x)^3)           # triangular numbers
        C-finite sequence, generated by x/(-x^3 + 3*x^2 - 3*x + 1)
        
    Polynomials are interpreted as finite sequences, or recurrences of degree 0::
    
        sage: CFiniteSequence(x^2-4*x^5)
        Finite sequence [1, 0, 0, -4], offset = 2
        sage: CFiniteSequence(1)
        Finite sequence [1], offset = 0

    This implementation allows any polynomial fraction as o.g.f. by interpreting
    any power of `x` dividing the o.g.f. numerator or denominator as a right or left shift
    of the sequence offset::

        sage: CFiniteSequence(x^2+3/x)
        Finite sequence [3, 0, 0, 1], offset = -1
        sage: CFiniteSequence(1/x+4/x^3)
        Finite sequence [4, 0, 1], offset = -3
        sage: P = LaurentPolynomialRing(QQ.fraction_field(), 'X')
        sage: X=P.gen()
        sage: CFiniteSequence(1/(1-X))
        C-finite sequence, generated by 1/(-x + 1)
        
    The o.g.f. is always normalized to get a denominator constant coefficient of `+1`::
    
        sage: CFiniteSequence(1/(x-2))
        C-finite sequence, generated by -1/2/(-1/2*x + 1)
    
    TESTS::
    
        sage: P.<x> = QQ[]
        sage: CFiniteSequence(0.1/(1-x))
        Traceback (most recent call last):
        ...
        ValueError: O.g.f. base not rational.
        sage: P.<x,y> = QQ[]
        sage: CFiniteSequence(x*y)
        Traceback (most recent call last):
        ...
        NotImplementedError: Multidimensional o.g.f. not implemented.
        """

        self._br = ogf.base_ring()
        if (self._br <> QQ) and (self._br <> ZZ) and not is_FiniteField(self._br):
            raise ValueError('O.g.f. base not proper.')
        
        P = PolynomialRing(self._br, 'x')
        if ogf in QQ:
            ogf = P(ogf)
        if hasattr(ogf,'numerator'):
            try:
                num = P(ogf.numerator())
                den = P(ogf.denominator())
            except TypeError:
                if ogf.numerator().parent().ngens() > 1:
                    raise NotImplementedError('Multidimensional o.g.f. not implemented.')
                else:
                    raise ValueError('Numerator and denominator must be polynomials.')
        else:
            num = P(ogf)
            den = 1
        
        # Transform the ogf numerator and denominator to canonical form
        # to get the correct offset, degree, and recurrence coeffs and
        # start values.
        self._off = 0
        self._deg = 0
        if isinstance (ogf, FractionFieldElement) and den == 1:
            ogf = num        # case p(x)/1: fall through
            
        if isinstance (ogf, (FractionFieldElement, FpTElement)):
            x = P.gen()
            if num.constant_coefficient() == 0:
                self._off = num.valuation()
                num = P(num / x**self._off)
            elif den.constant_coefficient() == 0:
                self._off = -den.valuation()
                den = P(den * x**self._off)
            f = den.constant_coefficient()
            num = P(num / f)
            den = P(den / f)
            f = gcd(num, den)
            num = P(num / f) 
            den = P(den / f)
            self._deg = den.degree()
            self._c = [-den.list()[i] for i in range(1, self._deg + 1)]
            if self._off >= 0:
                num = x**self._off * num
            else:
                den = x**(-self._off) * den

            # determine start values (may be different from _get_item_ values)
            R = LaurentSeriesRing(self._br, 'x')
            rem = num % den
            alen = max(self._deg, num.degree() + 1)
            R.set_default_prec (alen)
            if den <> 1:
                self._a = R(num/(den+O(x**alen))).list()
                self._aa = R(rem/(den+O(x**alen))).list()[:self._deg]  # needed for _get_item_
            else:
                self._a = num.list()
            if len(self._a) < alen:
                self._a.extend([0] * (alen - len(self._a)))
                
            super(CFiniteSequence, self).__init__(P.fraction_field(), num, den, *args, **kwargs)
            
        elif ogf.parent().is_integral_domain():
            super(CFiniteSequence, self).__init__(ogf.parent().fraction_field(), P(ogf), 1, *args, **kwargs)
            self._c = []
            self._off = P(ogf).valuation()
            if ogf == 0:
                self._a = [0]
            else:
                self._a = ogf.parent()((ogf / (ogf.parent().gen())**self._off)).list()
        else:
            raise ValueError("Cannot convert a " + str(type(ogf)) + " to CFiniteSequence.")
Exemple #17
0
def S(P, m):
    PP = P.parent()
    from sage.rings.laurent_series_ring import LaurentSeriesRing
    LS = LaurentSeriesRing(PP.base_ring(), name='z', default_prec=m)
    irP = 1 / LS(P.reverse())
    return PP(irP.list())
Exemple #18
0
    def __init__(self, parent, ogf):
        r"""
        Initialize the C-Finite sequence.

        The ``__init__`` method can only be called by the :class:`CFiniteSequences`
        class. By Default, a class call reaches the ``__classcall_private__``
        which first creates a proper parent and then call the ``__init__``.

        INPUT:

        - ``ogf`` -- the ordinary generating function, a fraction of polynomials over the rationals
        - ``parent`` --  the parent of the C-Finite sequence, an occurrence of :class:`CFiniteSequences`

        OUTPUT:

        - A CFiniteSequence object

        TESTS::

            sage: C.<x> = CFiniteSequences(QQ)
            sage: C((2-x)/(1-x-x^2))            # indirect doctest
            C-finite sequence, generated by (x - 2)/(x^2 + x - 1)
        """

        br = parent.base_ring()
        ogf = parent.fraction_field()(ogf)
        P = parent.polynomial_ring()
        num = ogf.numerator()
        den = ogf.denominator()

        FieldElement.__init__(self, parent)

        if den == 1:
            self._c = []
            self._off = num.valuation()
            self._deg = 0
            if ogf == 0:
                self._a = [0]
            else:
                self._a = num.shift(-self._off).list()
        else:
            # Transform the ogf numerator and denominator to canonical form
            # to get the correct offset, degree, and recurrence coeffs and
            # start values.
            self._off = 0
            self._deg = 0
            if num.constant_coefficient() == 0:
                self._off = num.valuation()
                num = num.shift(-self._off)
            elif den.constant_coefficient() == 0:
                self._off = -den.valuation()
                den = den.shift(self._off)
            f = den.constant_coefficient()
            num = P(num / f)
            den = P(den / f)
            f = num.gcd(den)
            num = P(num / f)
            den = P(den / f)
            self._deg = den.degree()
            self._c = [-den[i] for i in range(1, self._deg + 1)]
            if self._off >= 0:
                num = num.shift(self._off)
            else:
                den = den.shift(-self._off)

            # determine start values (may be different from _get_item_ values)
            alen = max(self._deg, num.degree() + 1)
            R = LaurentSeriesRing(br,
                                  parent.variable_name(),
                                  default_prec=alen)
            rem = num % den
            if den != 1:
                self._a = R(num / den).list()
                self._aa = R(rem /
                             den).list()[:self._deg]  # needed for _get_item_
            else:
                self._a = num.list()
            if len(self._a) < alen:
                self._a.extend([0] * (alen - len(self._a)))

            ogf = num / den

        self._ogf = ogf
Exemple #19
0
    def coleman(self,t1,t2,E=None,method='moments',mult=False,delta=-1,level=0):
        r"""
        If ``self`` is a `p`-adic automorphic form that corresponds to a rigid modular form,
        then this computes the coleman integral of this form between two points on
        the boundary `\PP^1(\QQ_p)` of the `p`-adic upper half plane.

        INPUT:

         - ``t1``, ``t2`` - elements of `\PP^1(\QQ_p)` (the endpoints of integration)

         - ``E`` - (Default: None). If specified, will not compute the covering adapted
            to ``t1`` and ``t2`` and instead use the given one. In that case, ``E``
            should be a list of matrices corresponding to edges describing the open
            balls to be considered.

         - ``method`` - string (Default: 'moments'). Tells which algorithm to use 
           (alternative is 'riemann_sum', which is unsuitable for computations 
           requiring high precision)

         - ``mult`` - boolean (Default: False). Whether to use the multiplicative version.

         - ``delta`` - integer (Default: -1)

         - ``level`` - integer (Default: 0)

        OUTPUT:

          The result of the coleman integral

        EXAMPLES:

        This example illustrates ...

        ::

        TESTS:

        ::
            sage: p = 7
            sage: lev = 2
            sage: prec = 20
            sage: X = BTQuotient(p,lev, use_magma = True) # optional - magma
            sage: k = 2 # optional - magma
            sage: M = HarmonicCocycles(X,k,prec) # optional - magma
            sage: B = M.basis() # optional - magma
            sage: f = 3*B[0] # optional - magma
            sage: MM = pAutomorphicForms(X,k,prec,overconvergent=True) # optional - magma
            sage: D = -11 # optional - magma
            sage: X.is_admissible(D) # optional - magma
            True
            sage: K.<a> = QuadraticField(D) # optional - magma
            sage: CM = X.get_CM_points(D,prec=prec) # optional - magma
            sage: Kp = CM[0].parent() # optional - magma
            sage: P=CM[0] # optional - magma
            sage: Q=P.trace()-P # optional - magma
            sage: F=MM.lift(f, verbose = False) # long time optional - magma
            sage: J0=F.coleman(P,Q,mult=True) # long time optional - magma
            sage: E=EllipticCurve([1,0,1,4,-6]) # optional - magma
            sage: T=E.tate_curve(p) # optional - magma
            sage: xx,yy=getcoords(T,J0,prec) # long time optional -magma
            sage: P = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); P # long time optional - magma
            (7/11 : 58/121*a - 9/11 : 1)

            sage: p = 13 # optional - magma
            sage: lev = 2 # optional - magma
            sage: prec = 20 # optional - magma
            sage: Y = BTQuotient(p,lev, use_magma = True) # optional - magma
            sage: k = 2 # optional - magma
            sage: M=HarmonicCocycles(Y,k,prec) # optional - magma
            sage: B=M.basis() # optional - magma

            sage: f = B[1] # optional - magma
            sage: g = -4*B[0]+3*B[1] # optional - magma
            sage: MM = pAutomorphicForms(Y,k,prec,overconvergent=True) # optional - magma
            sage: D = -11 # optional - magma
            sage: Y.is_admissible(D) # optional - magma
            True
            sage: K.<a> = QuadraticField(D) # optional - magma
            sage: CM = Y.get_CM_points(D,prec=prec) # optional - magma
            sage: Kp = parent(CM[0]) # optional - magma
            sage: P = CM[0] # optional - magma
            sage: Q = P.trace()-P # optional - magma
            sage: F = MM.lift(f, verbose = False) # long time optional - magma
            sage: J11 = F.coleman(P,Q,mult = True) # long time optional - magma
            sage: E = EllipticCurve('26a2') # optional - magma
            sage: T = E.tate_curve(p) # optional - magma
            sage: xx,yy = getcoords(T,J11,prec) # long time optional - magma
            sage: HP = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); HP # long time optional - magma
            (-137/11 : 2/121*a + 63/11 : 1)

        AUTHORS:

        - Cameron Franc (2012-02-20)
        - Marc Masdeu (2012-02-20)
        """
        if(mult and delta>=0):
            raise NotImplementedError, "Need to figure out how to implement the multiplicative part."
        p=self._parent._X._p
        K=t1.parent()
        R=PolynomialRing(K,'x')
        x=R.gen()
        R1=LaurentSeriesRing(K,'r1')
        r1=R1.gen()
        if(E is None):
            E=self._parent._X._BT.find_covering(t1,t2)
            # print 'Got %s open balls.'%len(E)
        value=0
        ii=0
        value_exp=K(1)
        if(method=='riemann_sum'):
            R1.set_default_prec(self._parent._U.weight()+1)
            for e in E:
                ii+=1
                b=e[0,1]
                d=e[1,1]
                y=(b-d*t1)/(b-d*t2)
                poly=R1(y.log()) #R1(our_log(y))
                c_e=self.evaluate(e)
                new=c_e.evaluate(poly)
                value+=new
                if mult:
                    value_exp *= K.teichmuller(y)**Integer(c_e[0].rational_reconstruction())

        elif(method=='moments'):
            R1.set_default_prec(self._parent._U.dimension())
            for e in E:
                ii+=1
                f=(x-t1)/(x-t2)
                a,b,c,d=e.list()
                y0=f(R1([b,a])/R1([d,c])) #f( (ax+b)/(cx+d) )
                y0=p**(-y0(0).valuation())*y0
                mu=K.teichmuller(y0(0))
                y=y0/mu-1
                poly=R1(0)
                ypow=y
                for jj in range(1,R1.default_prec()+10):
                    poly+=(-1)**(jj+1)*ypow/jj
                    ypow*=y
                if(delta>=0):
                    poly*=((r1-t1)**delta*(r1-t2)**(self._parent._n-delta))
                c_e=self.evaluate(e)
                new=c_e.evaluate(poly)
                value+=new
                if mult:
                    value_exp *= K.teichmuller((b-d*t1)/(b-d*t2))**Integer(c_e[0].rational_reconstruction())

        else:
            print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should not be used in practice.'
            return False
        if mult:
            return value_exp * value.exp()
        return value
    def coleman(self,t1,t2,poly = None, E = None,method = 'moments',mult = False,level = 0, branch = 0):
        r"""
        If ``self`` is a `p`-adic automorphic form that corresponds to a rigid modular form,
        then this computes the coleman integral of this form between two points on
        the boundary `\PP^1(\QQ_p)` of the `p`-adic upper half plane.

        INPUT:

        - ``t1``, ``t2`` - elements of `\PP^1(\QQ_p)` (the endpoints of integration)

        - ``E`` - (Default: None). If specified, will not compute the covering adapted
           to ``t1`` and ``t2`` and instead use the given one. In that case, ``E``
           should be a list of matrices corresponding to edges describing the open
           balls to be considered.

        - ``method`` - string (Default: 'moments'). Tells which algorithm to use
          (alternative is 'riemann_sum', which is unsuitable for computations
          requiring high precision)

        - ``mult`` - boolean (Default: False). Whether to use the multiplicative version.

        - ``poly`` - polynomial (Default: None)

        - ``level`` - integer (Default: 0)

        OUTPUT:

          The result of the coleman integral

        EXAMPLES::

            sage: p = 7
            sage: lev = 2
            sage: prec = 20
            sage: X = BTQuotient(p,lev, use_magma = True) # optional - magma
            sage: k = 2 # optional - magma
            sage: M = HarmonicCocycles(X,k,prec) # optional - magma
            sage: B = M.basis() # optional - magma
            sage: f = 3*M.decomposition()[0].gen(0) # optional - magma
            sage: MM = pAutomorphicForms(X,k,prec,overconvergent = True) # optional - magma
            sage: D = -11 # optional - magma
            sage: X.is_admissible(D) # optional - magma
            True
            sage: K.<a> = QuadraticField(D) # optional - magma
            sage: CM = X.get_CM_points(D,prec = prec) # optional - magma
            sage: P = CM[0] # optional - magma
            sage: Q = P.trace()-P # optional - magma
            sage: F = MM.lift(f, verbose = False) # long time optional - magma
            sage: J0 = F.coleman(P,Q,mult = True) # long time optional - magma
            sage: E = EllipticCurve([1,0,1,4,-6]) # optional - magma
            sage: T = E.tate_curve(p) # optional - magma
            sage: xx,yy = getcoords(T,J0,prec) # long time optional -magma
            sage: P = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); P # long time optional - magma
            (7/11 : 58/121*a - 9/11 : 1)

            sage: p = 13 # optional - magma
            sage: lev = 2 # optional - magma
            sage: prec = 20 # optional - magma
            sage: Y = BTQuotient(p,lev, use_magma = True) # optional - magma
            sage: k = 2 # optional - magma
            sage: M = HarmonicCocycles(Y,k,prec) # optional - magma
            sage: B = M.basis() # optional - magma
            sage: f = M.decomposition()[1].gen(0) # optional - magma
            sage: g = M.decomposition()[0].gen(0) # optional - magma
            sage: MM = pAutomorphicForms(Y,k,prec,overconvergent = True) # optional - magma
            sage: D = -11 # optional - magma
            sage: Y.is_admissible(D) # optional - magma
            True
            sage: K.<a> = QuadraticField(D) # optional - magma
            sage: CM = Y.get_CM_points(D,prec = prec) # optional - magma
            sage: P = CM[0] # optional - magma
            sage: Q = P.trace()-P # optional - magma
            sage: F = MM.lift(f, verbose = False) # long time optional - magma
            sage: J11 = F.coleman(P,Q,mult = True) # long time optional - magma
            sage: E = EllipticCurve('26a2') # optional - magma
            sage: T = E.tate_curve(p) # optional - magma
            sage: xx,yy = getcoords(T,J11,prec) # long time optional - magma
            sage: HP = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); HP # long time optional - magma
            (-137/11 : 2/121*a + 63/11 : 1)

        AUTHORS:

        - Cameron Franc (2012-02-20)
        - Marc Masdeu (2012-02-20)
        """
        p = self.parent().prime()
        K = t1.parent()
        if mult:
            branch = 0

        R = PolynomialRing(K,'x')
        x = R.gen()
        R1 = LaurentSeriesRing(K,'r1')
        r1 = R1.gen()
        if E is None:
            E = self.parent()._source._BT.find_covering(t1,t2,level)
            print 'Got %s open balls.'%len(E)
        value = K(0)
        ii = 0
        value_exp = K(1)
        wt = self.parent()._U.weight()
        dim = self.parent()._U.dimension()
        if(method == 'riemann_sum'):
            R1.set_default_prec(wt+1)
            for e in E:
                ii += 1
                b = e[0,1]
                d = e[1,1]
                y = (b-d*t1)/(b-d*t2)
                pol = R1(y.log(branch = branch))
                c_e = self.evaluate(e)
                new = c_e.evaluate(pol)
                value += new
                if mult:
                    value_exp  *=  K.teichmuller(y)**Integer(c_e[0].rational_reconstruction())

        elif method == 'moments':
            R1.set_default_prec(dim)
            for e in E:
                ii += 1
                f = (x-t1)/(x-t2)
                a,b,c,d = e.list()
                y0 = f((a*r1+b)/(c*r1+d))
                pol = y0(0).log(branch = branch)+((y0.derivative()/y0).integral())
                if poly is not None:
                    pol *= poly(r1) #((r1-t1)**delta*(r1-t2)**(self.parent()._n-delta))
                c_e = self.evaluate(e)
                new = c_e.evaluate(pol)
                value += new
                if mult:
                    base = ((b-d*t1)/(b-d*t2))
                    pwr = ZZ(c_e[0].rational_reconstruction())
                    value_exp  *=  base**pwr
        else:
            print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should not be used in practice.'
            return False
        if mult:
            a = value_exp.valuation(p)
            print 'a=',a
            return p**a*K.teichmuller(p**(-a)*value_exp) * value.exp(prec = 2*dim) +O(p**(dim+a))
        return value +O(p**(dim+value.valuation(p)))
def epsinv(F, target, prec=53, target_tol=0.001, z=None, emb=None):
    """
    Compute a bound on the hyperbolic distance.

    The true minimum will be within the computed bound.
    It is computed as the inverse of epsilon_F from [HS2018]_.
    
    INPUT:

    - ``F`` -- binary form of degree at least 3 with no multiple roots

    - ``target`` --  positive real number. The value we want to attain, i.e.,
      the value we are taking the inverse of

    - ``prec``-- positive integer. precision to use in CC

    - ``target_tol`` -- positive real number. The tolerance with which we
      attain the target value.

    - ``z`` -- complex number. ``z_0`` covariant for F.

    - ``emb`` -- embedding into CC

    OUTPUT: a real number delta satisfying  target + target_tol > eps_F(delta) > target.

    EXAMPLES::

        sage: from sage.rings.polynomial.binary_form_reduce import epsinv
        sage: R.<x,y> = QQ[]
        sage: epsinv(-2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3, 31.5022020249597) # tol 1e-12
        4.02520895942207       
    """
    def coshdelta(z):
        #The cosh of the hyperbolic distance from z = t+uj to j
        return (z.norm() + 1) / (2 * z.imag())

    def RQ(delta):
        # this is the quotient R(F_0,z)/R(F_0,z(F)) for a generic z
        # at distance delta from j. See Lemma 4.2 in [HS2018].
        cd = cosh(delta).n(prec=prec)
        sd = sinh(delta).n(prec=prec)
        return prod(
            [cd + (cost * phi[0] + sint * phi[1]) * sd for phi in phis])

    def epsF(delta):
        pol = RQ(delta)  #get R quotient in terms of z
        S = PolynomialRing(C, 'v')
        g = S([(i - d) * pol[i - d]
               for i in range(2 * d + 1)])  # take derivative
        drts = [
            e for e in g.roots(ring=C, multiplicities=False)
            if (e.norm() - 1).abs() < 0.1
        ]
        # find min
        return min([pol(r / r.abs()).real() for r in drts])

    C = ComplexField(prec=prec)
    R = F.parent()
    d = F.degree()
    if z is None:
        z, th = covariant_z0(F, prec=prec, emb=emb)
    else:  #need to do our own input checking
        if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()):
            raise TypeError('must be a binary form')
        if d < 3:
            raise ValueError('must be at least degree 3')

    f = F.subs({R.gen(1): 1}).univariate_polynomial()
    #now we have a single variable polynomial
    if (max([ex for p,ex in f.roots(ring=C)]) >= QQ(d)/2)\
      or (f.degree() < QQ(d)/2):
        raise ValueError('cannot have root with multiplicity >= deg(F)/2')

    R = RealField(prec=prec)
    PR = PolynomialRing(R, 't')
    t = PR.gen(0)
    # compute phi_1, ..., phi_k
    # first find F_0 and its roots
    # this change of variables on f moves z(f) to j, i.e. produces F_0
    rts = f(z.imag() * t + z.real()).roots(ring=C)
    phis = []  # stereographic projection of roots
    for r, e in rts:
        phis.extend(
            [[2 * r.real() / (r.norm() + 1), (r.norm() - 1) / (r.norm() + 1)]])
    if d != f.degree():  # include roots at infinity
        phis.extend([(d - f.degree()) * [0, 1]])

    # for writing RQ in terms of generic z to minimize
    LC = LaurentSeriesRing(C, 'u', default_prec=2 * d + 2)
    u = LC.gen(0)
    cost = (u + u**(-1)) / 2
    sint = (u - u**(-1)) / (2 * C.gen(0))

    # first find an interval containing the desired value
    # then use regula falsi on log eps_F
    # d -> delta value in interval [0,1]
    # v in value in interval [1,epsF(1)]
    dl = R(0.0)
    vl = R(1.0)
    du = R(1.0)
    vu = epsF(du)
    while vu < target:
        # compute the next value of epsF for delta = 2*delta
        dl = du
        vl = vu
        du *= 2
        vu = epsF(du)
    # now dl < delta <= du
    logt = target.log()
    l2 = (vu.log() - logt).n(prec=prec)
    l1 = (vl.log() - logt).n(prec=prec)
    dn = (dl * l2 - du * l1) / (l2 - l1)
    vn = epsF(dn)
    dl = du
    vl = vu
    du = dn
    vu = vn
    while (du - dl).abs() >= target_tol or max(vl, vu) < target:
        l2 = (vu.log() - logt).n(prec=prec)
        l1 = (vl.log() - logt).n(prec=prec)
        dn = (dl * l2 - du * l1) / (l2 - l1)
        vn = epsF(dn)
        dl = du
        vl = vu
        du = dn
        vu = vn
    return max(dl, du)