Path: blob/master/sage/modular/modform/find_generators.py
4057 views
"""1Graded Rings of Modular Forms23This module contains functions to find generators for the graded ring of4modular forms of given level.56AUTHORS:78- William Stein (2007-08-24): first version9"""101112from sage.rings.all import Integer, QQ, ZZ, PowerSeriesRing13from sage.misc.misc import prod, verbose14from sage.misc.cachefunc import cached_method15from sage.modular.arithgroup.all import Gamma0, is_CongruenceSubgroup16from constructor import ModularForms17from sage.structure.sage_object import SageObject18from random import shuffle1920def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=False):21r"""22Utility function. Given a nonempty list of pairs ``(k,f)``, where `k` is an23integer and `f` is a power series, and a weight l, return all weight l24forms obtained by multiplying together the given forms.2526INPUT:2728- ``forms`` -- list of pairs `(k, f)` with k an integer and f a power29series (all over the same base ring)30- ``weight`` -- an integer31- ``prec`` -- an integer (less than or equal to the precision of all the32forms in ``forms``) -- precision to use in power series computations.33- ``stop_dim`` -- an integer: stop as soon as we have enough forms to span34a submodule of this rank (a saturated one if the base ring is `\ZZ`).35Ignored if ``use_random`` is False.36- ``use_random`` -- which algorithm to use. If True, tries random products37of the generators of the appropriate weight until a large enough38submodule is found (determined by ``stop_dim``). If False, just tries39everything.4041Note that if the given forms do generate the whole space, then42``use_random=True`` will often be quicker (particularly if the weight is43large); but if the forms don't generate, the randomized algorithm is no44help and will actually be substantially slower, because it needs to do45repeated echelon form calls to check if vectors are in a submodule, while46the non-randomized algorithm just echelonizes one enormous matrix at the47end.4849EXAMPLES::5051sage: import sage.modular.modform.find_generators as f52sage: forms = [(4, 240*eisenstein_series_qexp(4,5)), (6,504*eisenstein_series_qexp(6,5))]53sage: f._span_of_forms_in_weight(forms, 12, prec=5)54Vector space of degree 5 and dimension 2 over Rational Field55Basis matrix:56[ 1 0 196560 16773120 398034000]57[ 0 1 -24 252 -1472]58sage: f._span_of_forms_in_weight(forms, 24, prec=5)59Vector space of degree 5 and dimension 3 over Rational Field60Basis matrix:61[ 1 0 0 52416000 39007332000]62[ 0 1 0 195660 12080128]63[ 0 0 1 -48 1080]64sage: ModularForms(1, 24).q_echelon_basis(prec=5)65[661 + 52416000*q^3 + 39007332000*q^4 + O(q^5),67q + 195660*q^3 + 12080128*q^4 + O(q^5),68q^2 - 48*q^3 + 1080*q^4 + O(q^5)69]7071Test the alternative randomized algorithm::7273sage: f._span_of_forms_in_weight(forms, 24, prec=5, use_random=True, stop_dim=3)74Vector space of degree 5 and dimension 3 over Rational Field75Basis matrix:76[ 1 0 0 52416000 39007332000]77[ 0 1 0 195660 12080128]78[ 0 0 1 -48 1080]79"""80t = verbose('multiplying forms up to weight %s'%weight)81# Algorithm: run through the monomials of the appropriate weight, and build82# up the vector space they span.8384n = len(forms)85R = forms[0][1].base_ring()86V = R ** prec87W = V.zero_submodule()88shortforms = [f[1].truncate_powerseries(prec) for f in forms]8990# List of weights91from sage.combinat.integer_vector_weighted import WeightedIntegerVectors92wts = list(WeightedIntegerVectors(weight, [f[0] for f in forms]))93t = verbose("calculated weight list", t)94N = len(wts)9596if use_random:97if stop_dim is None:98raise ValueError("stop_dim must be provided if use_random is True")99shuffle(wts)100101for c in xrange(N):102w = V(prod(shortforms[i]**wts[c][i] for i in xrange(n)).padded_list(prec))103if w in W: continue104W = V.span(list(W.gens()) + [w])105if stop_dim and W.rank() == stop_dim:106if R != ZZ or W.index_in_saturation() == 1:107verbose("Succeeded after %s of %s" % (c, N), t)108return W109verbose("Nothing worked", t)110return W111else:112G = [V(prod(forms[i][1]**c[i] for i in xrange(n)).padded_list(prec)) for c in wts]113t = verbose('found %s candidates' % N, t)114W = V.span(G)115verbose('span has dimension %s' % W.rank(), t)116return W117118def find_generators(*args):119r"""120This function, which existed in earlier versions of Sage, has now been121replaced by the :meth:`~ModularFormsRing.generators` method of122ModularFormsRing objects.123124EXAMPLE::125126sage: from sage.modular.modform.find_generators import find_generators127sage: find_generators()128Traceback (most recent call last):129...130NotImplementedError: find_generators has been removed -- use ModularFormsRing.generators()131"""132raise NotImplementedError("find_generators has been removed -- use ModularFormsRing.generators()")133134def basis_for_modform_space(*args):135r"""136This function, which existed in earlier versions of Sage, has now been137replaced by the :meth:`~ModularFormsRing.q_expansion_basis` method of138ModularFormsRing objects.139140EXAMPLE::141142sage: from sage.modular.modform.find_generators import basis_for_modform_space143sage: basis_for_modform_space()144Traceback (most recent call last):145...146NotImplementedError: basis_for_modform_space has been removed -- use ModularFormsRing.q_expansion_basis()147"""148raise NotImplementedError("basis_for_modform_space has been removed -- use ModularFormsRing.q_expansion_basis()")149150class ModularFormsRing(SageObject):151152def __init__(self, group, base_ring=QQ):153r"""154The ring of modular forms (of weights 0 or at least 2) for a congruence155subgroup of `{\rm SL}_2(\ZZ)`, with coefficients in a specified base ring.156157INPUT:158159- ``group`` -- a congruence subgroup of `{\rm SL}_2(\ZZ)`, or a160positive integer `N` (interpreted as `\Gamma_0(N)`)161162- ``base_ring`` (ring, default: `\QQ`) -- a base ring, which should be163`\QQ`, `\ZZ`, or the integers mod `p` for some prime `p`.164165EXAMPLES::166167sage: ModularFormsRing(Gamma1(13))168Ring of modular forms for Congruence Subgroup Gamma1(13) with coefficients in Rational Field169sage: m = ModularFormsRing(4); m170Ring of modular forms for Congruence Subgroup Gamma0(4) with coefficients in Rational Field171sage: m.modular_forms_of_weight(2)172Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(4) of weight 2 over Rational Field173sage: m.modular_forms_of_weight(10)174Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(4) of weight 10 over Rational Field175sage: m == loads(dumps(m))176True177sage: m.generators()178[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),179(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10))]180sage: m.q_expansion_basis(2,10)181[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),182q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]183sage: m.q_expansion_basis(3,10)184[]185sage: m.q_expansion_basis(10,10)186[1 + 10560*q^6 + 3960*q^8 + O(q^10),187q - 8056*q^7 - 30855*q^9 + O(q^10),188q^2 - 796*q^6 - 8192*q^8 + O(q^10),189q^3 + 66*q^7 + 832*q^9 + O(q^10),190q^4 + 40*q^6 + 528*q^8 + O(q^10),191q^5 + 20*q^7 + 190*q^9 + O(q^10)]192"""193if isinstance(group, (int, long, Integer)):194group = Gamma0(group)195elif not is_CongruenceSubgroup(group):196raise ValueError("Group (=%s) should be a congruence subgroup")197198if base_ring != ZZ and not base_ring.is_prime_field():199raise ValueError("Base ring (=%s) should be QQ, ZZ or a finite prime field")200201self.__group = group202self.__base_ring = base_ring203self.__cached_maxweight = ZZ(-1)204self.__cached_gens = []205self.__cached_cusp_maxweight = ZZ(-1)206self.__cached_cusp_gens = []207208209210def group(self):211r"""212Return the congruence subgroup for which this is the ring of modular forms.213214EXAMPLE::215216sage: R = ModularFormsRing(Gamma1(13))217sage: R.group() is Gamma1(13)218True219"""220return self.__group221222def base_ring(self):223r"""224Return the coefficient ring of this modular forms ring.225226EXAMPLE::227228sage: ModularFormsRing(Gamma1(13)).base_ring()229Rational Field230sage: ModularFormsRing(Gamma1(13), base_ring = ZZ).base_ring()231Integer Ring232"""233return self.__base_ring234235def __cmp__(self, other):236r"""237Compare self to other. Rings are equal if and only if their groups and238base rings are.239240EXAMPLE::241242sage: ModularFormsRing(3) == 3243False244sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(7))245False246sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(3))247True248"""249250if not isinstance(other, ModularFormsRing):251return cmp( type(self), type(other) )252else:253return cmp(self.group(), other.group()) or cmp(self.base_ring(), other.base_ring())254255def _repr_(self):256r"""257String representation of self.258259EXAMPLES::260261sage: ModularFormsRing(Gamma0(13))._repr_()262'Ring of modular forms for Congruence Subgroup Gamma0(13) with coefficients in Rational Field'263sage: ModularFormsRing(Gamma1(13), base_ring=ZZ)._repr_()264'Ring of modular forms for Congruence Subgroup Gamma1(13) with coefficients in Integer Ring'265"""266return "Ring of modular forms for %s with coefficients in %s" % (self.group(), self.base_ring())267268def modular_forms_of_weight(self, weight):269"""270Return the space of modular forms on this group of the given weight.271272EXAMPLES::273274sage: R = ModularFormsRing(13)275sage: R.modular_forms_of_weight(10)276Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(13) of weight 10 over Rational Field277sage: ModularFormsRing(Gamma1(13)).modular_forms_of_weight(3)278Modular Forms space of dimension 20 for Congruence Subgroup Gamma1(13) of weight 3 over Rational Field279"""280return ModularForms(self.group(), weight)281282def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2):283r"""284If `R` is the base ring of self, then this function calculates a set of285modular forms which generate the `R`-algebra of all modular forms of286weight up to ``maxweight`` with coefficients in `R`.287288INPUT:289290- ``maxweight`` (integer, default: 8) -- check up to this weight for291generators292293- ``prec`` (integer, default: 10) -- return `q`-expansions to this294precision295296- ``start_gens`` (list, default: ``[]``) -- list of pairs `(k, f)`, or297triples `(k, f, F)`, where:298299- `k` is an integer,300- `f` is the `q`-expansion of a modular form of weight `k`, as a power series over the base ring of self,301- `F` (if provided) is a modular form object corresponding to F.302303If this list is nonempty, we find a minimal generating set containing304these forms. If `F` is not supplied, then `f` needs to have305sufficiently large precision (an error will be raised if this is not306the case); otherwise, more terms will be calculated from the modular307form object `F`.308309- ``start_weight`` (integer, default: 2) -- calculate the graded310subalgebra of forms of weight at least ``start_weight``.311312OUTPUT:313314a list of pairs (k, f), where f is the q-expansion to precision315``prec`` of a modular form of weight k.316317.. seealso::318319:meth:`gen_forms`, which does exactly the same thing, but returns320Sage modular form objects rather than bare power series, and keeps321track of a lifting to characteristic 0 when the base ring is a322finite field.323324.. note::325326If called with the default values of ``start_gens`` (an empty list)327and ``start_weight`` (2), the values will be cached for re-use on328subsequent calls to this function. (This cache is shared with329:meth:`gen_forms`). If called with non-default values for these330parameters, caching will be disabled.331332EXAMPLES::333334sage: ModularFormsRing(SL2Z).generators()335[(4, 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + 60480*q^6 + 82560*q^7 + 140400*q^8 + 181680*q^9 + O(q^10)), (6, 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 - 4058208*q^6 - 8471232*q^7 - 17047800*q^8 - 29883672*q^9 + O(q^10))]336sage: s = ModularFormsRing(SL2Z).generators(maxweight=5, prec=3); s337[(4, 1 + 240*q + 2160*q^2 + O(q^3))]338sage: s[0][1].parent()339Power Series Ring in q over Rational Field340341sage: ModularFormsRing(1).generators(prec=4)342[(4, 1 + 240*q + 2160*q^2 + 6720*q^3 + O(q^4)), (6, 1 - 504*q - 16632*q^2 - 122976*q^3 + O(q^4))]343sage: ModularFormsRing(2).generators(prec=12)344[(2, 1 + 24*q + 24*q^2 + 96*q^3 + 24*q^4 + 144*q^5 + 96*q^6 + 192*q^7 + 24*q^8 + 312*q^9 + 144*q^10 + 288*q^11 + O(q^12)), (4, 1 + 240*q^2 + 2160*q^4 + 6720*q^6 + 17520*q^8 + 30240*q^10 + O(q^12))]345sage: ModularFormsRing(4).generators(maxweight=2, prec=20)346[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + 144*q^10 + 96*q^12 + 192*q^14 + 24*q^16 + 312*q^18 + O(q^20)), (2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + 12*q^11 + 14*q^13 + 24*q^15 + 18*q^17 + 20*q^19 + O(q^20))]347348Here we see that for ``\Gamma_0(11)`` taking a basis of forms in weights 2349and 4 is enough to generate everything up to weight 12 (and probably350everything else).::351352sage: v = ModularFormsRing(11).generators(maxweight=12)353sage: len(v)3543355sage: [k for k, _ in v]356[2, 2, 4]357sage: dimension_modular_forms(11,2)3582359sage: dimension_modular_forms(11,4)3604361362For congruence subgroups not containing -1, we miss out some forms since we363can't calculate weight 1 forms at present, but we can still find generators364for the ring of forms of weight `\ge 2`::365366sage: ModularFormsRing(Gamma1(4)).generators(prec=10, maxweight=10)367[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),368(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)),369(3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^10)),370(3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + 73*q^9 + O(q^10))]371372Using different base rings will change the generators::373374sage: ModularFormsRing(Gamma0(13)).generators(maxweight=12, prec=4)375[(2, 1 + 2*q + 6*q^2 + 8*q^3 + O(q^4)), (4, 1 + O(q^4)), (4, q + O(q^4)), (4, q^2 + O(q^4)), (4, q^3 + O(q^4)), (6, 1 + O(q^4)), (6, q + O(q^4))]376sage: ModularFormsRing(Gamma0(13),base_ring=ZZ).generators(maxweight=12, prec=4)377[(2, 1 + 2*q + 6*q^2 + 8*q^3 + O(q^4)), (4, O(q^4)), (4, q^3 + O(q^4)), (4, q^2 + O(q^4)), (4, q + O(q^4)), (6, O(q^4)), (6, O(q^4)), (12, O(q^4))]378379sage: [k for k,f in ModularFormsRing(1, QQ).generators(maxweight=12)]380[4, 6]381sage: [k for k,f in ModularFormsRing(1, ZZ).generators(maxweight=12)]382[4, 6, 12]383sage: [k for k,f in ModularFormsRing(1, Zmod(5)).generators(maxweight=12)]384[4, 6]385sage: [k for k,f in ModularFormsRing(1, Zmod(2)).generators(maxweight=12)]386[4, 6, 12]387388An example where ``start_gens`` are specified::389390sage: M = ModularForms(11, 2); f = (M.0 + M.1).qexp(8)391sage: ModularFormsRing(11).generators(start_gens = [(2, f)])392Traceback (most recent call last):393...394ValueError: Requested precision cannot be higher than precision of approximate starting generators!395sage: f = (M.0 + M.1).qexp(10); f3961 + 17/5*q + 26/5*q^2 + 43/5*q^3 + 94/5*q^4 + 77/5*q^5 + 154/5*q^6 + 86/5*q^7 + 36*q^8 + 146/5*q^9 + O(q^10)397sage: ModularFormsRing(11).generators(start_gens = [(2, f)])398[(2, 1 + 17/5*q + 26/5*q^2 + 43/5*q^3 + 94/5*q^4 + 77/5*q^5 + 154/5*q^6 + 86/5*q^7 + 36*q^8 + 146/5*q^9 + O(q^10)), (2, 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + 24*q^6 + 24*q^7 + 36*q^8 + 36*q^9 + O(q^10)), (4, 1 + O(q^10))]399"""400sgs = []401for x in start_gens:402if len(x) == 2:403if x[1].prec() < prec:404raise ValueError("Requested precision cannot be higher than precision of approximate starting generators!")405sgs.append((x[0], x[1], None))406else:407sgs.append(x)408409G = self._find_generators(maxweight, tuple(sgs), start_weight)410411ret = []412# Returned generators may be a funny mixture of precisions if start_gens has been used.413for k, f, F in G:414if f.prec() < prec:415f = F.qexp(prec).change_ring(self.base_ring())416else:417f = f.truncate_powerseries(prec)418ret.append((k, f))419420return ret421422423def gen_forms(self, maxweight=8, start_gens=[], start_weight=2):424r"""425This function calculates a list of modular forms generating this ring426(as an algebra over the appropriate base ring). It differs from427:meth:`generators` only in that it returns Sage modular form objects,428rather than bare `q`-expansions; and if the base ring is a finite429field, the modular forms returned will be forms in characteristic 0430with integral `q`-expansions whose reductions modulo `p` generate the431ring of modular forms mod `p`.432433INPUT:434435- ``maxweight`` (integer, default: 8) -- calculate forms generating all436forms up to this weight.437438- ``start_gens`` (list, default: ``[]``) -- a list of modular forms. If439this list is nonempty, we find a minimal generating set containing440these forms.441442- ``start_weight`` (integer, default: 2) -- calculate the graded443subalgebra of forms of weight at least ``start_weight``.444445.. note::446447If called with the default values of ``start_gens`` (an empty list)448and ``start_weight`` (2), the values will be cached for re-use on449subsequent calls to this function. (This cache is shared with450:meth:`generators`). If called with non-default values for these451parameters, caching will be disabled.452453EXAMPLE::454455sage: A = ModularFormsRing(Gamma0(11), Zmod(5)).gen_forms(); A456[1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6), q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), q - 9*q^4 - 10*q^5 + O(q^6)]457sage: A[0].parent()458Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field459"""460sgs = tuple( (F.weight(), None, F) for F in start_gens )461G = self._find_generators(maxweight, sgs, start_weight)462return [F for k,f,F in G]463464def _find_generators(self, maxweight, start_gens, start_weight):465r"""466For internal use. This function is called by :meth:`generators` and467:meth:`gen_forms`: it returns a list of triples `(k, f, F)` where `F`468is a modular form of weight `k` and `f` is its `q`-expansion coerced469into the base ring of self.470471INPUT:472473- maxweight: maximum weight to try474- start_weight: minimum weight to try475- start_gens: a sequence of tuples of the form `(k, f, F)`, where `F` is a476modular form of weight `k` and `f` is its `q`-expansion coerced into477``self.base_ring()`. Either (but not both) of `f` and `F` may be478None.479480OUTPUT:481482a list of tuples, formatted as with ``start_gens``.483484EXAMPLE::485486sage: R = ModularFormsRing(Gamma1(4))487sage: R._find_generators(8, (), 2)488[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^9), 1 + 24*q^2 + 24*q^4 + O(q^6)), (2, q + 4*q^3 + 6*q^5 + 8*q^7 + O(q^9), q + 4*q^3 + 6*q^5 + O(q^6)), (3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^9), 1 + 12*q^2 + 64*q^3 + 60*q^4 + O(q^6)), (3, q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + 32*q^6 + 48*q^7 + 64*q^8 + O(q^9), q + 4*q^2 + 8*q^3 + 16*q^4 + 26*q^5 + O(q^6))]489"""490default_params = (start_gens == () and start_weight == 2)491492if default_params and self.__cached_maxweight != -1:493verbose("Already know generators up to weight %s -- using those" % self.__cached_maxweight)494495if self.__cached_maxweight >= maxweight:496return [(k, f, F) for k, f, F in self.__cached_gens if k <= maxweight]497498start_gens = self.__cached_gens499start_weight = self.__cached_maxweight + 1500501if self.group().is_even():502increment = 2503else:504increment = 1505506working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()507508# parse the list of start gens509G = []510for x in start_gens:511k, f, F = x512if F is None and f.prec() < working_prec:513raise ValueError("Need start gens to precision at least %s" % working_prec)514elif f is None or f.prec() < working_prec:515f = F.qexp(working_prec).change_ring(self.base_ring())516G.append((k, f, F))517518k = start_weight519if increment == 2 and (k % 2) == 1: k += 1520521while k <= maxweight:522523if self.modular_forms_of_weight(k).dimension() == 0:524k += increment525continue526527verbose('Looking at k = %s'%k)528M = self.modular_forms_of_weight(k)529530# 1. Multiply together all forms in G that give an element531# of M.532if G != []:533F = _span_of_forms_in_weight(G, k, M.sturm_bound(), None, False)534else:535F = (self.base_ring() ** M.sturm_bound()).zero_submodule()536537# 2. If the dimension of the span of the result is equal538# to the dimension of M, increment k.539if F.rank() == M.dimension():540if self.base_ring().is_field() or F.index_in_saturation() == 1:541# TODO: Do something clever if the submodule's of the right542# rank but not saturated -- avoid triggering needless543# modular symbol computations.544verbose('Nothing new in weight %s' % k)545k += increment546continue547548# 3. If the dimension is less, compute a basis for G, and549# try adding basis elements of M into G.550551verbose("Known generators span a subspace of dimension %s of space of dimension %s" % (F.dimension(), M.dimension()))552if self.base_ring() == ZZ: verbose("saturation index is %s" % F.index_in_saturation())553554t = verbose("Computing more modular forms at weight %s" % k)555kprec = M.sturm_bound()556if self.base_ring() == QQ:557B = M.q_echelon_basis(working_prec)558else:559B = M.q_integral_basis(working_prec)560t = verbose("done computing forms", t)561V = F.ambient_module().submodule_with_basis([f.padded_list(kprec) for f in B])562Q = V / F563for q in Q.gens():564try:565qc = V.coordinates(Q.lift(q))566except AttributeError:567# work around a silly free module bug568qc = V.coordinates(q.lift())569qcZZ = map(ZZ, qc) # lift to ZZ so we can define F570f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])571F = M(f)572G.append((k, f.change_ring(self.base_ring()), F))573574verbose('added %s new generators' % Q.ngens(), t)575k += increment576577if default_params:578self.__cached_maxweight = maxweight579self.__cached_gens = G580581return G582583@cached_method584def q_expansion_basis(self, weight, prec=None, use_random=True):585r"""586Calculate a basis of q-expansions for the space of modular forms of the587given weight for this group, calculated using the ring generators given588by ``find_generators``.589590INPUT:591592- ``weight`` (integer) -- the weight593- ``prec`` (integer or ``None``, default: ``None``) -- power series594precision. If ``None``, the precision defaults to the Sturm bound for595the requested level and weight.596- ``use_random`` (boolean, default: True) -- whether or not to use a597randomized algorithm when building up the space of forms at the given598weight from known generators of small weight.599600EXAMPLES::601602sage: m = ModularFormsRing(Gamma0(4))603sage: m.q_expansion_basis(2,10)604[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),605q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]606sage: m.q_expansion_basis(3,10)607[]608609sage: X = ModularFormsRing(SL2Z)610sage: X.q_expansion_basis(12, 10)611[1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + 34417656000*q^6 + 187489935360*q^7 + 814879774800*q^8 + 2975551488000*q^9 + O(q^10),612q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 + O(q^10)]613614We calculate a basis of a massive modular forms space, in two ways.615Using this module is about twice as fast as Sage's generic code. ::616617sage: A = ModularFormsRing(11).q_expansion_basis(30, prec=40) # long time (5s)618sage: B = ModularForms(Gamma0(11), 30).q_echelon_basis(prec=40) # long time (9s)619sage: A == B # long time620True621622Check that absurdly small values of ``prec`` don't mess things up::623624sage: ModularFormsRing(11).q_expansion_basis(10, prec=5)625[1 + O(q^5), q + O(q^5), q^2 + O(q^5), q^3 + O(q^5), q^4 + O(q^5), O(q^5), O(q^5), O(q^5), O(q^5), O(q^5)]626"""627d = self.modular_forms_of_weight(weight).dimension()628if d == 0: return []629630if prec is None:631prec=self.modular_forms_of_weight(weight).sturm_bound()632633working_prec = max(prec, self.modular_forms_of_weight(weight).sturm_bound())634635gen_weight = min(6, weight)636637while 1:638verbose("Trying to generate the %s-dimensional space at weight %s using generators of weight up to %s" % (d, weight, gen_weight))639G = self.generators(maxweight=gen_weight, prec=working_prec)640V = _span_of_forms_in_weight(G, weight, prec=working_prec, use_random=use_random, stop_dim=d)641if V.rank() == d and (self.base_ring().is_field() or V.index_in_saturation() == 1):642break643else:644gen_weight += 1645verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)646647R = G[0][1].parent()648return [R(list(x), prec=prec) for x in V.gens()]649650def cuspidal_ideal_generators(self, maxweight=8, prec=None):651r"""652Calculate generators for the ideal of cuspidal forms in this ring, as a653module over the whole ring.654655EXAMPLE::656657sage: ModularFormsRing(Gamma0(3)).cuspidal_ideal_generators(maxweight=12)658[(6, q - 6*q^2 + 9*q^3 + 4*q^4 + O(q^5), q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6))]659sage: [k for k,f,F in ModularFormsRing(13, base_ring=ZZ).cuspidal_ideal_generators(maxweight=14)]660[4, 4, 4, 6, 6, 12]661"""662working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()663664if self.__cached_cusp_maxweight > -1:665k = self.__cached_cusp_maxweight + 1666verbose("Already calculated cusp gens up to weight %s -- using those" % (k-1))667668# we may need to increase the precision of the cached cusp669# generators670G = []671for j,f,F in self.__cached_cusp_gens:672if f.prec() >= working_prec:673f = F.qexp(working_prec).change_ring(self.base_ring())674G.append( (j,f,F) )675else:676k = 2677G = []678679680while k <= maxweight:681t = verbose("Looking for cusp generators in weight %s" % k)682683kprec = self.modular_forms_of_weight(k).sturm_bound()684685flist = []686687for (j, f, F) in G:688for g in self.q_expansion_basis(k - j, prec=kprec):689flist.append(g*f)690A = self.base_ring() ** kprec691W = A.span([A(f.padded_list(kprec)) for f in flist])692693S = self.modular_forms_of_weight(k).cuspidal_submodule()694if (W.rank() == S.dimension()695and (self.base_ring().is_field() or W.index_in_saturation() == 1)):696verbose("Nothing new in weight %s" % k, t)697k += 1698continue699700t = verbose("Known cusp generators span a submodule of dimension %s of space of dimension %s" % (W.rank(), S.dimension()), t)701702B = S.q_integral_basis(prec=working_prec)703V = A.span([A(f.change_ring(self.base_ring()).padded_list(kprec)) for f in B])704Q = V/W705706for q in Q.gens():707try:708qc = V.coordinates(Q.lift(q))709except AttributeError:710# work around a silly free module bug711qc = V.coordinates(q.lift())712qcZZ = map(ZZ, qc) # lift to ZZ so we can define F713f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])714F = S(f)715G.append((k, f.change_ring(self.base_ring()), F))716717verbose('added %s new generators' % Q.ngens(), t)718k += 1719720self.__cached_cusp_maxweight = maxweight721self.__cached_cusp_gens = G722723if prec is None:724return G725elif prec <= working_prec:726return [ (k, f.truncate_powerseries(prec), F) for k,f,F in G]727else:728# user wants increased precision, so we may as well cache that729Gnew = [ (k, F.qexp(prec).change_ring(self.base_ring()), F) for k,f,F in G]730self.__cached_cusp_gens = Gnew731return Gnew732733def cuspidal_submodule_q_expansion_basis(self, weight, prec=None):734r"""735Calculate a basis of `q`-expansions for the space of cusp forms of736weight ``weight`` for this group.737738INPUT:739740- ``weight`` (integer) -- the weight741- ``prec`` (integer or None) -- precision of `q`-expansions to return742743ALGORITHM: Uses the method :meth:`cuspidal_ideal_generators` to744calculate generators of the ideal of cusp forms inside this ring. Then745multiply these up to weight ``weight`` using the generators of the746whole modular form space returned by :meth:`q_expansion_basis`.747748EXAMPLES::749750sage: R = ModularFormsRing(Gamma0(3))751sage: R.cuspidal_submodule_q_expansion_basis(20)752[q - 8532*q^6 - 88442*q^7 + O(q^8), q^2 + 207*q^6 + 24516*q^7 + O(q^8), q^3 + 456*q^6 + O(q^8), q^4 - 135*q^6 - 926*q^7 + O(q^8), q^5 + 18*q^6 + 135*q^7 + O(q^8)]753754We compute a basis of a space of very large weight, quickly (using this755module) and slowly (using modular symbols), and verify that the answers756are the same. ::757758sage: A=R.cuspidal_submodule_q_expansion_basis(80, prec=30)759sage: B=R.modular_forms_of_weight(80).cuspidal_submodule().q_expansion_basis(prec=30) # long time (20s)760sage: A == B # long time761True762"""763d = self.modular_forms_of_weight(weight).cuspidal_submodule().dimension()764if d == 0: return []765766minprec = self.modular_forms_of_weight(weight).sturm_bound()767if prec is None:768prec = working_prec = minprec769else:770working_prec = max(prec, minprec)771772gen_weight = min(6, weight)773774while 1:775verbose("Trying to generate the %s-dimensional cuspidal submodule at weight %s using generators of weight up to %s" % (d, weight, gen_weight))776G = self.cuspidal_ideal_generators(maxweight=gen_weight, prec=working_prec)777778flist = []779for (j, f, F) in G:780for g in self.q_expansion_basis(weight - j, prec=working_prec):781flist.append(g*f)782783A = self.base_ring() ** working_prec784W = A.span([A(f.padded_list(working_prec)) for f in flist])785if W.rank() == d and (self.base_ring().is_field() or W.index_in_saturation() == 1):786break787else:788gen_weight += 1789verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)790791R = G[0][1].parent()792return [R(list(x), prec=prec) for x in W.gens()]793794795