Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" The Victor Miller Basis
This module contains functions for quick calculation of a basis of `q`-expansions for the space of modular forms of level 1 and any weight. The basis returned is the Victor Miller basis, which is the unique basis of elliptic modular forms `f_1, \dots, f_d` for which `a_i(f_j) = \delta_{ij}` for `1 \le i, j \le d` (where `d` is the dimension of the space).
This basis is calculated using a standard set of generators for the ring of modular forms, using the fast multiplication algorithms for polynomials and power series provided by the FLINT library. (This is far quicker than using modular symbols).
TESTS::
sage: ModularSymbols(1, 36, 1).cuspidal_submodule().q_expansion_basis(30) == victor_miller_basis(36, 30, cusp_only=True) True """ from __future__ import absolute_import
#***************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #***************************************************************************** from six.moves import range import math
from sage.rings.all import QQ, ZZ, Integer, \ PolynomialRing, PowerSeriesRing, O as bigO from sage.structure.all import Sequence from sage.libs.flint.fmpz_poly import Fmpz_poly from sage.misc.all import verbose
from .eis_series_cython import eisenstein_series_poly
def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): r""" Compute and return the Victor Miller basis for modular forms of weight `k` and level 1 to precision `O(q^{prec})`. If ``cusp_only`` is True, return only a basis for the cuspidal subspace.
INPUT:
- ``k`` -- an integer
- ``prec`` -- (default: 10) a positive integer
- ``cusp_only`` -- bool (default: False)
- ``var`` -- string (default: 'q')
OUTPUT:
A sequence whose entries are power series in ``ZZ[[var]]``.
EXAMPLES::
sage: victor_miller_basis(1, 6) [] sage: victor_miller_basis(0, 6) [ 1 + O(q^6) ] sage: victor_miller_basis(2, 6) [] sage: victor_miller_basis(4, 6) [ 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6) ]
sage: victor_miller_basis(6, 6, var='w') [ 1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6) ]
sage: victor_miller_basis(6, 6) [ 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6) ] sage: victor_miller_basis(12, 6) [ 1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ]
sage: victor_miller_basis(12, 6, cusp_only=True) [ q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6, cusp_only=True) [ q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(24, 6) [ 1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) ] sage: victor_miller_basis(32, 6) [ 1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6), q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6), q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6) ]
sage: victor_miller_basis(40,200)[1:] == victor_miller_basis(40,200,cusp_only=True) True sage: victor_miller_basis(200,40)[1:] == victor_miller_basis(200,40,cusp_only=True) True
AUTHORS:
- William Stein, Craig Citro: original code
- Martin Raum (2009-08-02): use FLINT for polynomial arithmetic (instead of NTL) """ raise ValueError("k must be non-negative")
# If prec is less than or equal to the dimension of the space of # cusp forms, which is just n, then we know the answer, and we # simply return it. q = PowerSeriesRing(ZZ,var).gen(0) err = bigO(q**prec) ls = [0] * (n+1) if not cusp_only: ls[0] = 1 + err for i in range(1,prec): ls[i] = q**i + err for i in range(prec,n+1): ls[i] = err return Sequence(ls, cr=True)
elif e == 10: A = eisenstein_series_poly(10,prec) else: # e == 14 A = eisenstein_series_poly(14,prec)
else:
else :
def _delta_poly(prec=10): """ Return the q-expansion of Delta as a FLINT polynomial. Used internally by the :func:`~delta_qexp` function. See the docstring of :func:`~delta_qexp` for more information.
INPUT:
- ``prec`` -- integer; the absolute precision of the output
OUTPUT:
the q-expansion of Delta to precision ``prec``, as a FLINT :class:`~sage.libs.flint.fmpz_poly.Fmpz_poly` object.
EXAMPLES::
sage: from sage.modular.modform.vm_basis import _delta_poly sage: _delta_poly(7) 7 0 1 -24 252 -1472 4830 -6048 """
# Let F = \sum_{n >= 0} (-1)^n (2n+1) q^(floor(n(n+1)/2)). # Then delta is F^8.
# First compute F^2 directly by naive polynomial multiplication, # since F is very sparse.
# make list of index/value pairs for the sparse poly for n in range(stop+1)]
def _delta_poly_modulo(N, prec=10): """ Return the q-expansion of `\Delta` modulo `N`. Used internally by the :func:`~delta_qexp` function. See the docstring of :func:`~delta_qexp` for more information.
INPUT:
- `N` -- positive integer modulo which we want to compute `\Delta`
- ``prec`` -- integer; the absolute precision of the output
OUTPUT:
the polynomial of degree ``prec``-1 which is the truncation of `\Delta` modulo `N`, as an element of the polynomial ring in `q` over the integers modulo `N`.
EXAMPLES::
sage: from sage.modular.modform.vm_basis import _delta_poly_modulo sage: _delta_poly_modulo(5, 7) 2*q^6 + 3*q^4 + 2*q^3 + q^2 + q sage: _delta_poly_modulo(10, 12) 2*q^11 + 7*q^9 + 6*q^7 + 2*q^6 + 8*q^4 + 2*q^3 + 6*q^2 + q """ raise ValueError( "prec must be positive" )
# Let F = \sum_{n >= 0} (-1)^n (2n+1) q^(floor(n(n+1)/2)). # Then delta is F^8.
# fast way of computing f*f truncated at prec
def delta_qexp(prec=10, var='q', K=ZZ) : """ Return the `q`-expansion of the weight 12 cusp form `\Delta` as a power series with coefficients in the ring K (`= \ZZ` by default).
INPUT:
- ``prec`` -- integer (default 10), the absolute precision of the output (must be positive)
- ``var`` -- string (default: 'q'), variable name
- ``K`` -- ring (default: `\ZZ`), base ring of answer
OUTPUT:
a power series over K in the variable ``var``
ALGORITHM:
Compute the theta series
.. MATH::
\sum_{n \ge 0} (-1)^n (2n+1) q^{n(n+1)/2},
a very simple explicit modular form whose 8th power is `\Delta`. Then compute the 8th power. All computations are done over `\ZZ` or `\ZZ` modulo `N` depending on the characteristic of the given coefficient ring `K`, and coerced into `K` afterwards.
EXAMPLES::
sage: delta_qexp(7) q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 + O(q^7) sage: delta_qexp(7,'z') z - 24*z^2 + 252*z^3 - 1472*z^4 + 4830*z^5 - 6048*z^6 + O(z^7) sage: delta_qexp(-3) Traceback (most recent call last): ... ValueError: prec must be positive sage: delta_qexp(20, K = GF(3)) q + q^4 + 2*q^7 + 2*q^13 + q^16 + 2*q^19 + O(q^20) sage: delta_qexp(20, K = GF(3^5, 'a')) q + q^4 + 2*q^7 + 2*q^13 + q^16 + 2*q^19 + O(q^20) sage: delta_qexp(10, K = IntegerModRing(60)) q + 36*q^2 + 12*q^3 + 28*q^4 + 30*q^5 + 12*q^6 + 56*q^7 + 57*q^9 + O(q^10)
TESTS:
Test algorithm with modular arithmetic (see also :trac:`11804`)::
sage: delta_qexp(10^4).change_ring(GF(13)) == delta_qexp(10^4, K=GF(13)) True sage: delta_qexp(1000).change_ring(IntegerModRing(5^100)) == delta_qexp(1000, K=IntegerModRing(5^100)) True
AUTHORS:
- William Stein: original code
- David Harvey (2007-05): sped up first squaring step
- Martin Raum (2009-08-02): use FLINT for polynomial arithmetic (instead of NTL) """ else: # compute over ZZ and coerce |