Пример #1
0
def zeta__exact(n):
    r"""
    Returns the exact value of the Riemann Zeta function

    The argument must be a critical value, namely either positive even
    or negative odd.

    See for example [Iwasawa]_, p13, Special value of `\zeta(2k)`

    EXAMPLES:

    Let us test the accuracy for negative special values::

        sage: RR = RealField(100)
        sage: for i in range(1,10):
        ...       print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i))
        zeta(-1):  0.00000000000000000000000000000
        zeta(-3):  0.00000000000000000000000000000
        zeta(-5):  0.00000000000000000000000000000
        zeta(-7):  0.00000000000000000000000000000
        zeta(-9):  0.00000000000000000000000000000
        zeta(-11):  0.00000000000000000000000000000
        zeta(-13):  0.00000000000000000000000000000
        zeta(-15):  0.00000000000000000000000000000
        zeta(-17):  0.00000000000000000000000000000

    Let us test the accuracy for positive special values::

        sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10))
        True

    TESTS::

        sage: zeta__exact(5)
        Traceback (most recent call last):
        ...
        TypeError: n must be a critical value (i.e. even > 0 or odd < 0)

    REFERENCES:

    .. [Iwasawa] Iwasawa, *Lectures on p-adic L-functions*
    .. [IreRos] Ireland and Rosen, *A Classical Introduction to Modern Number Theory*
    .. [WashCyc] Washington, *Cyclotomic Fields*
    """
    if n < 0:
        return bernoulli(1 - n) / (n - 1)
    elif n > 1:
        if (n % 2 == 0):
            return ZZ(-1)**(n / 2 + 1) * ZZ(2)**(
                n - 1) * pi**n * bernoulli(n) / factorial(n)
        else:
            raise TypeError(
                "n must be a critical value (i.e. even > 0 or odd < 0)")
    elif n == 1:
        return infinity
    elif n == 0:
        return -1 / 2
Пример #2
0
def zeta__exact(n):
    r"""
    Returns the exact value of the Riemann Zeta function

    The argument must be a critical value, namely either positive even
    or negative odd.

    See for example [Iwasawa]_, p13, Special value of `\zeta(2k)`

    EXAMPLES:

    Let us test the accuracy for negative special values::

        sage: RR = RealField(100)
        sage: for i in range(1,10):
        ...       print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i))
        zeta(-1):  0.00000000000000000000000000000
        zeta(-3):  0.00000000000000000000000000000
        zeta(-5):  0.00000000000000000000000000000
        zeta(-7):  0.00000000000000000000000000000
        zeta(-9):  0.00000000000000000000000000000
        zeta(-11):  0.00000000000000000000000000000
        zeta(-13):  0.00000000000000000000000000000
        zeta(-15):  0.00000000000000000000000000000
        zeta(-17):  0.00000000000000000000000000000

    Let us test the accuracy for positive special values::

        sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10))
        True

    TESTS::

        sage: zeta__exact(5)
        Traceback (most recent call last):
        ...
        TypeError: n must be a critical value (i.e. even > 0 or odd < 0)

    REFERENCES:

    .. [Iwasawa] Iwasawa, *Lectures on p-adic L-functions*
    .. [IreRos] Ireland and Rosen, *A Classical Introduction to Modern Number Theory*
    .. [WashCyc] Washington, *Cyclotomic Fields*
    """
    if n < 0:
        return bernoulli(1-n)/(n-1)
    elif n > 1:
        if (n % 2 == 0):
            return ZZ(-1)**(n/2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n)
        else:
            raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)")
    elif n==1:
        return infinity
    elif n==0:
        return -1/2
Пример #3
0
def gritsenko_lift_subspace(N, weight, precision):
    """
    Return a list of data, which can be used by the Fourier expansion
    generator, for the space of Gritsenko lifts.
    
    INPUT:
        - `N`           -- the level of the paramodular group 
        - ``weight``    -- the weight of the space, that we consider
        - ``precision`` -- A precision class 
        
    NOTE:
        The lifts returned have to have integral Fourier coefficients.
    """
    jf = JacobiFormsD1NN(QQ, JacobiFormD1NN_Gamma(
        N,
        weight), (4 * N**2 + precision._enveloping_discriminant_bound() - 1) //
                         (4 * N) + 1)

    return Sequence([
        gritsenko_lift_fourier_expansion(
            g if i != 0 else (bernoulli(weight) /
                              (2 * weight)).denominator() * g, precision, True)
        for (i, g) in enumerate(jf.gens())
    ],
                    universe=ParamodularFormD2FourierExpansionRing(ZZ, N),
                    immutable=True,
                    check=False)
Пример #4
0
    def gritsenko_lift(self, f, k, is_integral=False):
        """
        INPUT:
            - `f` -- the Fourier expansion of a Jacobi form as a dictionary
        """
        N = self.level()
        frN = 4 * N
        p1list = self.precision()._p1list()

        divisor_dict = self._divisor_dict()

        ##TODO: Precalculate disc_coeffs or at least use a recursive definition
        disc_coeffs = dict()
        coeffs = dict()
        f_index = lambda d, b: ((d + b**2) // frN, b)

        for (
            ((a, b, c), l), eps, disc
        ) in self.__precision._iter_positive_forms_with_content_and_discriminant(
        ):
            (_, bp, _) = apply_GL_to_form(p1list[l], (a, b, c))
            try:
                coeffs[((a, b, c), l)] = disc_coeffs[(disc, bp, eps)]
            except KeyError:
                disc_coeffs[(disc, bp, eps)] = \
                    sum(t**(k-1) * f[ f_index(disc//t**2, (bp // t) % (2 * N)) ]
                           for t in divisor_dict[eps])

                if disc_coeffs[(disc, bp, eps)] != 0:
                    coeffs[((a, b, c), l)] = disc_coeffs[(disc, bp, eps)]

        for ((a, b, c), l) in self.__precision.iter_indefinite_forms():
            if l == 0:
                coeffs[((a, b, c), l)] = (
                    sigma(c, k - 1) * f[(0, 0)] if c != 0 else
                    (Integer(-bernoulli(k) / Integer(2 * k) *
                             f[(0, 0)]) if is_integral else -bernoulli(k) /
                     Integer(2 * k) * f[(0, 0)]))
            else:
                coeffs[((a, b, c), l)] = (
                    sigma(c // self.level(), k - 1) * f[(0, 0)] if c != 0 else
                    (Integer(-bernoulli(k) / Integer(2 * k) *
                             f[(0, 0)]) if is_integral else -bernoulli(k) /
                     Integer(2 * k) * f[(0, 0)]))

        return coeffs
    def gritsenko_lift(self, f, k, is_integral = False) :
        """
        INPUT:
            - `f` -- the Fourier expansion of a Jacobi form as a dictionary
        """
        N = self.level()
        frN = 4 * N
        p1list = self.precision()._p1list()

        divisor_dict = self._divisor_dict()
        
        ##TODO: Precalculate disc_coeffs or at least use a recursive definition
        disc_coeffs = dict()
        coeffs = dict()
        f_index = lambda d,b : ((d + b**2)//frN, b)
        
        for (((a,b,c),l), eps, disc) in self.__precision._iter_positive_forms_with_content_and_discriminant() :
            (_,bp,_) = apply_GL_to_form(p1list[l], (a,b,c))
            try :
                coeffs[((a,b,c),l)] = disc_coeffs[(disc, bp, eps)]
            except KeyError :
                disc_coeffs[(disc, bp, eps)] = \
                    sum(   t**(k-1) * f[ f_index(disc//t**2, (bp // t) % (2 * N)) ]
                           for t in divisor_dict[eps] )
 
                if disc_coeffs[(disc, bp, eps)]  != 0 :
                    coeffs[((a,b,c),l)] = disc_coeffs[(disc, bp, eps)]

        for ((a,b,c), l) in self.__precision.iter_indefinite_forms() :
            if l == 0 :
                coeffs[((a,b,c),l)] = ( sigma(c, k-1) * f[(0,0)]
                                        if c != 0 else 
                                         ( Integer(-bernoulli(k) / Integer(2 * k) * f[(0,0)])
                                           if is_integral else
                                           -bernoulli(k) / Integer(2 * k) * f[(0,0)] ) )
            else :
                coeffs[((a,b,c),l)] = ( sigma(c//self.level(), k-1) * f[(0,0)]
                                        if c != 0 else 
                                         ( Integer(-bernoulli(k) / Integer(2 * k) * f[(0,0)])
                                           if is_integral else
                                           -bernoulli(k) / Integer(2 * k) * f[(0,0)] ) )
        
        return coeffs
    def _log_StirlingNegativePowers_(var, precision):
        r"""
        Helper function to calculate the logarithm of Stirling's approximation
        formula from the negative powers of ``var`` on, i.e., it skips the
        summands `n \log n - n + (\log n)/2 + \log(2\pi)/2`.

        INPUT:

        - ``var`` -- a string for the variable name.

        - ``precision`` -- an integer specifying the number of exact summands.
          If this is negative, then the result is `0`.

        OUTPUT:

        An asymptotic expansion.

        TESTS::

            sage: asymptotic_expansions._log_StirlingNegativePowers_(
            ....:     'm', precision=-1)
            0
            sage: asymptotic_expansions._log_StirlingNegativePowers_(
            ....:     'm', precision=0)
            O(m^(-1))
            sage: asymptotic_expansions._log_StirlingNegativePowers_(
            ....:     'm', precision=3)
            1/12*m^(-1) - 1/360*m^(-3) + 1/1260*m^(-5) + O(m^(-7))
            sage: _.parent()
            Asymptotic Ring <m^ZZ> over Rational Field
        """
        from asymptotic_ring import AsymptoticRing
        from sage.rings.rational_field import QQ

        A = AsymptoticRing(growth_group='{n}^ZZ'.format(n=var),
                           coefficient_ring=QQ)
        if precision < 0:
            return A.zero()
        n = A.gen()

        from sage.arith.all import bernoulli
        from sage.arith.srange import srange

        result = sum((bernoulli(k) / k / (k-1) / n**(k-1)
                      for k in srange(2, 2*precision + 2, 2)),
                     A.zero())
        return result + (1 / n**(2*precision + 1)).O()
    def _log_StirlingNegativePowers_(var, precision):
        r"""
        Helper function to calculate the logarithm of Stirling's approximation
        formula from the negative powers of ``var`` on, i.e., it skips the
        summands `n \log n - n + (\log n)/2 + \log(2\pi)/2`.

        INPUT:

        - ``var`` -- a string for the variable name.

        - ``precision`` -- an integer specifying the number of exact summands.
          If this is negative, then the result is `0`.

        OUTPUT:

        An asymptotic expansion.

        TESTS::

            sage: asymptotic_expansions._log_StirlingNegativePowers_(
            ....:     'm', precision=-1)
            0
            sage: asymptotic_expansions._log_StirlingNegativePowers_(
            ....:     'm', precision=0)
            O(m^(-1))
            sage: asymptotic_expansions._log_StirlingNegativePowers_(
            ....:     'm', precision=3)
            1/12*m^(-1) - 1/360*m^(-3) + 1/1260*m^(-5) + O(m^(-7))
            sage: _.parent()
            Asymptotic Ring <m^ZZ> over Rational Field
        """
        from asymptotic_ring import AsymptoticRing
        from sage.rings.rational_field import QQ

        A = AsymptoticRing(growth_group='{n}^ZZ'.format(n=var),
                           coefficient_ring=QQ)
        if precision < 0:
            return A.zero()
        n = A.gen()

        from sage.arith.all import bernoulli
        from sage.arith.srange import srange

        result = sum((bernoulli(k) / k / (k - 1) / n**(k - 1)
                      for k in srange(2, 2 * precision + 2, 2)), A.zero())
        return result + (1 / n**(2 * precision + 1)).O()
    def __maass_lifts(self, k, precision, return_value) :
        r"""
        Return the Fourier expansion of all Maass forms of weight `k`.
        """
        result = []
        
        if k < 4 or k % 2 != 0 :
            return []
                
        mf = ModularForms(1,k).echelon_basis()
        cf = ModularForms(1,k + 2).echelon_basis()[1:]
        integrality_factor = 2*k * bernoulli(k).denominator()

        for c in [(integrality_factor * mf[0],0)] \
                     + [ (f,0) for f in mf[1:] ] + [ (0,g) for g in cf ] :
            if return_value == "lifts" :
                result.append(SiegelModularFormG2MaassLift(c[0],c[1], precision, True))
            else :
                result.append(c)
        
        return result
def gritsenko_lift_subspace(N, weight, precision) :
    """
    Return a list of data, which can be used by the Fourier expansion
    generator, for the space of Gritsenko lifts.
    
    INPUT:
        - `N`           -- the level of the paramodular group 
        - ``weight``    -- the weight of the space, that we consider
        - ``precision`` -- A precision class 
        
    NOTE:
        The lifts returned have to have integral Fourier coefficients.
    """
    jf = JacobiFormsD1NN( QQ, JacobiFormD1NN_Gamma(N, weight),
                          (4 * N**2 + precision._enveloping_discriminant_bound() - 1)//(4 * N) + 1)

    return Sequence( [ gritsenko_lift_fourier_expansion( g if i != 0 else (bernoulli(weight) / (2 * weight)).denominator() * g,
                                                         precision, True )
                       for (i,g) in enumerate(jf.gens()) ],
                       universe = ParamodularFormD2FourierExpansionRing(ZZ, N), immutable = True,
                       check = False )
Пример #10
0
        def coeff(m):
            m = ZZ(m)
            if m < 0:
                return ZZ(0)
            elif m == 0:
                return ZZ(1)

            factor = -2*k / QQ(bernoulli(k)) / lamk
            sum1   = sigma(m, k-1)
            if M.divides(m):
                sum2 = (lamk-1) * sigma(ZZ(m/M), k-1)
            else:
                sum2 = ZZ(0)
            if (M == 1):
                sum3 = ZZ(0)
            else:
                if (m == 1):
                    N = ZZ(1)
                else:
                    N = ZZ(m / M**ZZ(m.valuation(M)))
                sum3 = -sigma(ZZ(N), k-1) * ZZ(m/N)**(k-1) / (lamk + 1)

            return factor * (sum1 + sum2 + sum3) * dval**m
Пример #11
0
        def coeff(m):
            m = ZZ(m)
            if m < 0:
                return ZZ(0)
            elif m == 0:
                return ZZ(1)

            factor = -2 * k / QQ(bernoulli(k)) / lamk
            sum1 = sigma(m, k - 1)
            if M.divides(m):
                sum2 = (lamk - 1) * sigma(ZZ(m / M), k - 1)
            else:
                sum2 = ZZ(0)
            if (M == 1):
                sum3 = ZZ(0)
            else:
                if (m == 1):
                    N = ZZ(1)
                else:
                    N = ZZ(m / M**ZZ(m.valuation(M)))
                sum3 = -sigma(ZZ(N), k - 1) * ZZ(m / N)**(k - 1) / (lamk + 1)

            return factor * (sum1 + sum2 + sum3) * dval**m
Пример #12
0
def zeta__exact(n):
    r"""
    Returns the exact value of the Riemann Zeta function

    The argument must be a critical value, namely either positive even
    or negative odd.

    See for example [Iwa1972]_, p13, Special value of `\zeta(2k)`

    EXAMPLES:

    Let us test the accuracy for negative special values::

        sage: RR = RealField(100)
        sage: for i in range(1,10):
        ....:     print("zeta({}): {}".format(1-2*i, RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i))))
        zeta(-1): 0.00000000000000000000000000000
        zeta(-3): 0.00000000000000000000000000000
        zeta(-5): 0.00000000000000000000000000000
        zeta(-7): 0.00000000000000000000000000000
        zeta(-9): 0.00000000000000000000000000000
        zeta(-11): 0.00000000000000000000000000000
        zeta(-13): 0.00000000000000000000000000000
        zeta(-15): 0.00000000000000000000000000000
        zeta(-17): 0.00000000000000000000000000000

    Let us test the accuracy for positive special values::

        sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10))
        True

    TESTS::

        sage: zeta__exact(4)
        1/90*pi^4
        sage: zeta__exact(-3)
        1/120
        sage: zeta__exact(0)
        -1/2
        sage: zeta__exact(5)
        Traceback (most recent call last):
        ...
        TypeError: n must be a critical value (i.e. even > 0 or odd < 0)

    REFERENCES:

    - [Iwa1972]_
    - [IR1990]_
    - [Was1997]_
    """
    if n < 0:
        return bernoulli(1 - n) / (n - 1)
    elif n > 1:
        if (n % 2 == 0):
            return ZZ(-1)**(n // 2 + 1) * ZZ(2)**(
                n - 1) * pi**n * bernoulli(n) / factorial(n)
        else:
            raise TypeError(
                "n must be a critical value (i.e. even > 0 or odd < 0)")
    elif n == 1:
        return infinity
    elif n == 0:
        return QQ((-1, 2))
Пример #13
0
def eisenstein_series_qexp(k, prec = 10, K=QQ, var='q', normalization='linear'):
    r"""
    Return the `q`-expansion of the normalized weight `k` Eisenstein series on
    `{\rm SL}_2(\ZZ)` to precision prec in the ring `K`. Three normalizations
    are available, depending on the parameter ``normalization``; the default
    normalization is the one for which the linear coefficient is 1.

    INPUT:

    - ``k`` - an even positive integer

    - ``prec`` - (default: 10) a nonnegative integer

    - ``K`` - (default: `\QQ`) a ring

    - ``var`` - (default: ``'q'``) variable name to use for q-expansion

    - ``normalization`` - (default: ``'linear'``) normalization to use. If this
      is ``'linear'``, then the series will be normalized so that the linear
      term is 1. If it is ``'constant'``, the series will be normalized to have
      constant term 1. If it is ``'integral'``, then the series will be
      normalized to have integer coefficients and no common factor, and linear
      term that is positive. Note that ``'integral'`` will work over arbitrary
      base rings, while ``'linear'`` or ``'constant'`` will fail if the
      denominator (resp. numerator) of `B_k / 2k` is invertible.

    ALGORITHM:

        We know `E_k = \text{constant} + \sum_n \sigma_{k-1}(n) q^n`. So we
        compute all the `\sigma_{k-1}(n)` simultaneously, using the fact that
        `\sigma` is multiplicative.

    EXAMPLES::

        sage: eisenstein_series_qexp(2,5)
        -1/24 + q + 3*q^2 + 4*q^3 + 7*q^4 + O(q^5)
        sage: eisenstein_series_qexp(2,0)
        O(q^0)
        sage: eisenstein_series_qexp(2,5,GF(7))
        2 + q + 3*q^2 + 4*q^3 + O(q^5)
        sage: eisenstein_series_qexp(2,5,GF(7),var='T')
        2 + T + 3*T^2 + 4*T^3 + O(T^5)

    We illustrate the use of the ``normalization`` parameter::

        sage: eisenstein_series_qexp(12, 5, normalization='integral')
        691 + 65520*q + 134250480*q^2 + 11606736960*q^3 + 274945048560*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, normalization='constant')
        1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, normalization='linear')
        691/65520 + q + 2049*q^2 + 177148*q^3 + 4196353*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 50, K=GF(13), normalization="constant")
        1 + O(q^50)

    TESTS:

    Test that :trac:`5102` is fixed::

        sage: eisenstein_series_qexp(10, 30, GF(17))
        15 + q + 3*q^2 + 15*q^3 + 7*q^4 + 13*q^5 + 11*q^6 + 11*q^7 + 15*q^8 + 7*q^9 + 5*q^10 + 7*q^11 + 3*q^12 + 14*q^13 + 16*q^14 + 8*q^15 + 14*q^16 + q^17 + 4*q^18 + 3*q^19 + 6*q^20 + 12*q^21 + 4*q^22 + 12*q^23 + 4*q^24 + 4*q^25 + 8*q^26 + 14*q^27 + 9*q^28 + 6*q^29 + O(q^30)

    This shows that the bug reported at :trac:`8291` is fixed::

        sage: eisenstein_series_qexp(26, 10, GF(13))
        7 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + 12*q^6 + 8*q^7 + 2*q^8 + O(q^10)

    We check that the function behaves properly over finite-characteristic base rings::

        sage: eisenstein_series_qexp(12, 5, K = Zmod(691), normalization="integral")
        566*q + 236*q^2 + 286*q^3 + 194*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, K = Zmod(691), normalization="constant")
        Traceback (most recent call last):
        ...
        ValueError: The numerator of -B_k/(2*k) (=691) must be invertible in the ring Ring of integers modulo 691
        sage: eisenstein_series_qexp(12, 5, K = Zmod(691), normalization="linear")
        q + 667*q^2 + 252*q^3 + 601*q^4 + O(q^5)

        sage: eisenstein_series_qexp(12, 5, K = Zmod(2), normalization="integral")
        1 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, K = Zmod(2), normalization="constant")
        1 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, K = Zmod(2), normalization="linear")
        Traceback (most recent call last):
        ...
        ValueError: The denominator of -B_k/(2*k) (=65520) must be invertible in the ring Ring of integers modulo 2

    AUTHORS:

    - William Stein: original implementation

    - Craig Citro (2007-06-01): rewrote for massive speedup

    - Martin Raum (2009-08-02): port to cython for speedup

    - David Loeffler (2010-04-07): work around an integer overflow when `k` is large

    - David Loeffler (2012-03-15): add options for alternative normalizations
      (motivated by :trac:`12043`)
    """
    ## we use this to prevent computation if it would fail anyway.
    if k <= 0 or k % 2 == 1 :
        raise ValueError("k must be positive and even")

    a0 = - bernoulli(k) / (2*k)

    if normalization == 'linear':
        a0den = a0.denominator()
        try:
            a0fac = K(1/a0den)
        except ZeroDivisionError:
            raise ValueError("The denominator of -B_k/(2*k) (=%s) must be invertible in the ring %s"%(a0den, K))
    elif normalization == 'constant':
        a0num = a0.numerator()
        try:
            a0fac = K(1/a0num)
        except ZeroDivisionError:
            raise ValueError("The numerator of -B_k/(2*k) (=%s) must be invertible in the ring %s"%(a0num, K))
    elif normalization == 'integral':
        a0fac = None
    else:
        raise ValueError("Normalization (=%s) must be one of 'linear', 'constant', 'integral'" % normalization)

    R = PowerSeriesRing(K, var)
    if K == QQ and normalization == 'linear':
        ls = Ek_ZZ(k, prec)
        # The following is *dramatically* faster than doing the more natural
        # "R(ls)" would be:
        E = ZZ[var](ls, prec=prec, check=False).change_ring(QQ)
        if len(ls)>0:
            E._unsafe_mutate(0, a0)
        return R(E, prec)
        # The following is an older slower alternative to the above three lines:
        #return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=False)
    else:
        # This used to work with check=False, but that can only be regarded as
        # an improbable lucky miracle. Enabling checking is a noticeable speed
        # regression; the morally right fix would be to expose FLINT's
        # fmpz_poly_to_nmod_poly command (at least for word-sized N).
        if a0fac is not None:
            return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True)
        else:
            return R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True)
Пример #14
0
def eisenstein_series_lseries(weight, prec=53,
               max_imaginary_part=0,
               max_asymp_coeffs=40):
    r"""
    Return the L-series of the weight `2k` Eisenstein series
    on `\mathrm{SL}_2(\ZZ)`.

    This actually returns an interface to Tim Dokchitser's program
    for computing with the L-series of the Eisenstein series

    INPUT:

    - ``weight`` - even integer

    - ``prec`` - integer (bits precision)

    - ``max_imaginary_part`` - real number

    - ``max_asymp_coeffs`` - integer

    OUTPUT:

    The L-series of the Eisenstein series.

    EXAMPLES:

    We compute with the L-series of `E_{16}` and then `E_{20}`::

       sage: L = eisenstein_series_lseries(16)
       sage: L(1)
       -0.291657724743874
       sage: L = eisenstein_series_lseries(20)
       sage: L(2)
       -5.02355351645998

    Now with higher precision::

        sage: L = eisenstein_series_lseries(20, prec=200)
        sage: L(2)
        -5.0235535164599797471968418348135050804419155747868718371029
    """
    f = eisenstein_series_qexp(weight,prec)
    from sage.lfunctions.all import Dokchitser
    from sage.symbolic.constants import pi
    key = (prec, max_imaginary_part, max_asymp_coeffs)
    j = weight
    L = Dokchitser(conductor = 1,
                   gammaV = [0,1],
                   weight = j,
                   eps = (-1)**Integer(j/2),
                   poles = [j],
                   # Using a string for residues is a hack but it works well
                   # since this will make PARI/GP compute sqrt(pi) with the
                   # right precision.
                   residues = '[sqrt(Pi)*(%s)]'%((-1)**Integer(j/2)*bernoulli(j)/j),
                   prec = prec)

    s = 'coeff = %s;'%f.list()
    L.init_coeffs('coeff[k+1]',pari_precode = s,
                  max_imaginary_part=max_imaginary_part,
                  max_asymp_coeffs=max_asymp_coeffs)
    L.check_functional_equation()
    L.rename('L-series associated to the weight %s Eisenstein series %s on SL_2(Z)'%(j,f))
    return L
Пример #15
0
def eisenstein_series_qexp(k, prec = 10, K=QQ, var='q', normalization='linear'):
    r"""
    Return the `q`-expansion of the normalized weight `k` Eisenstein series on
    `{\rm SL}_2(\ZZ)` to precision prec in the ring `K`. Three normalizations
    are available, depending on the parameter ``normalization``; the default
    normalization is the one for which the linear coefficient is 1.

    INPUT:

    - ``k`` - an even positive integer

    - ``prec`` - (default: 10) a nonnegative integer

    - ``K`` - (default: `\QQ`) a ring

    - ``var`` - (default: ``'q'``) variable name to use for q-expansion

    - ``normalization`` - (default: ``'linear'``) normalization to use. If this
      is ``'linear'``, then the series will be normalized so that the linear
      term is 1. If it is ``'constant'``, the series will be normalized to have
      constant term 1. If it is ``'integral'``, then the series will be
      normalized to have integer coefficients and no common factor, and linear
      term that is positive. Note that ``'integral'`` will work over arbitrary
      base rings, while ``'linear'`` or ``'constant'`` will fail if the
      denominator (resp. numerator) of `B_k / 2k` is invertible.

    ALGORITHM:

        We know `E_k = \text{constant} + \sum_n \sigma_{k-1}(n) q^n`. So we
        compute all the `\sigma_{k-1}(n)` simultaneously, using the fact that
        `\sigma` is multiplicative.

    EXAMPLES::

        sage: eisenstein_series_qexp(2,5)
        -1/24 + q + 3*q^2 + 4*q^3 + 7*q^4 + O(q^5)
        sage: eisenstein_series_qexp(2,0)
        O(q^0)
        sage: eisenstein_series_qexp(2,5,GF(7))
        2 + q + 3*q^2 + 4*q^3 + O(q^5)
        sage: eisenstein_series_qexp(2,5,GF(7),var='T')
        2 + T + 3*T^2 + 4*T^3 + O(T^5)

    We illustrate the use of the ``normalization`` parameter::

        sage: eisenstein_series_qexp(12, 5, normalization='integral')
        691 + 65520*q + 134250480*q^2 + 11606736960*q^3 + 274945048560*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, normalization='constant')
        1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, normalization='linear')
        691/65520 + q + 2049*q^2 + 177148*q^3 + 4196353*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 50, K=GF(13), normalization="constant")
        1 + O(q^50)

    TESTS:

    Test that :trac:`5102` is fixed::

        sage: eisenstein_series_qexp(10, 30, GF(17))
        15 + q + 3*q^2 + 15*q^3 + 7*q^4 + 13*q^5 + 11*q^6 + 11*q^7 + 15*q^8 + 7*q^9 + 5*q^10 + 7*q^11 + 3*q^12 + 14*q^13 + 16*q^14 + 8*q^15 + 14*q^16 + q^17 + 4*q^18 + 3*q^19 + 6*q^20 + 12*q^21 + 4*q^22 + 12*q^23 + 4*q^24 + 4*q^25 + 8*q^26 + 14*q^27 + 9*q^28 + 6*q^29 + O(q^30)

    This shows that the bug reported at :trac:`8291` is fixed::

        sage: eisenstein_series_qexp(26, 10, GF(13))
        7 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + 12*q^6 + 8*q^7 + 2*q^8 + O(q^10)

    We check that the function behaves properly over finite-characteristic base rings::

        sage: eisenstein_series_qexp(12, 5, K = Zmod(691), normalization="integral")
        566*q + 236*q^2 + 286*q^3 + 194*q^4 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, K = Zmod(691), normalization="constant")
        Traceback (most recent call last):
        ...
        ValueError: The numerator of -B_k/(2*k) (=691) must be invertible in the ring Ring of integers modulo 691
        sage: eisenstein_series_qexp(12, 5, K = Zmod(691), normalization="linear")
        q + 667*q^2 + 252*q^3 + 601*q^4 + O(q^5)

        sage: eisenstein_series_qexp(12, 5, K = Zmod(2), normalization="integral")
        1 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, K = Zmod(2), normalization="constant")
        1 + O(q^5)
        sage: eisenstein_series_qexp(12, 5, K = Zmod(2), normalization="linear")
        Traceback (most recent call last):
        ...
        ValueError: The denominator of -B_k/(2*k) (=65520) must be invertible in the ring Ring of integers modulo 2

    AUTHORS:

    - William Stein: original implementation

    - Craig Citro (2007-06-01): rewrote for massive speedup

    - Martin Raum (2009-08-02): port to cython for speedup

    - David Loeffler (2010-04-07): work around an integer overflow when `k` is large

    - David Loeffler (2012-03-15): add options for alternative normalizations
      (motivated by :trac:`12043`)
    """
    ## we use this to prevent computation if it would fail anyway.
    if k <= 0 or k % 2 == 1 :
        raise ValueError("k must be positive and even")

    a0 = - bernoulli(k) / (2*k)

    if normalization == 'linear':
        a0den = a0.denominator()
        try:
            a0fac = K(1/a0den)
        except ZeroDivisionError:
            raise ValueError("The denominator of -B_k/(2*k) (=%s) must be invertible in the ring %s"%(a0den, K))
    elif normalization == 'constant':
        a0num = a0.numerator()
        try:
            a0fac = K(1/a0num)
        except ZeroDivisionError:
            raise ValueError("The numerator of -B_k/(2*k) (=%s) must be invertible in the ring %s"%(a0num, K))
    elif normalization == 'integral':
        a0fac = None
    else:
        raise ValueError("Normalization (=%s) must be one of 'linear', 'constant', 'integral'" % normalization)

    R = PowerSeriesRing(K, var)
    if K == QQ and normalization == 'linear':
        ls = Ek_ZZ(k, prec)
        # The following is *dramatically* faster than doing the more natural
        # "R(ls)" would be:
        E = ZZ[var](ls, prec=prec, check=False).change_ring(QQ)
        if len(ls)>0:
            E._unsafe_mutate(0, a0)
        return R(E, prec)
        # The following is an older slower alternative to the above three lines:
        #return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=False)
    else:
        # This used to work with check=False, but that can only be regarded as
        # an improbable lucky miracle. Enabling checking is a noticeable speed
        # regression; the morally right fix would be to expose FLINT's
        # fmpz_poly_to_nmod_poly command (at least for word-sized N).
        if a0fac is not None:
            return a0fac*R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True)
        else:
            return R(eisenstein_series_poly(k, prec).list(), prec=prec, check=True)
Пример #16
0
def eisenstein_series_lseries(weight, prec=53,
               max_imaginary_part=0,
               max_asymp_coeffs=40):
    r"""
    Return the L-series of the weight `2k` Eisenstein series
    on `\mathrm{SL}_2(\ZZ)`.

    This actually returns an interface to Tim Dokchitser's program
    for computing with the L-series of the Eisenstein series

    INPUT:

    - ``weight`` - even integer

    - ``prec`` - integer (bits precision)

    - ``max_imaginary_part`` - real number

    - ``max_asymp_coeffs`` - integer

    OUTPUT:

    The L-series of the Eisenstein series.

    EXAMPLES:

    We compute with the L-series of `E_{16}` and then `E_{20}`::

       sage: L = eisenstein_series_lseries(16)
       sage: L(1)
       -0.291657724743874
       sage: L = eisenstein_series_lseries(20)
       sage: L(2)
       -5.02355351645998

    Now with higher precision::

        sage: L = eisenstein_series_lseries(20, prec=200)
        sage: L(2)
        -5.0235535164599797471968418348135050804419155747868718371029
    """
    f = eisenstein_series_qexp(weight,prec)
    from sage.lfunctions.all import Dokchitser
    j = weight
    L = Dokchitser(conductor = 1,
                   gammaV = [0,1],
                   weight = j,
                   eps = (-1)**Integer(j/2),
                   poles = [j],
                   # Using a string for residues is a hack but it works well
                   # since this will make PARI/GP compute sqrt(pi) with the
                   # right precision.
                   residues = '[sqrt(Pi)*(%s)]'%((-1)**Integer(j/2)*bernoulli(j)/j),
                   prec = prec)

    s = 'coeff = %s;'%f.list()
    L.init_coeffs('coeff[k+1]',pari_precode = s,
                  max_imaginary_part=max_imaginary_part,
                  max_asymp_coeffs=max_asymp_coeffs)
    L.check_functional_equation()
    L.rename('L-series associated to the weight %s Eisenstein series %s on SL_2(Z)'%(j,f))
    return L
def siegel_product(self, u):
    """
    Computes the infinite product of local densities of the quadratic
    form for the number `u`.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1])
        sage: Q.theta_series(11)
        1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 + O(q^11)

        sage: Q.siegel_product(1)
        8
        sage: Q.siegel_product(2)      ## This one is wrong -- expect 24, and the higher powers of 2 don't work... =(
        24
        sage: Q.siegel_product(3)
        32
        sage: Q.siegel_product(5)
        48
        sage: Q.siegel_product(6)
        96
        sage: Q.siegel_product(7)
        64
        sage: Q.siegel_product(9)
        104

        sage: Q.local_density(2,1)
        1
        sage: M = 4; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 1]) / M^3
        1
        sage: M = 16; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 1]) / M^3  # long time (2s on sage.math, 2014)
        1

        sage: Q.local_density(2,2)
        3/2
        sage: M = 4; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 2]) / M^3
        3/2
        sage: M = 16; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 2]) / M^3  # long time (2s on sage.math, 2014)
        3/2

    TESTS::

        sage: [1] + [Q.siegel_product(ZZ(a))  for a in range(1,11)] == Q.theta_series(11).list()  # long time (2s on sage.math, 2014)
        True
    """
    ## Protect u (since it fails often if it's an just an int!)
    u = ZZ(u)

    n = self.dim()
    d = self.det(
    )  ## ??? Warning: This is a factor of 2^n larger than it should be!

    # DIAGNOSTIC
    verbose("n = " + str(n))
    verbose("d = " + str(d))
    verbose("In siegel_product:  d = " + str(d) + "\n")

    ## Product of "bad" places to omit
    S = 2 * d * u

    ## DIAGNOSTIC
    verbose("siegel_product Break 1. \n")
    verbose(" u = " + str(u) + "\n")

    ## Make the odd generic factors
    if ((n % 2) == 1):
        m = (n - 1) // 2
        d1 = fundamental_discriminant(
            ((-1)**m) * 2 * d *
            u)  ## Replaced d by 2d here to compensate for the determinant
        f = abs(
            d1)  ## gaining an odd power of 2 by using the matrix of 2Q instead
        ## of the matrix of Q.
        ##  --> Old d1 = CoreDiscriminant((mpz_class(-1)^m) * d * u);

        ## Make the ratio of factorials factor: [(2m)! / m!] * prod_{i=1}^m (2*i-1)
        factor1 = 1
        for i in range(1, m + 1):
            factor1 *= 2 * i - 1
        for i in range(m + 1, 2 * m + 1):
            factor1 *= i

        genericfactor = factor1 * ((u / f) ** m) \
            * QQ(sqrt((2 ** n) *  f) / (u * d)) \
            * abs(QuadraticBernoulliNumber(m, d1) / bernoulli(2*m))

    ## DIAGNOSTIC
    verbose("siegel_product Break 2. \n")

    ## Make the even generic factor
    if ((n % 2) == 0):
        m = n // 2
        d1 = fundamental_discriminant(((-1)**m) * d)
        f = abs(d1)

        ## DIAGNOSTIC
        #cout << " mpz_class(-1)^m = " << (mpz_class(-1)^m) << " and d = " << d << endl;
        #cout << " f = " << f << " and d1 = " << d1 << endl;


        genericfactor = m / QQ(sqrt(f*d)) \
            * ((u/2) ** (m-1)) * (f ** m) \
            / abs(QuadraticBernoulliNumber(m, d1)) \
            * (2 ** m)                                               ## This last factor compensates for using the matrix of 2*Q

    ##return genericfactor

    ## Omit the generic factors in S and compute them separately
    omit = 1
    include = 1

    S_divisors = prime_divisors(S)

    ## DIAGNOSTIC
    #cout << "\n S is " << S << endl;
    #cout << " The Prime divisors of S are :";
    #PrintV(S_divisors);

    for p in S_divisors:
        Q_normal = self.local_normal_form(p)

        ## DIAGNOSTIC
        verbose(" p = " + str(p) + " and its Kronecker symbol (d1/p) = (" +
                str(d1) + "/" + str(p) + ") is " +
                str(kronecker_symbol(d1, p)) + "\n")

        omit *= 1 / (1 - (kronecker_symbol(d1, p) / (p**m)))

        ## DIAGNOSTIC
        verbose(" omit = " + str(omit) + "\n")
        verbose(" Q_normal is \n" + str(Q_normal) + "\n")
        verbose(" Q_normal = \n" + str(Q_normal))
        verbose(" p = " + str(p) + "\n")
        verbose(" u = " + str(u) + "\n")
        verbose(" include = " + str(include) + "\n")

        include *= Q_normal.local_density(p, u)

        ## DIAGNOSTIC
        #cout << " Including the p = " << p << " factor: " << local_density(Q_normal, p, u) << endl;

        ## DIAGNOSTIC
        verbose("    ---  Exiting loop \n")

    #// ****************  Important *******************
    #// Additional fix (only included for n=4) to deal
    #// with the power of 2 introduced at the real place
    #// by working with Q instead of 2*Q.  This needs to
    #// be done for all other n as well...
    #/*
    #if (n==4)
    #  genericfactor = 4 * genericfactor;
    #*/

    ## DIAGNOSTIC
    #cout << endl;
    #cout << " generic factor = " << genericfactor << endl;
    #cout << " omit = " << omit << endl;
    #cout << " include = " << include << endl;
    #cout << endl;

    ## DIAGNOSTIC
    #//  cout << "siegel_product Break 3. " << endl;

    ## Return the final factor (and divide by 2 if n=2)
    if n == 2:
        return genericfactor * omit * include / 2
    else:
        return genericfactor * omit * include
    def HarmonicNumber(var, precision=None, skip_constant_summand=False):
        r"""
        Return the asymptotic expansion of a harmonic number.

        INPUT:

        - ``var`` -- a string for the variable name.

        - ``precision`` -- (default: ``None``) an integer. If ``None``, then
          the default precision of the asymptotic ring is used.

        - ``skip_constant_summand`` -- (default: ``False``) a
          boolean. If set, then the constant summand ``euler_gamma`` is left out.
          As a consequence, the coefficient ring of the output changes
          from ``Symbolic Constants Subring`` (if ``False``) to
          ``Rational Field`` (if ``True``).

        OUTPUT:

        An asymptotic expansion.

        EXAMPLES::

            sage: asymptotic_expansions.HarmonicNumber('n', precision=5)
            log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6))

        TESTS::

            sage: ex = asymptotic_expansions.HarmonicNumber('n', precision=5)
            sage: n = ex.parent().gen()
            sage: ex.compare_with_values(n,                      # rel tol 1e-6
            ....:      lambda x: sum(1/k for k in srange(1, x+1)), [5, 10, 20])
            [(5, 0.0038125360?), (10, 0.00392733?), (20, 0.0039579?)]
            sage: asymptotic_expansions.HarmonicNumber('n')
            log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4)
            - 1/252*n^(-6) + 1/240*n^(-8) - 1/132*n^(-10)
            + 691/32760*n^(-12) - 1/12*n^(-14) + 3617/8160*n^(-16)
            - 43867/14364*n^(-18) + 174611/6600*n^(-20) - 77683/276*n^(-22)
            + 236364091/65520*n^(-24) - 657931/12*n^(-26)
            + 3392780147/3480*n^(-28) - 1723168255201/85932*n^(-30)
            + 7709321041217/16320*n^(-32)
            - 151628697551/12*n^(-34) + O(n^(-36))
            sage: _.parent()
            Asymptotic Ring <n^ZZ * log(n)^ZZ> over Symbolic Constants Subring

        ::

            sage: asymptotic_expansions.HarmonicNumber(
            ....:     'n', precision=5, skip_constant_summand=True)
            log(n) + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6))
            sage: _.parent()
            Asymptotic Ring <n^ZZ * log(n)^ZZ> over Rational Field
            sage: for p in range(5):
            ....:     print asymptotic_expansions.HarmonicNumber(
            ....:         'n', precision=p)
            O(log(n))
            log(n) + O(1)
            log(n) + euler_gamma + O(n^(-1))
            log(n) + euler_gamma + 1/2*n^(-1) + O(n^(-2))
            log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + O(n^(-4))
            sage: asymptotic_expansions.HarmonicNumber('m', precision=5)
            log(m) + euler_gamma + 1/2*m^(-1) - 1/12*m^(-2) + 1/120*m^(-4) + O(m^(-6))
        """
        if not skip_constant_summand:
            from sage.symbolic.ring import SR
            coefficient_ring = SR.subring(no_variables=True)
        else:
            from sage.rings.rational_field import QQ
            coefficient_ring = QQ

        from asymptotic_ring import AsymptoticRing
        A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var),
                           coefficient_ring=coefficient_ring)
        n = A.gen()

        if precision is None:
            precision = A.default_prec

        from sage.functions.log import log
        result = A.zero()
        if precision >= 1:
            result += log(n)
        if precision >= 2 and not skip_constant_summand:
            from sage.symbolic.constants import euler_gamma
            result += coefficient_ring(euler_gamma)
        if precision >= 3:
            result += 1 / (2 * n)

        from sage.arith.srange import srange
        from sage.arith.all import bernoulli
        for k in srange(2, 2 * precision - 4, 2):
            result += -bernoulli(k) / k / n**k

        if precision < 1:
            result += (log(n)).O()
        elif precision == 1:
            result += A(1).O()
        elif precision == 2:
            result += (1 / n).O()
        else:
            result += (1 / n**(2 * precision - 4)).O()

        return result
    def maass_form( self, f, g, k = None, is_integral = False) :
        r"""
        Return the Siegel modular form `I(f,g)` (Notation as in [Sko]).
    
        INPUT:
        - `f`              -- modular form of level `1`
        - `g`              -- cusp form of level `1` and weight = ``weight of f + 2``
        - ``is_integral``  -- ``True`` if the result is garanteed to have integer
                              coefficients
        """
        
        ## we introduce an abbreviations
        if is_integral :
            PS = self.integral_power_series_ring()
        else :
            PS = self.power_series_ring()
        
        fismodular = isinstance(f, ModularFormElement)
        gismodular = isinstance(g, ModularFormElement)
    
        ## We only check the arguments if f and g are ModularFormElements.
        ## Otherwise we trust in the user 
        if fismodular and gismodular :
            assert( f.weight() + 2 == g.weight() | (f==0) | (g==0)), \
                    "incorrect weights!"
            assert( g.q_expansion(1) == 0), "second argument is not a cusp form"

        qexp_prec = self._get_maass_form_qexp_prec()
        if qexp_prec is None : # there are no forms below prec
            return dict()

        if fismodular :
            k = f.weight()
            if f == f.parent()(0) :
                f = PS(0, qexp_prec)
            else :
                f = PS(f.qexp(qexp_prec), qexp_prec)
        elif f == 0 :
            f = PS(0, qexp_prec)
        else :
            f = PS(f(qexp_prec), qexp_prec)
        
        if gismodular :
            k = g.weight() - 2
            if g == g.parent()(0) :
                g = PS(0, qexp_prec)
            else :
                g = PS(g.qexp(qexp_prec), qexp_prec)
        elif g == 0 :
            g = PS(0, qexp_prec)
        else :
            g = PS(g(qexp_prec), qexp_prec)
                
        if k is None :
            raise ValueError, "if neither f nor g are not ModularFormElements " + \
                              "you must pass k"
            
        fderiv = f.derivative().shift(1)
        f *= Integer(k/2)
        gfderiv = g - fderiv

        ## Form A and B - the Jacobi forms used in [Sko]'s I map.
        ## This is not necessary if we multiply Ifg0 and Ifg1 by etapow
        # (A0,A1,B0,B1) = (a0*etapow, a1*etapow, b0*etapow, b1*etapow)
    
        ## Calculate the image of the pair of modular forms (f,g) under
        ## [Sko]'s isomorphism I : M_{k} \oplus S_{k+2} -> J_{k,1}.
        
        # Multiplication of big polynomials may take > 60 GB, so wie have
        # to do it in small parts; This is only implemented for integral
        # coefficients.

        """
        Create the Jacobi form I(f,g) as in [Sko].
    
        It suffices to construct for all Jacobi forms phi only the part
        sum_{r=0,1;n} c_phi(r^2-4n) q^n zeta^r.
        When, in this code part, we speak of Jacobi form we only mean this part.
        
        We need to compute Ifg = \sum_{r=0,1; n} c(r^2-4n) q^n zeta^r up to
        4n-r^2 <= Dtop, i.e. n < precision
        """

        ## Create the Jacobi forms A=a*etapow and B=b*etapow in stages.
        ## Recall a = sum_{s != r mod 2} s^2*(-1)^r*q^((s^2+r^2-1)/4)*zeta^r
        ##        b = sum_{s != r mod 2}     (-1)^r*q^((s^2+r^2-1)/4)*zeta^r
        ## r, s run over ZZ but with opposite parities.
        ## For r=0, we need s odd, (s^2-1)/4 < precision, with s=2t+1 hence t^2+t < precision.
        ## For r=1, we need s even, s^2/4 < precision, with s=2t hence t^2 < precision.
    
        ## we use a slightly overestimated ab_prec 
        
        ab_prec = isqrt(qexp_prec + 1)
        a1dict = dict(); a0dict = dict()
        b1dict = dict(); b0dict = dict()
    
        for t in xrange(1, ab_prec + 1) :
            tmp = t**2
            a1dict[tmp] = -8*tmp
            b1dict[tmp] = -2
        
            tmp += t
            a0dict[tmp] = 8*tmp + 2
            b0dict[tmp] = 2
        b1dict[0] = -1
        a0dict[0] = 2; b0dict[0] = 2 
        
        a1 = PS(a1dict); b1 = PS(b1dict)
        a0 = PS(a0dict); b0 = PS(b0dict)

        ## Finally: I(f,g) is given by the formula below:
        ## We multiply by etapow explecitely and save two multiplications
        # Ifg0 = k/2*f*A0 - fderiv*B0 + g*B0 + O(q^precision)
        # Ifg1 = k/2*f*A1 - fderiv*B1 + g*B1 + O(q^precision)
        Ifg0 = (self._eta_power() * (f*a0 + gfderiv*b0)).list()
        Ifg1 = (self._eta_power() * (f*a1 + gfderiv*b1)).list()

        if len(Ifg0) < qexp_prec :
            Ifg0 += [0]*(qexp_prec - len(Ifg0))
        if len(Ifg1) < qexp_prec :
            Ifg1 += [0]*(qexp_prec - len(Ifg1))
        
        ## For applying the Maass' lifting to genus 2 modular forms.
        ## we put the coefficients of Ifg into a dictionary Chi
        ## so that we can access the coefficient corresponding to 
        ## discriminant D by going Chi[D].
        
        Cphi = dict([(0,0)])
        for i in xrange(qexp_prec) :
            Cphi[-4*i] = Ifg0[i]
            Cphi[1-4*i] = Ifg1[i]

        del Ifg0[:], Ifg1[:]

        """
        Create the Maas lift F := VI(f,g) as in [Sko].
        """
        
        ## The constant term is given by -Cphi[0]*B_{2k}/(4*k)
        ## (note in [Sko] this coeff has typos).
        ## For nonconstant terms,
        ## The Siegel coefficient of q^n * zeta^r * qdash^m is given 
        ## by the formula  \sum_{ a | gcd(n,r,m) } Cphi[D/a^2] where 
        ## D = r^2-4*n*m is the discriminant.  
        ## Hence in either case the coefficient 
        ## is fully deterimined by the pair (D,gcd(n,r,m)).
        ## Put (D,t) -> \sum_{ a | t } Cphi[D/a^2]
        ## in a dictionary (hash table) maassc.

        maass_coeffs = dict()
        divisor_dict = self._divisor_dict()

        ## First calculate maass coefficients corresponding to strictly positive definite matrices:        
        for disc in self._negative_fundamental_discriminants() :
            for s in xrange(1, isqrt((-self.__precision.discriminant()) // disc) + 1) :
                ## add (disc*s^2,t) as a hash key, for each t that divides s
                for t in divisor_dict[s] :
                    maass_coeffs[(disc * s**2,t)] = \
                       sum( a**(k-1) * Cphi[disc * s**2 / a**2] 
                            for a in divisor_dict[t] )

        ## Compute the coefficients of the Siegel form $F$:
        siegel_coeffs = dict()
        for (n,r,m), g in self.__precision.iter_positive_forms_with_content() :
            siegel_coeffs[(n,r,m)] = maass_coeffs[(r**2 - 4*m*n, g)]

        ## Secondly, deal with the singular part.
        ## Include the coeff corresponding to (0,0,0):
        ## maass_coeffs = {(0,0): -bernoulli(k)/(2*k)*Cphi[0]}
        siegel_coeffs[(0,0,0)] = -bernoulli(k)/(2*k)*Cphi[0]
        if is_integral :
            siegel_coeffs[(0,0,0)] = Integer(siegel_coeffs[(0,0,0)])
        
        ## Calculate the other discriminant-zero maass coefficients.
        ## Since sigma is quite cheap it is faster to estimate the bound and
        ## save the time for repeated calculation
        for i in xrange(1, self.__precision._indefinite_content_bound()) :
            ## maass_coeffs[(0,i)] = sigma(i, k-1) * Cphi[0]
            siegel_coeffs[(0,0,i)] = sigma(i, k-1) * Cphi[0]

        return siegel_coeffs
Пример #20
0
    def maass_form(self, f, g, k=None, is_integral=False):
        r"""
        Return the Siegel modular form `I(f,g)` (Notation as in [Sko]).
    
        INPUT:
        - `f`              -- modular form of level `1`
        - `g`              -- cusp form of level `1` and weight = ``weight of f + 2``
        - ``is_integral``  -- ``True`` if the result is guaranteed to have integer
                              coefficients
        """

        ## we introduce an abbreviations
        if is_integral:
            PS = self.integral_power_series_ring()
        else:
            PS = self.power_series_ring()

        fismodular = isinstance(f, ModularFormElement)
        gismodular = isinstance(g, ModularFormElement)

        ## We only check the arguments if f and g are ModularFormElements.
        ## Otherwise we trust in the user
        if fismodular and gismodular:
            assert(f.weight() + 2 == g.weight() | (f==0) | (g==0)), \
                    "incorrect weights!"
            assert (
                g.q_expansion(1) == 0), "second argument is not a cusp form"

        qexp_prec = self._get_maass_form_qexp_prec()
        if qexp_prec is None:  # there are no forms below prec
            return dict()

        if fismodular:
            k = f.weight()
            if f == f.parent()(0):
                f = PS(0, qexp_prec)
            else:
                f = PS(f.qexp(qexp_prec), qexp_prec)
        elif f == 0:
            f = PS(0, qexp_prec)
        else:
            f = PS(f(qexp_prec), qexp_prec)

        if gismodular:
            k = g.weight() - 2
            if g == g.parent()(0):
                g = PS(0, qexp_prec)
            else:
                g = PS(g.qexp(qexp_prec), qexp_prec)
        elif g == 0:
            g = PS(0, qexp_prec)
        else:
            g = PS(g(qexp_prec), qexp_prec)

        if k is None:
            raise ValueError("if neither f nor g are not ModularFormElements " + \
                              "you must pass k")

        fderiv = f.derivative().shift(1)
        f *= Integer(k / 2)
        gfderiv = g - fderiv

        ## Form A and B - the Jacobi forms used in [Sko]'s I map.
        ## This is not necessary if we multiply Ifg0 and Ifg1 by etapow
        # (A0,A1,B0,B1) = (a0*etapow, a1*etapow, b0*etapow, b1*etapow)

        ## Calculate the image of the pair of modular forms (f,g) under
        ## [Sko]'s isomorphism I: M_{k} \oplus S_{k+2} -> J_{k,1}.

        # Multiplication of big polynomials may take > 60 GB, so wie have
        # to do it in small parts; This is only implemented for integral
        # coefficients.
        r"""
        Create the Jacobi form I(f,g) as in [Sko].
    
        It suffices to construct for all Jacobi forms phi only the part
        sum_{r=0,1;n} c_phi(r^2-4n) q^n zeta^r.
        When, in this code part, we speak of Jacobi form we only mean this part.
        
        We need to compute Ifg = \sum_{r=0,1; n} c(r^2-4n) q^n zeta^r up to
        4n-r^2 <= Dtop, i.e. n < precision
        """

        ## Create the Jacobi forms A=a*etapow and B=b*etapow in stages.
        ## Recall a = sum_{s != r mod 2} s^2*(-1)^r*q^((s^2+r^2-1)/4)*zeta^r
        ##        b = sum_{s != r mod 2}     (-1)^r*q^((s^2+r^2-1)/4)*zeta^r
        ## r, s run over ZZ but with opposite parities.
        ## For r=0, we need s odd, (s^2-1)/4 < precision, with s=2t+1 hence t^2+t < precision.
        ## For r=1, we need s even, s^2/4 < precision, with s=2t hence t^2 < precision.

        ## we use a slightly overestimated ab_prec

        ab_prec = isqrt(qexp_prec + 1)
        a1dict = dict()
        a0dict = dict()
        b1dict = dict()
        b0dict = dict()

        for t in range(1, ab_prec + 1):
            tmp = t**2
            a1dict[tmp] = -8 * tmp
            b1dict[tmp] = -2

            tmp += t
            a0dict[tmp] = 8 * tmp + 2
            b0dict[tmp] = 2
        b1dict[0] = -1
        a0dict[0] = 2
        b0dict[0] = 2

        a1 = PS(a1dict)
        b1 = PS(b1dict)
        a0 = PS(a0dict)
        b0 = PS(b0dict)

        ## Finally: I(f,g) is given by the formula below:
        ## We multiply by etapow explicitly and save two multiplications
        # Ifg0 = k/2*f*A0 - fderiv*B0 + g*B0 + O(q^precision)
        # Ifg1 = k/2*f*A1 - fderiv*B1 + g*B1 + O(q^precision)
        Ifg0 = (self._eta_power() * (f * a0 + gfderiv * b0)).list()
        Ifg1 = (self._eta_power() * (f * a1 + gfderiv * b1)).list()

        if len(Ifg0) < qexp_prec:
            Ifg0 += [0] * (qexp_prec - len(Ifg0))
        if len(Ifg1) < qexp_prec:
            Ifg1 += [0] * (qexp_prec - len(Ifg1))

        ## For applying the Maass' lifting to genus 2 modular forms.
        ## we put the coefficients of Ifg into a dictionary Chi
        ## so that we can access the coefficient corresponding to
        ## discriminant D by going Chi[D].

        Cphi = dict([(0, 0)])
        for i in range(qexp_prec):
            Cphi[-4 * i] = Ifg0[i]
            Cphi[1 - 4 * i] = Ifg1[i]

        del Ifg0[:], Ifg1[:]
        """
        Create the Maas lift F:= VI(f,g) as in [Sko].
        """

        ## The constant term is given by -Cphi[0]*B_{2k}/(4*k)
        ## (note in [Sko] this coeff has typos).
        ## For nonconstant terms,
        ## The Siegel coefficient of q^n * zeta^r * qdash^m is given
        ## by the formula  \sum_{ a | gcd(n,r,m) } Cphi[D/a^2] where
        ## D = r^2-4*n*m is the discriminant.
        ## Hence in either case the coefficient
        ## is fully determined by the pair (D,gcd(n,r,m)).
        ## Put (D,t) -> \sum_{ a | t } Cphi[D/a^2]
        ## in a dictionary (hash table) maassc.

        maass_coeffs = dict()
        divisor_dict = self._divisor_dict()

        ## First calculate maass coefficients corresponding to strictly positive definite matrices:
        for disc in self._negative_fundamental_discriminants():
            for s in range(
                    1,
                    isqrt((-self.__precision.discriminant()) // disc) + 1):
                ## add (disc*s^2,t) as a hash key, for each t that divides s
                for t in divisor_dict[s]:
                    maass_coeffs[(disc * s**2,t)] = \
                       sum(a**(k-1) * Cphi[disc * s**2 / a**2]
                            for a in divisor_dict[t])

        ## Compute the coefficients of the Siegel form $F$:
        siegel_coeffs = dict()
        for (n, r,
             m), g in self.__precision.iter_positive_forms_with_content():
            siegel_coeffs[(n, r, m)] = maass_coeffs[(r**2 - 4 * m * n, g)]

        ## Secondly, deal with the singular part.
        ## Include the coeff corresponding to (0,0,0):
        ## maass_coeffs = {(0,0): -bernoulli(k)/(2*k)*Cphi[0]}
        siegel_coeffs[(0, 0, 0)] = -bernoulli(k) / (2 * k) * Cphi[0]
        if is_integral:
            siegel_coeffs[(0, 0, 0)] = Integer(siegel_coeffs[(0, 0, 0)])

        ## Calculate the other discriminant-zero maass coefficients.
        ## Since sigma is quite cheap it is faster to estimate the bound and
        ## save the time for repeated calculation
        for i in range(1, self.__precision._indefinite_content_bound()):
            ## maass_coeffs[(0,i)] = sigma(i, k-1) * Cphi[0]
            siegel_coeffs[(0, 0, i)] = sigma(i, k - 1) * Cphi[0]

        return siegel_coeffs
    def HarmonicNumber(var, precision=None, skip_constant_summand=False):
        r"""
        Return the asymptotic expansion of a harmonic number.

        INPUT:

        - ``var`` -- a string for the variable name.

        - ``precision`` -- (default: ``None``) an integer. If ``None``, then
          the default precision of the asymptotic ring is used.

        - ``skip_constant_summand`` -- (default: ``False``) a
          boolean. If set, then the constant summand ``euler_gamma`` is left out.
          As a consequence, the coefficient ring of the output changes
          from ``Symbolic Constants Subring`` (if ``False``) to
          ``Rational Field`` (if ``True``).

        OUTPUT:

        An asymptotic expansion.

        EXAMPLES::

            sage: asymptotic_expansions.HarmonicNumber('n', precision=5)
            log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6))

        TESTS::

            sage: ex = asymptotic_expansions.HarmonicNumber('n', precision=5)
            sage: n = ex.parent().gen()
            sage: ex.compare_with_values(n,                      # rel tol 1e-6
            ....:      lambda x: sum(1/k for k in srange(1, x+1)), [5, 10, 20])
            [(5, 0.0038125360?), (10, 0.00392733?), (20, 0.0039579?)]
            sage: asymptotic_expansions.HarmonicNumber('n')
            log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4)
            - 1/252*n^(-6) + 1/240*n^(-8) - 1/132*n^(-10)
            + 691/32760*n^(-12) - 1/12*n^(-14) + 3617/8160*n^(-16)
            - 43867/14364*n^(-18) + 174611/6600*n^(-20) - 77683/276*n^(-22)
            + 236364091/65520*n^(-24) - 657931/12*n^(-26)
            + 3392780147/3480*n^(-28) - 1723168255201/85932*n^(-30)
            + 7709321041217/16320*n^(-32)
            - 151628697551/12*n^(-34) + O(n^(-36))
            sage: _.parent()
            Asymptotic Ring <n^ZZ * log(n)^ZZ> over Symbolic Constants Subring

        ::

            sage: asymptotic_expansions.HarmonicNumber(
            ....:     'n', precision=5, skip_constant_summand=True)
            log(n) + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6))
            sage: _.parent()
            Asymptotic Ring <n^ZZ * log(n)^ZZ> over Rational Field
            sage: for p in range(5):
            ....:     print asymptotic_expansions.HarmonicNumber(
            ....:         'n', precision=p)
            O(log(n))
            log(n) + O(1)
            log(n) + euler_gamma + O(n^(-1))
            log(n) + euler_gamma + 1/2*n^(-1) + O(n^(-2))
            log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + O(n^(-4))
            sage: asymptotic_expansions.HarmonicNumber('m', precision=5)
            log(m) + euler_gamma + 1/2*m^(-1) - 1/12*m^(-2) + 1/120*m^(-4) + O(m^(-6))
        """
        if not skip_constant_summand:
            from sage.symbolic.ring import SR
            coefficient_ring = SR.subring(no_variables=True)
        else:
            from sage.rings.rational_field import QQ
            coefficient_ring = QQ

        from asymptotic_ring import AsymptoticRing
        A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var),
                           coefficient_ring=coefficient_ring)
        n = A.gen()

        if precision is None:
            precision = A.default_prec

        from sage.functions.log import log
        result = A.zero()
        if precision >= 1:
            result += log(n)
        if precision >= 2 and not skip_constant_summand:
            from sage.symbolic.constants import euler_gamma
            result += coefficient_ring(euler_gamma)
        if precision >= 3:
            result += 1 / (2 * n)

        from sage.arith.srange import srange
        from sage.arith.all import bernoulli
        for k in srange(2, 2*precision - 4, 2):
            result += -bernoulli(k) / k / n**k

        if precision < 1:
            result += (log(n)).O()
        elif precision == 1:
            result += A(1).O()
        elif precision == 2:
            result += (1 / n).O()
        else:
            result += (1 / n**(2*precision - 4)).O()

        return result
Пример #22
0
def siegel_product(self, u):
    """
    Computes the infinite product of local densities of the quadratic
    form for the number `u`.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1])
        sage: Q.theta_series(11)
        1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 + O(q^11)

        sage: Q.siegel_product(1)
        8
        sage: Q.siegel_product(2)      ## This one is wrong -- expect 24, and the higher powers of 2 don't work... =(
        24
        sage: Q.siegel_product(3)
        32
        sage: Q.siegel_product(5)
        48
        sage: Q.siegel_product(6)
        96
        sage: Q.siegel_product(7)
        64
        sage: Q.siegel_product(9)
        104

        sage: Q.local_density(2,1)
        1
        sage: M = 4; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 1]) / M^3
        1
        sage: M = 16; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 1]) / M^3  # long time (2s on sage.math, 2014)
        1

        sage: Q.local_density(2,2)
        3/2
        sage: M = 4; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 2]) / M^3
        3/2
        sage: M = 16; len([v  for v in mrange([M,M,M,M])  if Q(v) % M == 2]) / M^3  # long time (2s on sage.math, 2014)
        3/2

    TESTS::

        sage: [1] + [Q.siegel_product(ZZ(a))  for a in range(1,11)] == Q.theta_series(11).list()  # long time (2s on sage.math, 2014)
        True
    """
    ## Protect u (since it fails often if it's an just an int!)
    u = ZZ(u)

    n = self.dim()
    d = self.det()       ## ??? Warning: This is a factor of 2^n larger than it should be!

    ## DIAGNOSTIC
    verbose("n = " + str(n))
    verbose("d = " + str(d))
    verbose("In siegel_product:  d = ", d, "\n");


    ## Product of "bad" places to omit
    S = 2 * d * u

    ## DIAGNOSTIC
    verbose("siegel_product Break 1. \n")
    verbose(" u = ", u, "\n")


    ## Make the odd generic factors
    if ((n % 2) == 1):
        m = (n-1) // 2
        d1 = fundamental_discriminant(((-1)**m) * 2*d * u)     ## Replaced d by 2d here to compensate for the determinant
        f = abs(d1)                                            ## gaining an odd power of 2 by using the matrix of 2Q instead
                                                               ## of the matrix of Q.
                                                               ##  --> Old d1 = CoreDiscriminant((mpz_class(-1)^m) * d * u);

        ## Make the ratio of factorials factor: [(2m)! / m!] * prod_{i=1}^m (2*i-1)
        factor1 = 1
        for i in range(1, m+1):
            factor1 *= 2*i - 1
        for i in range(m+1, 2*m + 1):
            factor1 *= i

        genericfactor = factor1 * ((u / f) ** m) \
            * QQ(sqrt((2 ** n) *  f) / (u * d)) \
            * abs(QuadraticBernoulliNumber(m, d1) / bernoulli(2*m))



    ## DIAGNOSTIC
    verbose("siegel_product Break 2. \n")


    ## Make the even generic factor
    if ((n % 2) == 0):
        m = n // 2
        d1 = fundamental_discriminant(((-1)**m) * d)
        f = abs(d1)

        ## DIAGNOSTIC
        #cout << " mpz_class(-1)^m = " << (mpz_class(-1)^m) << " and d = " << d << endl;
        #cout << " f = " << f << " and d1 = " << d1 << endl;


        genericfactor = m / QQ(sqrt(f*d)) \
            * ((u/2) ** (m-1)) * (f ** m) \
            / abs(QuadraticBernoulliNumber(m, d1)) \
            * (2 ** m)                                               ## This last factor compensates for using the matrix of 2*Q


    ##return genericfactor


    ## Omit the generic factors in S and compute them separately
    omit = 1
    include = 1

    S_divisors = prime_divisors(S)

    ## DIAGNOSTIC
    #cout << "\n S is " << S << endl;
    #cout << " The Prime divisors of S are :";
    #PrintV(S_divisors);


    for p in S_divisors:
        Q_normal = self.local_normal_form(p)


        ## DIAGNOSTIC
        verbose(" p = " + str(p) + " and its Kronecker symbol (d1/p) = (" + str(d1) + "/" + str(p) + ") is " + str(kronecker_symbol(d1, p)) + "\n")

        omit *= 1 / (1 - (kronecker_symbol(d1, p) / (p**m)))


        ## DIAGNOSTIC
        verbose(" omit = " + str(omit) + "\n")
        verbose(" Q_normal is \n" + str(Q_normal) + "\n")
        verbose(" Q_normal = \n" + str(Q_normal))
        verbose(" p = " + str(p) + "\n")
        verbose(" u = " +str(u) + "\n")
        verbose(" include = " + str(include) + "\n")


        include *= Q_normal.local_density(p, u)


        ## DIAGNOSTIC
        #cout << " Including the p = " << p << " factor: " << local_density(Q_normal, p, u) << endl;

        ## DIAGNSOTIC
        verbose("    ---  Exiting loop \n")




    #// ****************  Important *******************
    #// Additional fix (only included for n=4) to deal
    #// with the power of 2 introduced at the real place
    #// by working with Q instead of 2*Q.  This needs to
    #// be done for all other n as well...
    #/*
    #if (n==4)
    #  genericfactor = 4 * genericfactor;
    #*/


    ## DIAGNSOTIC
    #cout << endl;
    #cout << " generic factor = " << genericfactor << endl;
    #cout << " omit = " << omit << endl;
    #cout << " include = " << include << endl;
    #cout << endl;


    ## DIAGNSOTIC
    #//  cout << "siegel_product Break 3. " << endl;


    ## Return the final factor (and divide by 2 if n=2)
    if (n == 2):
        return (genericfactor * omit * include / 2)
    else:
        return (genericfactor * omit * include)
Пример #23
0
def zeta__exact(n):
    r"""
    Returns the exact value of the Riemann Zeta function

    The argument must be a critical value, namely either positive even
    or negative odd.

    See for example [Iwa1972]_, p13, Special value of `\zeta(2k)`

    EXAMPLES:

    Let us test the accuracy for negative special values::

        sage: RR = RealField(100)
        sage: for i in range(1,10):
        ....:     print("zeta({}): {}".format(1-2*i, RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i))))
        zeta(-1): 0.00000000000000000000000000000
        zeta(-3): 0.00000000000000000000000000000
        zeta(-5): 0.00000000000000000000000000000
        zeta(-7): 0.00000000000000000000000000000
        zeta(-9): 0.00000000000000000000000000000
        zeta(-11): 0.00000000000000000000000000000
        zeta(-13): 0.00000000000000000000000000000
        zeta(-15): 0.00000000000000000000000000000
        zeta(-17): 0.00000000000000000000000000000

    Let us test the accuracy for positive special values::

        sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10))
        True

    TESTS::

        sage: zeta__exact(4)
        1/90*pi^4
        sage: zeta__exact(-3)
        1/120
        sage: zeta__exact(0)
        -1/2
        sage: zeta__exact(5)
        Traceback (most recent call last):
        ...
        TypeError: n must be a critical value (i.e. even > 0 or odd < 0)

    REFERENCES:

    - [Iwa1972]_
    - [IR1990]_
    - [Was1997]_
    """
    if n < 0:
        return bernoulli(1-n)/(n-1)
    elif n > 1:
        if (n % 2 == 0):
            return ZZ(-1)**(n//2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n)
        else:
            raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)")
    elif n == 1:
        return infinity
    elif n == 0:
        return QQ((-1, 2))