Path: blob/master/src/sage/modular/modform/find_generators.py
8820 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)]192193TESTS:194195Check that :trac:`15037` is fixed::196197sage: ModularFormsRing(3.4)198Traceback (most recent call last):199...200ValueError: Group (=3.40000000000000) should be a congruence subgroup201sage: ModularFormsRing(Gamma0(2), base_ring=PolynomialRing(ZZ,x))202Traceback (most recent call last):203...204ValueError: Base ring (=Univariate Polynomial Ring in x over Integer Ring) should be QQ, ZZ or a finite prime field205"""206if isinstance(group, (int, long, Integer)):207group = Gamma0(group)208elif not is_CongruenceSubgroup(group):209raise ValueError("Group (=%s) should be a congruence subgroup" % group)210211if base_ring != ZZ and not base_ring.is_prime_field():212raise ValueError("Base ring (=%s) should be QQ, ZZ or a finite prime field" % base_ring)213214self.__group = group215self.__base_ring = base_ring216self.__cached_maxweight = ZZ(-1)217self.__cached_gens = []218self.__cached_cusp_maxweight = ZZ(-1)219self.__cached_cusp_gens = []220221def group(self):222r"""223Return the congruence subgroup for which this is the ring of modular forms.224225EXAMPLE::226227sage: R = ModularFormsRing(Gamma1(13))228sage: R.group() is Gamma1(13)229True230"""231return self.__group232233def base_ring(self):234r"""235Return the coefficient ring of this modular forms ring.236237EXAMPLE::238239sage: ModularFormsRing(Gamma1(13)).base_ring()240Rational Field241sage: ModularFormsRing(Gamma1(13), base_ring = ZZ).base_ring()242Integer Ring243"""244return self.__base_ring245246def __cmp__(self, other):247r"""248Compare self to other. Rings are equal if and only if their groups and249base rings are.250251EXAMPLE::252253sage: ModularFormsRing(3) == 3254False255sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(7))256False257sage: ModularFormsRing(Gamma0(3)) == ModularFormsRing(Gamma0(3))258True259"""260261if not isinstance(other, ModularFormsRing):262return cmp( type(self), type(other) )263else:264return cmp(self.group(), other.group()) or cmp(self.base_ring(), other.base_ring())265266def _repr_(self):267r"""268String representation of self.269270EXAMPLES::271272sage: ModularFormsRing(Gamma0(13))._repr_()273'Ring of modular forms for Congruence Subgroup Gamma0(13) with coefficients in Rational Field'274sage: ModularFormsRing(Gamma1(13), base_ring=ZZ)._repr_()275'Ring of modular forms for Congruence Subgroup Gamma1(13) with coefficients in Integer Ring'276"""277return "Ring of modular forms for %s with coefficients in %s" % (self.group(), self.base_ring())278279def modular_forms_of_weight(self, weight):280"""281Return the space of modular forms on this group of the given weight.282283EXAMPLES::284285sage: R = ModularFormsRing(13)286sage: R.modular_forms_of_weight(10)287Modular Forms space of dimension 11 for Congruence Subgroup Gamma0(13) of weight 10 over Rational Field288sage: ModularFormsRing(Gamma1(13)).modular_forms_of_weight(3)289Modular Forms space of dimension 20 for Congruence Subgroup Gamma1(13) of weight 3 over Rational Field290"""291return ModularForms(self.group(), weight)292293def generators(self, maxweight=8, prec=10, start_gens=[], start_weight=2):294r"""295If `R` is the base ring of self, then this function calculates a set of296modular forms which generate the `R`-algebra of all modular forms of297weight up to ``maxweight`` with coefficients in `R`.298299INPUT:300301- ``maxweight`` (integer, default: 8) -- check up to this weight for302generators303304- ``prec`` (integer, default: 10) -- return `q`-expansions to this305precision306307- ``start_gens`` (list, default: ``[]``) -- list of pairs `(k, f)`, or308triples `(k, f, F)`, where:309310- `k` is an integer,311- `f` is the `q`-expansion of a modular form of weight `k`, as a power series over the base ring of self,312- `F` (if provided) is a modular form object corresponding to F.313314If this list is nonempty, we find a minimal generating set containing315these forms. If `F` is not supplied, then `f` needs to have316sufficiently large precision (an error will be raised if this is not317the case); otherwise, more terms will be calculated from the modular318form object `F`.319320- ``start_weight`` (integer, default: 2) -- calculate the graded321subalgebra of forms of weight at least ``start_weight``.322323OUTPUT:324325a list of pairs (k, f), where f is the q-expansion to precision326``prec`` of a modular form of weight k.327328.. seealso::329330:meth:`gen_forms`, which does exactly the same thing, but returns331Sage modular form objects rather than bare power series, and keeps332track of a lifting to characteristic 0 when the base ring is a333finite field.334335.. note::336337If called with the default values of ``start_gens`` (an empty list)338and ``start_weight`` (2), the values will be cached for re-use on339subsequent calls to this function. (This cache is shared with340:meth:`gen_forms`). If called with non-default values for these341parameters, caching will be disabled.342343EXAMPLES::344345sage: ModularFormsRing(SL2Z).generators()346[(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))]347sage: s = ModularFormsRing(SL2Z).generators(maxweight=5, prec=3); s348[(4, 1 + 240*q + 2160*q^2 + O(q^3))]349sage: s[0][1].parent()350Power Series Ring in q over Rational Field351352sage: ModularFormsRing(1).generators(prec=4)353[(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))]354sage: ModularFormsRing(2).generators(prec=12)355[(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))]356sage: ModularFormsRing(4).generators(maxweight=2, prec=20)357[(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))]358359Here we see that for ``\Gamma_0(11)`` taking a basis of forms in weights 2360and 4 is enough to generate everything up to weight 12 (and probably361everything else).::362363sage: v = ModularFormsRing(11).generators(maxweight=12)364sage: len(v)3653366sage: [k for k, _ in v]367[2, 2, 4]368sage: dimension_modular_forms(11,2)3692370sage: dimension_modular_forms(11,4)3714372373For congruence subgroups not containing -1, we miss out some forms since we374can't calculate weight 1 forms at present, but we can still find generators375for the ring of forms of weight `\ge 2`::376377sage: ModularFormsRing(Gamma1(4)).generators(prec=10, maxweight=10)378[(2, 1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10)),379(2, q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)),380(3, 1 + 12*q^2 + 64*q^3 + 60*q^4 + 160*q^6 + 384*q^7 + 252*q^8 + O(q^10)),381(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))]382383Using different base rings will change the generators::384385sage: ModularFormsRing(Gamma0(13)).generators(maxweight=12, prec=4)386[(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))]387sage: ModularFormsRing(Gamma0(13),base_ring=ZZ).generators(maxweight=12, prec=4)388[(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))]389390sage: [k for k,f in ModularFormsRing(1, QQ).generators(maxweight=12)]391[4, 6]392sage: [k for k,f in ModularFormsRing(1, ZZ).generators(maxweight=12)]393[4, 6, 12]394sage: [k for k,f in ModularFormsRing(1, Zmod(5)).generators(maxweight=12)]395[4, 6]396sage: [k for k,f in ModularFormsRing(1, Zmod(2)).generators(maxweight=12)]397[4, 6, 12]398399An example where ``start_gens`` are specified::400401sage: M = ModularForms(11, 2); f = (M.0 + M.1).qexp(8)402sage: ModularFormsRing(11).generators(start_gens = [(2, f)])403Traceback (most recent call last):404...405ValueError: Requested precision cannot be higher than precision of approximate starting generators!406sage: f = (M.0 + M.1).qexp(10); f4071 + 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)408sage: ModularFormsRing(11).generators(start_gens = [(2, f)])409[(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))]410"""411sgs = []412for x in start_gens:413if len(x) == 2:414if x[1].prec() < prec:415raise ValueError("Requested precision cannot be higher than precision of approximate starting generators!")416sgs.append((x[0], x[1], None))417else:418sgs.append(x)419420G = self._find_generators(maxweight, tuple(sgs), start_weight)421422ret = []423# Returned generators may be a funny mixture of precisions if start_gens has been used.424for k, f, F in G:425if f.prec() < prec:426f = F.qexp(prec).change_ring(self.base_ring())427else:428f = f.truncate_powerseries(prec)429ret.append((k, f))430431return ret432433434def gen_forms(self, maxweight=8, start_gens=[], start_weight=2):435r"""436This function calculates a list of modular forms generating this ring437(as an algebra over the appropriate base ring). It differs from438:meth:`generators` only in that it returns Sage modular form objects,439rather than bare `q`-expansions; and if the base ring is a finite440field, the modular forms returned will be forms in characteristic 0441with integral `q`-expansions whose reductions modulo `p` generate the442ring of modular forms mod `p`.443444INPUT:445446- ``maxweight`` (integer, default: 8) -- calculate forms generating all447forms up to this weight.448449- ``start_gens`` (list, default: ``[]``) -- a list of modular forms. If450this list is nonempty, we find a minimal generating set containing451these forms.452453- ``start_weight`` (integer, default: 2) -- calculate the graded454subalgebra of forms of weight at least ``start_weight``.455456.. note::457458If called with the default values of ``start_gens`` (an empty list)459and ``start_weight`` (2), the values will be cached for re-use on460subsequent calls to this function. (This cache is shared with461:meth:`generators`). If called with non-default values for these462parameters, caching will be disabled.463464EXAMPLE::465466sage: A = ModularFormsRing(Gamma0(11), Zmod(5)).gen_forms(); A467[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)]468sage: A[0].parent()469Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field470"""471sgs = tuple( (F.weight(), None, F) for F in start_gens )472G = self._find_generators(maxweight, sgs, start_weight)473return [F for k,f,F in G]474475def _find_generators(self, maxweight, start_gens, start_weight):476r"""477For internal use. This function is called by :meth:`generators` and478:meth:`gen_forms`: it returns a list of triples `(k, f, F)` where `F`479is a modular form of weight `k` and `f` is its `q`-expansion coerced480into the base ring of self.481482INPUT:483484- maxweight: maximum weight to try485- start_weight: minimum weight to try486- start_gens: a sequence of tuples of the form `(k, f, F)`, where `F` is a487modular form of weight `k` and `f` is its `q`-expansion coerced into488``self.base_ring()`. Either (but not both) of `f` and `F` may be489None.490491OUTPUT:492493a list of tuples, formatted as with ``start_gens``.494495EXAMPLE::496497sage: R = ModularFormsRing(Gamma1(4))498sage: R._find_generators(8, (), 2)499[(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))]500"""501default_params = (start_gens == () and start_weight == 2)502503if default_params and self.__cached_maxweight != -1:504verbose("Already know generators up to weight %s -- using those" % self.__cached_maxweight)505506if self.__cached_maxweight >= maxweight:507return [(k, f, F) for k, f, F in self.__cached_gens if k <= maxweight]508509start_gens = self.__cached_gens510start_weight = self.__cached_maxweight + 1511512if self.group().is_even():513increment = 2514else:515increment = 1516517working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()518519# parse the list of start gens520G = []521for x in start_gens:522k, f, F = x523if F is None and f.prec() < working_prec:524raise ValueError("Need start gens to precision at least %s" % working_prec)525elif f is None or f.prec() < working_prec:526f = F.qexp(working_prec).change_ring(self.base_ring())527G.append((k, f, F))528529k = start_weight530if increment == 2 and (k % 2) == 1: k += 1531532while k <= maxweight:533534if self.modular_forms_of_weight(k).dimension() == 0:535k += increment536continue537538verbose('Looking at k = %s'%k)539M = self.modular_forms_of_weight(k)540541# 1. Multiply together all forms in G that give an element542# of M.543if G != []:544F = _span_of_forms_in_weight(G, k, M.sturm_bound(), None, False)545else:546F = (self.base_ring() ** M.sturm_bound()).zero_submodule()547548# 2. If the dimension of the span of the result is equal549# to the dimension of M, increment k.550if F.rank() == M.dimension():551if self.base_ring().is_field() or F.index_in_saturation() == 1:552# TODO: Do something clever if the submodule's of the right553# rank but not saturated -- avoid triggering needless554# modular symbol computations.555verbose('Nothing new in weight %s' % k)556k += increment557continue558559# 3. If the dimension is less, compute a basis for G, and560# try adding basis elements of M into G.561562verbose("Known generators span a subspace of dimension %s of space of dimension %s" % (F.dimension(), M.dimension()))563if self.base_ring() == ZZ: verbose("saturation index is %s" % F.index_in_saturation())564565t = verbose("Computing more modular forms at weight %s" % k)566kprec = M.sturm_bound()567if self.base_ring() == QQ:568B = M.q_echelon_basis(working_prec)569else:570B = M.q_integral_basis(working_prec)571t = verbose("done computing forms", t)572V = F.ambient_module().submodule_with_basis([f.padded_list(kprec) for f in B])573Q = V / F574for q in Q.gens():575try:576qc = V.coordinates(Q.lift(q))577except AttributeError:578# work around a silly free module bug579qc = V.coordinates(q.lift())580qcZZ = map(ZZ, qc) # lift to ZZ so we can define F581f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])582F = M(f)583G.append((k, f.change_ring(self.base_ring()), F))584585verbose('added %s new generators' % Q.ngens(), t)586k += increment587588if default_params:589self.__cached_maxweight = maxweight590self.__cached_gens = G591592return G593594@cached_method595def q_expansion_basis(self, weight, prec=None, use_random=True):596r"""597Calculate a basis of q-expansions for the space of modular forms of the598given weight for this group, calculated using the ring generators given599by ``find_generators``.600601INPUT:602603- ``weight`` (integer) -- the weight604- ``prec`` (integer or ``None``, default: ``None``) -- power series605precision. If ``None``, the precision defaults to the Sturm bound for606the requested level and weight.607- ``use_random`` (boolean, default: True) -- whether or not to use a608randomized algorithm when building up the space of forms at the given609weight from known generators of small weight.610611EXAMPLES::612613sage: m = ModularFormsRing(Gamma0(4))614sage: m.q_expansion_basis(2,10)615[1 + 24*q^2 + 24*q^4 + 96*q^6 + 24*q^8 + O(q^10),616q + 4*q^3 + 6*q^5 + 8*q^7 + 13*q^9 + O(q^10)]617sage: m.q_expansion_basis(3,10)618[]619620sage: X = ModularFormsRing(SL2Z)621sage: X.q_expansion_basis(12, 10)622[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),623q - 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)]624625We calculate a basis of a massive modular forms space, in two ways.626Using this module is about twice as fast as Sage's generic code. ::627628sage: A = ModularFormsRing(11).q_expansion_basis(30, prec=40) # long time (5s)629sage: B = ModularForms(Gamma0(11), 30).q_echelon_basis(prec=40) # long time (9s)630sage: A == B # long time631True632633Check that absurdly small values of ``prec`` don't mess things up::634635sage: ModularFormsRing(11).q_expansion_basis(10, prec=5)636[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)]637"""638d = self.modular_forms_of_weight(weight).dimension()639if d == 0: return []640641if prec is None:642prec=self.modular_forms_of_weight(weight).sturm_bound()643644working_prec = max(prec, self.modular_forms_of_weight(weight).sturm_bound())645646gen_weight = min(6, weight)647648while 1:649verbose("Trying to generate the %s-dimensional space at weight %s using generators of weight up to %s" % (d, weight, gen_weight))650G = self.generators(maxweight=gen_weight, prec=working_prec)651V = _span_of_forms_in_weight(G, weight, prec=working_prec, use_random=use_random, stop_dim=d)652if V.rank() == d and (self.base_ring().is_field() or V.index_in_saturation() == 1):653break654else:655gen_weight += 1656verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)657658R = G[0][1].parent()659return [R(list(x), prec=prec) for x in V.gens()]660661def cuspidal_ideal_generators(self, maxweight=8, prec=None):662r"""663Calculate generators for the ideal of cuspidal forms in this ring, as a664module over the whole ring.665666EXAMPLE::667668sage: ModularFormsRing(Gamma0(3)).cuspidal_ideal_generators(maxweight=12)669[(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))]670sage: [k for k,f,F in ModularFormsRing(13, base_ring=ZZ).cuspidal_ideal_generators(maxweight=14)]671[4, 4, 4, 6, 6, 12]672"""673working_prec = self.modular_forms_of_weight(maxweight).sturm_bound()674675if self.__cached_cusp_maxweight > -1:676k = self.__cached_cusp_maxweight + 1677verbose("Already calculated cusp gens up to weight %s -- using those" % (k-1))678679# we may need to increase the precision of the cached cusp680# generators681G = []682for j,f,F in self.__cached_cusp_gens:683if f.prec() >= working_prec:684f = F.qexp(working_prec).change_ring(self.base_ring())685G.append( (j,f,F) )686else:687k = 2688G = []689690691while k <= maxweight:692t = verbose("Looking for cusp generators in weight %s" % k)693694kprec = self.modular_forms_of_weight(k).sturm_bound()695696flist = []697698for (j, f, F) in G:699for g in self.q_expansion_basis(k - j, prec=kprec):700flist.append(g*f)701A = self.base_ring() ** kprec702W = A.span([A(f.padded_list(kprec)) for f in flist])703704S = self.modular_forms_of_weight(k).cuspidal_submodule()705if (W.rank() == S.dimension()706and (self.base_ring().is_field() or W.index_in_saturation() == 1)):707verbose("Nothing new in weight %s" % k, t)708k += 1709continue710711t = verbose("Known cusp generators span a submodule of dimension %s of space of dimension %s" % (W.rank(), S.dimension()), t)712713B = S.q_integral_basis(prec=working_prec)714V = A.span([A(f.change_ring(self.base_ring()).padded_list(kprec)) for f in B])715Q = V/W716717for q in Q.gens():718try:719qc = V.coordinates(Q.lift(q))720except AttributeError:721# work around a silly free module bug722qc = V.coordinates(q.lift())723qcZZ = map(ZZ, qc) # lift to ZZ so we can define F724f = sum([B[i] * qcZZ[i] for i in xrange(len(B))])725F = S(f)726G.append((k, f.change_ring(self.base_ring()), F))727728verbose('added %s new generators' % Q.ngens(), t)729k += 1730731self.__cached_cusp_maxweight = maxweight732self.__cached_cusp_gens = G733734if prec is None:735return G736elif prec <= working_prec:737return [ (k, f.truncate_powerseries(prec), F) for k,f,F in G]738else:739# user wants increased precision, so we may as well cache that740Gnew = [ (k, F.qexp(prec).change_ring(self.base_ring()), F) for k,f,F in G]741self.__cached_cusp_gens = Gnew742return Gnew743744def cuspidal_submodule_q_expansion_basis(self, weight, prec=None):745r"""746Calculate a basis of `q`-expansions for the space of cusp forms of747weight ``weight`` for this group.748749INPUT:750751- ``weight`` (integer) -- the weight752- ``prec`` (integer or None) -- precision of `q`-expansions to return753754ALGORITHM: Uses the method :meth:`cuspidal_ideal_generators` to755calculate generators of the ideal of cusp forms inside this ring. Then756multiply these up to weight ``weight`` using the generators of the757whole modular form space returned by :meth:`q_expansion_basis`.758759EXAMPLES::760761sage: R = ModularFormsRing(Gamma0(3))762sage: R.cuspidal_submodule_q_expansion_basis(20)763[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)]764765We compute a basis of a space of very large weight, quickly (using this766module) and slowly (using modular symbols), and verify that the answers767are the same. ::768769sage: A = R.cuspidal_submodule_q_expansion_basis(80, prec=30) # long time (1s on sage.math, 2013)770sage: B = R.modular_forms_of_weight(80).cuspidal_submodule().q_expansion_basis(prec=30) # long time (19s on sage.math, 2013)771sage: A == B # long time772True773"""774d = self.modular_forms_of_weight(weight).cuspidal_submodule().dimension()775if d == 0: return []776777minprec = self.modular_forms_of_weight(weight).sturm_bound()778if prec is None:779prec = working_prec = minprec780else:781working_prec = max(prec, minprec)782783gen_weight = min(6, weight)784785while 1:786verbose("Trying to generate the %s-dimensional cuspidal submodule at weight %s using generators of weight up to %s" % (d, weight, gen_weight))787G = self.cuspidal_ideal_generators(maxweight=gen_weight, prec=working_prec)788789flist = []790for (j, f, F) in G:791for g in self.q_expansion_basis(weight - j, prec=working_prec):792flist.append(g*f)793794A = self.base_ring() ** working_prec795W = A.span([A(f.padded_list(working_prec)) for f in flist])796if W.rank() == d and (self.base_ring().is_field() or W.index_in_saturation() == 1):797break798else:799gen_weight += 1800verbose("Need more generators: trying again with generators of weight up to %s" % gen_weight)801802R = G[0][1].parent()803return [R(list(x), prec=prec) for x in W.gens()]804805806