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
r""" Modular forms for Hecke triangle groups
AUTHORS:
- Jonas Jermann (2013): initial version
"""
#***************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann <jjermann2@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/ #*****************************************************************************
r""" Abstract (Hecke) forms space.
This should never be called directly. Instead one should instantiate one of the derived classes of this class. """
r""" Abstract (Hecke) forms space.
INPUT:
- ``group`` -- The Hecke triangle group (default: ``HeckeTriangleGroup(3)``)
- ``k`` -- The weight (default: `0`)
- ``ep`` -- The epsilon (default: ``None``). If ``None``, then k*(n-2) has to be divisible by `2` and ``ep=(-1)^(k*(n-2)/2)`` is used.
- ``base_ring`` -- The base_ring (default: `\Z`).
OUTPUT:
The corresponding abstract (Hecke) forms space.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=5, base_ring=ZZ, k=6, ep=-1) sage: MF ModularForms(n=5, k=6, ep=-1) over Integer Ring sage: MF.group() Hecke triangle group for n = 5 sage: MF.base_ring() Integer Ring sage: MF.weight() 6 sage: MF.ep() -1 sage: MF.has_reduce_hom() True sage: MF.is_homogeneous() True """
#from space import canonical_parameters #(group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep, n)
#self.register_embedding(self.hom(lambda f: f.parent().graded_ring()(f), codomain=self.graded_ring()))
r""" Return the string representation of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: QuasiModularForms(n=4, k=2, ep=-1) QuasiModularForms(n=4, k=2, ep=-1) over Integer Ring """
r""" Return the LaTeX representation of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms sage: latex(QuasiWeakModularForms()) QM^!_{ n=3 }(0,\ 1)(\Bold{Z}) """
r""" Return ``el`` coerced into this forms space.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.graded_ring import MeromorphicModularFormsRing sage: from sage.modular.modform_hecketriangle.space import ModularForms, QuasiWeakModularForms sage: MF = ModularForms(k=12, ep=1) sage: (x,y,z,d) = MF.pol_ring().gens()
sage: Delta = MeromorphicModularFormsRing().Delta() sage: Delta.parent() MeromorphicModularFormsRing(n=3) over Integer Ring sage: MF(Delta) q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5) sage: MF(Delta).parent() == MF True
sage: E2 = MF.E2() sage: e2 = QuasiWeakModularForms(n=infinity, k=2, ep=-1)(E2) sage: e2 1 - 24*q^2 - 72*q^4 + O(q^5) sage: e2.parent() QuasiWeakModularForms(n=+Infinity, k=2, ep=-1) over Integer Ring sage: e2.as_ring_element() (-f_i + 3*E2)/2 sage: MF(x^3) 1 + 720*q + 179280*q^2 + 16954560*q^3 + 396974160*q^4 + O(q^5) sage: MF(x^3).parent() == MF True
sage: qexp = Delta.q_expansion(prec=2) sage: qexp q + O(q^2) sage: qexp.parent() Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: MF(qexp) q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5) sage: MF(qexp) == MF(Delta) True
sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1) sage: QF.default_prec(2) sage: el2 = QF.quasi_part_gens(min_exp=-1)[4] sage: el2.reduced_parent() QuasiWeakModularForms(n=8, k=10/3, ep=-1) over Integer Ring sage: prec = QF.required_laurent_prec(min_exp=-1) sage: qexp2 = el2.q_expansion(prec=prec) sage: qexp2 q^-1 - 19/(64*d) - 7497/(262144*d^2)*q + 15889/(8388608*d^3)*q^2 + 543834047/(1649267441664*d^4)*q^3 + 711869853/(43980465111040*d^5)*q^4 + O(q^5) sage: qexp2.parent() Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: QF(qexp2) q^-1 - 19/(64*d) - 7497/(262144*d^2)*q + O(q^2) sage: QF(qexp2).reduced_parent() QuasiWeakModularForms(n=8, k=10/3, ep=-1) over Integer Ring sage: QF(qexp2) == el2 True
sage: QF = QuasiWeakModularForms(n=infinity, k=2, ep=-1) sage: el3 = QF.f_i() + QF.f_i()^3/QF.E4() sage: prec = QF.required_laurent_prec(order_1=-1) sage: qexp3 = el3.q_expansion(prec=prec) sage: qexp3 2 - 7/(4*d)*q + 195/(256*d^2)*q^2 - 903/(4096*d^3)*q^3 + 41987/(1048576*d^4)*q^4 - 181269/(33554432*d^5)*q^5 + O(q^6) sage: QF.construct_quasi_form(qexp3, check=False) == el3 False sage: QF.construct_quasi_form(qexp3, order_1=-1) == el3 True
sage: MF([0,1]) == MF(Delta) True sage: MF([1,0]) == MF(x^3) - 720*MF(Delta) True
sage: vec = MF(Delta).coordinate_vector() sage: vec (0, 1) sage: vec.parent() Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: vec in MF.module() True sage: MF(vec) == MF(Delta) True
sage: subspace = MF.subspace([MF(Delta)]) sage: subspace Subspace of dimension 1 of ModularForms(n=3, k=12, ep=1) over Integer Ring sage: subspace(MF(Delta)) == subspace(d*(x^3-y^2)) == subspace(qexp) == subspace([0,1]) == subspace(vec) == subspace.gen() True sage: subspace(MF(Delta)).parent() == subspace(d*(x^3-y^2)).parent() == subspace(qexp).parent() == subspace([0,1]).parent() == subspace(vec).parent() True sage: subspace([1]) == subspace.gen() True sage: ssvec = subspace(vec).coordinate_vector() sage: ssvec (1) sage: ssvec.parent() Vector space of dimension 1 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: ambvec = subspace(vec).ambient_coordinate_vector() sage: ambvec (0, 1) sage: ambvec.parent() Vector space of degree 2 and dimension 1 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring Basis matrix: [0 1] sage: subspace(ambvec) == subspace(vec) and subspace(ambvec).parent() == subspace(vec).parent() True """
else: raise ValueError("{} has group {} != {}".format(el, el.group(), self.group())) # This assumes that the series corresponds to a _weakly # holomorphic_ (quasi) form. It also assumes that the form is # holomorphic at -1 for n=infinity (this assumption however # can be changed in construct_form # resp. construct_quasi_form)) else: except (ArithmeticError, TypeError): pass return self.element_from_ambient_coordinates(self.ambient_module()(el)) except (ArithmeticError, TypeError): pass
r""" Return whether or not there exists a coercion from ``S`` to ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, CuspForms, ZeroForm sage: MF1 = QuasiWeakModularForms(n=4, base_ring=CC, k=0, ep=1) sage: MF2 = ModularForms(n=4, k=24, ep=1) sage: MF3 = ModularForms(n=4, k=24, ep=-1) sage: MF4 = CuspForms(n=4, k=0, ep=1) sage: MF5 = ZeroForm(n=4, k=10, ep=-1) sage: MF6 = QuasiWeakModularForms(n=3, k=24, ep=1) sage: MF7 = QuasiWeakModularForms(n=infinity, k=24, ep=1) sage: subspace1 = MF3.subspace([MF3.gen(0), MF3.gen(1)]) sage: subspace2 = MF3.subspace([MF3.gen(2)]) sage: subspace3 = MF3.subspace([MF3.gen(0), MF3.gen(0)+MF3.gen(2)])
sage: MF2.has_coerce_map_from(MF3) False sage: MF1.has_coerce_map_from(MF4) True sage: MF4.has_coerce_map_from(MF5) True sage: MF4.has_coerce_map_from(ZZ) False sage: MF1.has_coerce_map_from(ZZ) True sage: MF7.has_coerce_map_from(MF6) True sage: MF7.has_coerce_map_from(MF2) False sage: MF3.has_coerce_map_from(subspace1) True sage: subspace1.has_coerce_map_from(MF3) False sage: subspace3.has_coerce_map_from(subspace1) False sage: subspace3.has_coerce_map_from(subspace2) True """
and isinstance(self, SubSpaceForms) ): else: return False and self.graded_ring().has_coerce_map_from(S.graded_ring())\ and S.weight() == self._weight\ and S.ep() == self._ep\ and not isinstance(self, SubSpaceForms)): else: and self.coeff_ring().has_coerce_map_from(S)
# Since forms spaces are modules instead of rings # we have to manually define one(). # one() allows to take the power 0 of an element def one(self): r""" Return the one element from the corresponding space of constant forms.
Note: The one element does not lie in ``self`` in general.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: MF = CuspForms(k=12) sage: MF.Delta()^0 == MF.one() True sage: (MF.Delta()^0).parent() ModularForms(n=3, k=0, ep=1) over Integer Ring """
r""" Return the one element from the corresponding space of constant forms.
Note: The one element does not lie in ``self`` in general.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: MF = CuspForms(k=12) sage: (MF.Delta()^(-1)).parent() MeromorphicModularForms(n=3, k=-12, ep=1) over Integer Ring sage: MF.one_element() doctest:...: DeprecationWarning: .one_element() is deprecated. Use .one() instead. See http://trac.sagemath.org/17694 for details. 1 + O(q^5) """
r""" Return whether ``self`` is an ambient space.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=12) sage: MF.is_ambient() True sage: MF.subspace([MF.gen(0)]).is_ambient() False """
r""" Return the ambient space of self.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=12) sage: MF.ambient_space() ModularForms(n=3, k=12, ep=1) over Integer Ring sage: MF.ambient_space() == MF True sage: subspace = MF.subspace([MF.gen(0)]) sage: subspace Subspace of dimension 1 of ModularForms(n=3, k=12, ep=1) over Integer Ring sage: subspace.ambient_space() == MF True """
r""" Return the module associated to self.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=12) sage: MF.module() Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: subspace = MF.subspace([MF.gen(0)]) sage: subspace.module() Vector space of degree 2 and dimension 1 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring Basis matrix: [1 0] """
r""" Return the module associated to the ambient space of self.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=12) sage: MF.ambient_module() Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: MF.ambient_module() == MF.module() True sage: subspace = MF.subspace([MF.gen(0)]) sage: subspace.ambient_module() == MF.module() True """
r""" Return the subspace of ``self`` generated by ``basis``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=24) sage: MF.dimension() 3 sage: subspace = MF.subspace([MF.gen(0), MF.gen(1)]) sage: subspace Subspace of dimension 2 of ModularForms(n=3, k=24, ep=1) over Integer Ring """
r""" Return the same space as ``self`` but over a new base ring ``new_base_ring``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: CuspForms(n=5, k=24).change_ring(CC) CuspForms(n=5, k=24, ep=1) over Complex Field with 53 bits of precision """
r""" Return a functor that constructs ``self`` (used by the coercion machinery).
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: QuasiModularForms(n=4, k=2, ep=1, base_ring=CC).construction() (QuasiModularFormsFunctor(n=4, k=2, ep=1), BaseFacade(Complex Field with 53 bits of precision))
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF=ModularForms(k=12) sage: MF.subspace([MF.gen(1)]).construction() (FormsSubSpaceFunctor with 1 generator for the ModularFormsFunctor(n=3, k=12, ep=1), BaseFacade(Integer Ring)) """
else:
def weight(self): r""" Return the weight of (elements of) ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: QuasiModularForms(n=16, k=16/7, ep=-1).weight() 16/7 """
def ep(self): r""" Return the multiplier of (elements of) ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: QuasiModularForms(n=16, k=16/7, ep=-1).ep() -1 """
def contains_coeff_ring(self): r""" Return whether ``self`` contains its coefficient ring.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: QuasiModularForms(k=0, ep=1, n=8).contains_coeff_ring() True sage: QuasiModularForms(k=0, ep=-1, n=8).contains_coeff_ring() False """
r""" If ``self`` has an associated free module, then return the element of ``self`` corresponding to the given coordinate vector ``vec``. Otherwise raise an exception.
INPUT:
- ``vec`` -- A coordinate vector with respect to ``self.gens()``.
OUTPUT:
An element of ``self`` corresponding to the coordinate vector ``vec``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=24) sage: MF.dimension() 3 sage: el = MF.element_from_coordinates([1,1,1]) sage: el 1 + q + q^2 + 52611612*q^3 + 39019413208*q^4 + O(q^5) sage: el == MF.gen(0) + MF.gen(1) + MF.gen(2) True sage: el.parent() == MF True
sage: subspace = MF.subspace([MF.gen(0), MF.gen(1)]) sage: el = subspace.element_from_coordinates([1,1]) sage: el 1 + q + 52611660*q^3 + 39019412128*q^4 + O(q^5) sage: el == subspace.gen(0) + subspace.gen(1) True sage: el.parent() == subspace True """
raise ValueError("No free module defined for {}".format(self)) # vec = self.module()(self.module().linear_combination_of_basis(vec)) # this also handles the trivial case (dimension 0)
r""" If ``self`` has an associated free module, then return the element of ``self`` corresponding to the given ``vec``. Otherwise raise an exception.
INPUT:
- ``vec`` -- An element of ``self.module()`` or ``self.ambient_module()``.
OUTPUT:
An element of ``self`` corresponding to ``vec``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=24) sage: MF.dimension() 3 sage: el = MF.element_from_ambient_coordinates([1,1,1]) sage: el == MF.element_from_coordinates([1,1,1]) True sage: el.parent() == MF True
sage: subspace = MF.subspace([MF.gen(0), MF.gen(1)]) sage: el = subspace.element_from_ambient_coordinates([1,1,0]) sage: el 1 + q + 52611660*q^3 + 39019412128*q^4 + O(q^5) sage: el.parent() == subspace True """
r""" Since ``self`` already is a homogeneous component return ``self`` unless the degree differs in which case a ``ValueError`` is raised.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms sage: MF = QuasiMeromorphicModularForms(n=6, k=4) sage: MF == MF.homogeneous_part(4,1) True sage: MF.homogeneous_part(5,1) Traceback (most recent call last): ... ValueError: QuasiMeromorphicModularForms(n=6, k=4, ep=1) over Integer Ring already is homogeneous with degree (4, 1) != (5, 1)! """
else:
r""" Check whether ``self`` has a valid weight and multiplier.
If not then an exception is raised. Otherwise the two weight parameters corresponding to the weight and multiplier of ``self`` are returned.
The weight parameters are e.g. used to calculate dimensions or precisions of Fourier expansion.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import MeromorphicModularForms sage: MF = MeromorphicModularForms(n=18, k=-7, ep=-1) sage: MF.weight_parameters() (-3, 17) sage: (MF._l1, MF._l2) == MF.weight_parameters() True sage: (k, ep) = (MF.weight(), MF.ep()) sage: n = MF.hecke_n() sage: k == 4*(n*MF._l1 + MF._l2)/(n-2) + (1-ep)*n/(n-2) True
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=5, k=12, ep=1) sage: MF.weight_parameters() (1, 4) sage: (MF._l1, MF._l2) == MF.weight_parameters() True sage: (k, ep) = (MF.weight(), MF.ep()) sage: n = MF.hecke_n() sage: k == 4*(n*MF._l1 + MF._l2)/(n-2) + (1-ep)*n/(n-2) True sage: MF.dimension() == MF._l1 + 1 True
sage: MF = ModularForms(n=infinity, k=8, ep=1) sage: MF.weight_parameters() (2, 0) sage: MF.dimension() == MF._l1 + 1 True """
else: # TODO: Figure out what to do in this case # (l1 and l2 are no longer defined in an analog/unique way) #l2 = num % ZZ(2) #l1 = ((num-l2)/ZZ(2)).numerator() ## TODO: The correct generalization seems (l1,l2) = (0,num) else: else: raise ValueError("Invalid or non-occuring weight k={}, ep={}!".format(k,ep))
# TODO: this only makes sense for modular forms, # resp. needs a big adjustment for quasi modular forms r""" The automorphy factor of ``self``.
INPUT:
- ``gamma`` -- An element of the group of ``self``.
- ``t`` -- An element of the upper half plane.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=8, k=4, ep=1) sage: full_factor = lambda mat, t: (mat[1][0]*t+mat[1][1])**4 sage: T = MF.group().T() sage: S = MF.group().S() sage: i = AlgebraicField()(i) sage: z = 1 + i/2
sage: MF.aut_factor(S, z) 3/2*I - 7/16 sage: MF.aut_factor(-T^(-2), z) 1 sage: MF.aut_factor(MF.group().V(6), z) 173.2640595631...? + 343.8133289126...?*I sage: MF.aut_factor(S, z) == full_factor(S, z) True sage: MF.aut_factor(T, z) == full_factor(T, z) True sage: MF.aut_factor(MF.group().V(6), z) == full_factor(MF.group().V(6), z) True
sage: MF = ModularForms(n=7, k=14/5, ep=-1) sage: T = MF.group().T() sage: S = MF.group().S()
sage: MF.aut_factor(S, z) 1.3655215324256...? + 0.056805991182877...?*I sage: MF.aut_factor(-T^(-2), z) 1 sage: MF.aut_factor(S, z) == MF.ep() * (z/i)^MF.weight() True sage: MF.aut_factor(MF.group().V(6), z) 13.23058830577...? + 15.71786610686...?*I """
else:
r""" Return a (the most) simple normalized element of ``self`` corresponding to the weight parameters ``l1=self._l1`` and ``l2=self._l2``. If the element does not lie in ``self`` the type of its parent is extended accordingly.
The main part of the element is given by the ``(l1 - order_1)``-th power of ``f_inf``, up to a small holomorphic correction factor.
INPUT:
- ``order_1`` -- An integer (default: 0) denoting the desired order at ``-1`` in the case ``n = infinity``. If ``n != infinity`` the parameter is ignored.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms sage: MF = WeakModularForms(n=18, k=-7, ep=-1) sage: MF.disp_prec(1) sage: MF.F_simple() q^-3 + 16/(81*d)*q^-2 - 4775/(104976*d^2)*q^-1 - 14300/(531441*d^3) + O(q) sage: MF.F_simple() == MF.f_inf()^MF._l1 * MF.f_rho()^MF._l2 * MF.f_i() True
sage: from sage.modular.modform_hecketriangle.space import CuspForms, ModularForms sage: MF = CuspForms(n=5, k=2, ep=-1) sage: MF._l1 -1 sage: MF.F_simple().parent() WeakModularForms(n=5, k=2, ep=-1) over Integer Ring
sage: MF = ModularForms(n=infinity, k=8, ep=1) sage: MF.F_simple().reduced_parent() ModularForms(n=+Infinity, k=8, ep=1) over Integer Ring sage: MF.F_simple() q^2 - 16*q^3 + 120*q^4 + O(q^5) sage: MF.F_simple(order_1=2) 1 + 32*q + 480*q^2 + 4480*q^3 + 29152*q^4 + O(q^5) """
else:
else:
r""" Return the ``m``'th Faber polynomial of ``self``.
Namely a polynomial ``P(q)`` such that ``P(J_inv)*F_simple(order_1)`` has a Fourier expansion of the form ``q^m + O(q^(order_inf + 1))``. where ``order_inf = self._l1 - order_1`` and ``d^(order_inf - m)*P(q)`` is a monic polynomial of degree ``order_inf - m``.
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the parameter ``order_1`` (default: 0). Otherwise it is ignored.
The Faber polynomials are e.g. used to construct a basis of weakly holomorphic forms and to recover such forms from their initial Fourier coefficients.
INPUT:
- ``m`` -- An integer ``m <= order_inf = self._l1 - order_1``.
- ``order_1`` -- The order at ``-1`` of F_simple (default: 0). This parameter is ignored if ``n != infinity``.
- ``fix_d`` -- If ``False`` (default) a formal parameter is used for ``d``. If ``True`` then the numerical value of ``d`` is used (resp. an exact value if the group is arithmetic). Otherwise the given value is used for ``d``.
- ``d_num_prec`` -- The precision to be used if a numerical value for ``d`` is substituted. Default: ``None`` in which case the default numerical precision of ``self.parent()`` is used.
OUTPUT:
The corresponding Faber polynomial ``P(q)``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms sage: MF = WeakModularForms(n=5, k=62/3, ep=-1) sage: MF.weight_parameters() (2, 3)
sage: MF.Faber_pol(2) 1 sage: MF.Faber_pol(1) 1/d*q - 19/(100*d) sage: MF.Faber_pol(0) 1/d^2*q^2 - 117/(200*d^2)*q + 9113/(320000*d^2) sage: MF.Faber_pol(-2) 1/d^4*q^4 - 11/(8*d^4)*q^3 + 41013/(80000*d^4)*q^2 - 2251291/(48000000*d^4)*q + 1974089431/(4915200000000*d^4) sage: (MF.Faber_pol(2)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2) q^2 - 41/(200*d)*q^3 + O(q^4) sage: (MF.Faber_pol(1)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1) q + O(q^3) sage: (MF.Faber_pol(0)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1) 1 + O(q^3) sage: (MF.Faber_pol(-2)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1) q^-2 + O(q^3)
sage: MF.Faber_pol(2, fix_d=1) 1 sage: MF.Faber_pol(1, fix_d=1) q - 19/100 sage: MF.Faber_pol(-2, fix_d=1) q^4 - 11/8*q^3 + 41013/80000*q^2 - 2251291/48000000*q + 1974089431/4915200000000 sage: (MF.Faber_pol(2, fix_d=1)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=1) q^2 - 41/200*q^3 + O(q^4) sage: (MF.Faber_pol(-2)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1, fix_d=1) q^-2 + O(q^3)
sage: MF = WeakModularForms(n=4, k=-2, ep=1) sage: MF.weight_parameters() (-1, 3)
sage: MF.Faber_pol(-1) 1 sage: MF.Faber_pol(-2, fix_d=True) 256*q - 184 sage: MF.Faber_pol(-3, fix_d=True) 65536*q^2 - 73728*q + 14364 sage: (MF.Faber_pol(-1, fix_d=True)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True) q^-1 + 80 + O(q) sage: (MF.Faber_pol(-2, fix_d=True)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True) q^-2 + 400 + O(q) sage: (MF.Faber_pol(-3)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True) q^-3 + 2240 + O(q)
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1) sage: MF.Faber_pol(3) 1 sage: MF.Faber_pol(2) 1/d*q + 3/(8*d) sage: MF.Faber_pol(1) 1/d^2*q^2 + 75/(1024*d^2) sage: MF.Faber_pol(0) 1/d^3*q^3 - 3/(8*d^3)*q^2 + 3/(512*d^3)*q + 41/(4096*d^3) sage: MF.Faber_pol(-1) 1/d^4*q^4 - 3/(4*d^4)*q^3 + 81/(1024*d^4)*q^2 + 9075/(8388608*d^4) sage: (MF.Faber_pol(-1)(MF.J_inv())*MF.F_simple()).q_expansion(prec=MF._l1 + 1) q^-1 + O(q^4)
sage: MF.Faber_pol(3, order_1=-1) 1/d*q + 3/(4*d) sage: MF.Faber_pol(1, order_1=2) 1 sage: MF.Faber_pol(0, order_1=2) 1/d*q - 3/(8*d) sage: MF.Faber_pol(-1, order_1=2) 1/d^2*q^2 - 3/(4*d^2)*q + 81/(1024*d^2) sage: (MF.Faber_pol(-1, order_1=2)(MF.J_inv())*MF.F_simple(order_1=2)).q_expansion(prec=MF._l1 + 1) q^-1 - 9075/(8388608*d^4)*q^3 + O(q^4) """
else:
raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf))
# The precision could be infinity, otherwise we could do this: #assert(temp_reminder.prec() == 1)
# The first term is zero only up to numerical errors, # so we manually have to remove it temp_reminder=temp_reminder.truncate_neg(-temp_exp+1)
# very similar to Faber_pol: faber_pol(q)=Faber_pol(d*q) r""" If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the parameter ``order_1`` (default: 0). Otherwise it is ignored. Return the `m`'th Faber polynomial of ``self`` with a different normalization based on ``j_inv`` instead of ``J_inv``.
Namely a polynomial ``p(q)`` such that ``p(j_inv)*F_simple()`` has a Fourier expansion of the form ``q^m + O(q^(order_inf + 1))``. where ``order_inf = self._l1 - order_1`` and ``p(q)`` is a monic polynomial of degree ``order_inf - m``.
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the parameter ``order_1`` (default: 0). Otherwise it is ignored.
The relation to ``Faber_pol`` is: ``faber_pol(q) = Faber_pol(d*q)``.
INPUT:
- ``m`` -- An integer ``m <= self._l1 - order_1``.
- ``order_1`` -- The order at ``-1`` of ``F_simple`` (default: 0). This parameter is ignored if ``n != infinity``.
- ``fix_d`` -- If ``False`` (default) a formal parameter is used for ``d``. If ``True`` then the numerical value of ``d`` is used (resp. an exact value if the group is arithmetic). Otherwise the given value is used for ``d``.
- ``d_num_prec`` -- The precision to be used if a numerical value for ``d`` is substituted. Default: ``None`` in which case the default numerical precision of ``self.parent()`` is used.
OUTPUT:
The corresponding Faber polynomial ``p(q)``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms sage: MF = WeakModularForms(n=5, k=62/3, ep=-1) sage: MF.weight_parameters() (2, 3)
sage: MF.faber_pol(2) 1 sage: MF.faber_pol(1) q - 19/(100*d) sage: MF.faber_pol(0) q^2 - 117/(200*d)*q + 9113/(320000*d^2) sage: MF.faber_pol(-2) q^4 - 11/(8*d)*q^3 + 41013/(80000*d^2)*q^2 - 2251291/(48000000*d^3)*q + 1974089431/(4915200000000*d^4) sage: (MF.faber_pol(2)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2) q^2 - 41/(200*d)*q^3 + O(q^4) sage: (MF.faber_pol(1)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1) q + O(q^3) sage: (MF.faber_pol(0)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1) 1 + O(q^3) sage: (MF.faber_pol(-2)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+1) q^-2 + O(q^3)
sage: MF = WeakModularForms(n=4, k=-2, ep=1) sage: MF.weight_parameters() (-1, 3)
sage: MF.faber_pol(-1) 1 sage: MF.faber_pol(-2, fix_d=True) q - 184 sage: MF.faber_pol(-3, fix_d=True) q^2 - 288*q + 14364 sage: (MF.faber_pol(-1, fix_d=True)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True) q^-1 + 80 + O(q) sage: (MF.faber_pol(-2, fix_d=True)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True) q^-2 + 400 + O(q) sage: (MF.faber_pol(-3)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1+2, fix_d=True) q^-3 + 2240 + O(q)
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1) sage: MF.faber_pol(3) 1 sage: MF.faber_pol(2) q + 3/(8*d) sage: MF.faber_pol(1) q^2 + 75/(1024*d^2) sage: MF.faber_pol(0) q^3 - 3/(8*d)*q^2 + 3/(512*d^2)*q + 41/(4096*d^3) sage: MF.faber_pol(-1) q^4 - 3/(4*d)*q^3 + 81/(1024*d^2)*q^2 + 9075/(8388608*d^4) sage: (MF.faber_pol(-1)(MF.j_inv())*MF.F_simple()).q_expansion(prec=MF._l1 + 1) q^-1 + O(q^4)
sage: MF.faber_pol(3, order_1=-1) q + 3/(4*d) sage: MF.faber_pol(1, order_1=2) 1 sage: MF.faber_pol(0, order_1=2) q - 3/(8*d) sage: MF.faber_pol(-1, order_1=2) q^2 - 3/(4*d)*q + 81/(1024*d^2) sage: (MF.faber_pol(-1, order_1=2)(MF.j_inv())*MF.F_simple(order_1=2)).q_expansion(prec=MF._l1 + 1) q^-1 - 9075/(8388608*d^4)*q^3 + O(q^4) """
else:
raise ValueError("Invalid basis index: m = {} > {} = order_inf!".format(m, order_inf))
# The precision could be infinity, otherwise we could do this: #assert(temp_reminder.prec() == 1)
# The first term is zero only up to numerical errors, # so we manually have to remove it temp_reminder=temp_reminder.truncate_neg(-temp_exp+1)
r""" Returns a polynomial corresponding to the basis element of the corresponding space of weakly holomorphic forms of the same degree as ``self``. The basis element is determined by the property that the Fourier expansion is of the form ``q^m + O(q^(order_inf + 1))``, where ``order_inf = self._l1 - order_1``.
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the parameter ``order_1`` (default: 0). Otherwise it is ignored.
INPUT:
- ``m`` -- An integer ``m <= self._l1``.
- ``order_1`` -- The order at ``-1`` of ``F_simple`` (default: 0). This parameter is ignored if ``n != infinity``.
OUTPUT:
A polynomial in ``x,y,z,d``, corresponding to ``f_rho, f_i, E2`` and the (possibly) transcendental parameter ``d``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms sage: MF = WeakModularForms(n=5, k=62/3, ep=-1) sage: MF.weight_parameters() (2, 3)
sage: MF.F_basis_pol(2) x^13*y*d^2 - 2*x^8*y^3*d^2 + x^3*y^5*d^2 sage: MF.F_basis_pol(1) (-81*x^13*y*d + 62*x^8*y^3*d + 19*x^3*y^5*d)/(-100) sage: MF.F_basis_pol(0) (141913*x^13*y + 168974*x^8*y^3 + 9113*x^3*y^5)/320000
sage: MF(MF.F_basis_pol(2)).q_expansion(prec=MF._l1+2) q^2 - 41/(200*d)*q^3 + O(q^4) sage: MF(MF.F_basis_pol(1)).q_expansion(prec=MF._l1+1) q + O(q^3) sage: MF(MF.F_basis_pol(0)).q_expansion(prec=MF._l1+1) 1 + O(q^3) sage: MF(MF.F_basis_pol(-2)).q_expansion(prec=MF._l1+1) q^-2 + O(q^3) sage: MF(MF.F_basis_pol(-2)).parent() WeakModularForms(n=5, k=62/3, ep=-1) over Integer Ring
sage: MF = WeakModularForms(n=4, k=-2, ep=1) sage: MF.weight_parameters() (-1, 3)
sage: MF.F_basis_pol(-1) x^3/(x^4*d - y^2*d) sage: MF.F_basis_pol(-2) (9*x^7 + 23*x^3*y^2)/(32*x^8*d^2 - 64*x^4*y^2*d^2 + 32*y^4*d^2)
sage: MF(MF.F_basis_pol(-1)).q_expansion(prec=MF._l1+2) q^-1 + 5/(16*d) + O(q) sage: MF(MF.F_basis_pol(-2)).q_expansion(prec=MF._l1+2) q^-2 + 25/(4096*d^2) + O(q)
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1) sage: MF.F_basis_pol(3) -y^7*d^3 + 3*x*y^5*d^3 - 3*x^2*y^3*d^3 + x^3*y*d^3 sage: MF.F_basis_pol(2) (3*y^7*d^2 - 17*x*y^5*d^2 + 25*x^2*y^3*d^2 - 11*x^3*y*d^2)/(-8) sage: MF.F_basis_pol(1) (-75*y^7*d + 225*x*y^5*d - 1249*x^2*y^3*d + 1099*x^3*y*d)/1024 sage: MF.F_basis_pol(0) (41*y^7 - 147*x*y^5 - 1365*x^2*y^3 - 2625*x^3*y)/(-4096) sage: MF.F_basis_pol(-1) (-9075*y^9 + 36300*x*y^7 - 718002*x^2*y^5 - 4928052*x^3*y^3 - 2769779*x^4*y)/(8388608*y^2*d - 8388608*x*d)
sage: MF.F_basis_pol(3, order_1=-1) (-3*y^9*d^3 + 16*x*y^7*d^3 - 30*x^2*y^5*d^3 + 24*x^3*y^3*d^3 - 7*x^4*y*d^3)/(-4*x) sage: MF.F_basis_pol(1, order_1=2) -x^2*y^3*d + x^3*y*d sage: MF.F_basis_pol(0, order_1=2) (-3*x^2*y^3 - 5*x^3*y)/(-8) sage: MF.F_basis_pol(-1, order_1=2) (-81*x^2*y^5 - 606*x^3*y^3 - 337*x^4*y)/(1024*y^2*d - 1024*x*d) """
else:
r""" Returns a weakly holomorphic element of ``self`` (extended if necessarily) determined by the property that the Fourier expansion is of the form is of the form ``q^m + O(q^(order_inf + 1))``, where ``order_inf = self._l1 - order_1``.
In particular for all ``m <= order_inf`` these elements form a basis of the space of weakly holomorphic modular forms of the corresponding degree in case ``n!=infinity``.
If ``n=infinity`` a non-trivial order of ``-1`` can be specified through the parameter ``order_1`` (default: 0). Otherwise it is ignored.
INPUT:
- ``m`` -- An integer ``m <= self._l1``.
- ``order_1`` -- The order at ``-1`` of ``F_simple`` (default: 0). This parameter is ignored if ``n != infinity``.
OUTPUT:
The corresponding element in (possibly an extension of) ``self``. Note that the order at ``-1`` of the resulting element may be bigger than ``order_1`` (rare).
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms, CuspForms sage: MF = WeakModularForms(n=5, k=62/3, ep=-1) sage: MF.disp_prec(MF._l1+2) sage: MF.weight_parameters() (2, 3)
sage: MF.F_basis(2) q^2 - 41/(200*d)*q^3 + O(q^4) sage: MF.F_basis(1) q - 13071/(640000*d^2)*q^3 + O(q^4) sage: MF.F_basis(0) 1 - 277043/(192000000*d^3)*q^3 + O(q^4) sage: MF.F_basis(-2) q^-2 - 162727620113/(40960000000000000*d^5)*q^3 + O(q^4) sage: MF.F_basis(-2).parent() == MF True
sage: MF = CuspForms(n=4, k=-2, ep=1) sage: MF.weight_parameters() (-1, 3)
sage: MF.F_basis(-1).parent() WeakModularForms(n=4, k=-2, ep=1) over Integer Ring sage: MF.F_basis(-1).parent().disp_prec(MF._l1+2) sage: MF.F_basis(-1) q^-1 + 80 + O(q) sage: MF.F_basis(-2) q^-2 + 400 + O(q)
sage: MF = WeakModularForms(n=infinity, k=14, ep=-1) sage: MF.F_basis(3) q^3 - 48*q^4 + O(q^5) sage: MF.F_basis(2) q^2 - 1152*q^4 + O(q^5) sage: MF.F_basis(1) q - 18496*q^4 + O(q^5) sage: MF.F_basis(0) 1 - 224280*q^4 + O(q^5) sage: MF.F_basis(-1) q^-1 - 2198304*q^4 + O(q^5)
sage: MF.F_basis(3, order_1=-1) q^3 + O(q^5) sage: MF.F_basis(1, order_1=2) q - 300*q^3 - 4096*q^4 + O(q^5) sage: MF.F_basis(0, order_1=2) 1 - 24*q^2 - 2048*q^3 - 98328*q^4 + O(q^5) sage: MF.F_basis(-1, order_1=2) q^-1 - 18150*q^3 - 1327104*q^4 + O(q^5) """
else: else: else:
r""" Return an adjusted value of ``min_exp`` and ``order_1`` corresponding to the analytic type of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: CF = CuspForms(n=5, k=16, ep=1) sage: CF._canonical_min_exp(-2, 0) (1, 0)
sage: CF = CuspForms(n=infinity, k=10, ep=-1) sage: CF._canonical_min_exp(-2, -2) (1, 1) """
else:
r""" Return a basis in ``self`` of the subspace of (quasi) weakly holomorphic forms which satisfy the specified properties on the quasi parts and the initial Fourier coefficient.
INPUT:
- ``r`` -- An integer or ``None`` (default), indicating the desired power of ``E2`` If ``r=None`` then all possible powers (``r``) are choosen.
- ``min_exp`` -- An integer giving a lower bound for the first non-trivial Fourier coefficient of the generators (default: 0).
- ``max_exp`` -- An integer or ``infinity`` (default) giving an upper bound for the first non-trivial Fourier coefficient of the generators. If ``max_exp==infinity`` then no upper bound is assumed.
- ``order_1`` -- A lower bound for the order at ``-1`` of all quasi parts of the basis elements (default: 0). If ``n!=infinity`` this parameter is ignored.
OUTPUT:
A basis in ``self`` of the subspace of forms which are modular after dividing by ``E2^r`` and which have a Fourier expansion of the form ``q^m + O(q^(m+1))`` with ``min_exp <= m <= max_exp`` for each quasi part (and at least the specified order at ``-1`` in case ``n=infinity``). Note that linear combinations of forms/quasi parts maybe have a higher order at infinity than ``max_exp``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1) sage: QF.default_prec(1) sage: QF.quasi_part_gens(min_exp=-1) [q^-1 + O(q), 1 + O(q), q^-1 - 9/(128*d) + O(q), 1 + O(q), q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q)]
sage: QF.quasi_part_gens(min_exp=-1, max_exp=-1) [q^-1 + O(q), q^-1 - 9/(128*d) + O(q), q^-1 - 19/(64*d) + O(q), q^-1 + 1/(64*d) + O(q)] sage: QF.quasi_part_gens(min_exp=-2, r=1) [q^-2 - 9/(128*d)*q^-1 - 261/(131072*d^2) + O(q), q^-1 - 9/(128*d) + O(q), 1 + O(q)]
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(k=36) sage: MF.quasi_part_gens(min_exp=2) [q^2 + 194184*q^4 + O(q^5), q^3 - 72*q^4 + O(q^5)]
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms sage: MF = QuasiModularForms(n=5, k=6, ep=-1) sage: MF.default_prec(2) sage: MF.dimension() 3 sage: MF.quasi_part_gens(r=0) [1 - 37/(200*d)*q + O(q^2)] sage: MF.quasi_part_gens(r=0)[0] == MF.E6() True sage: MF.quasi_part_gens(r=1) [1 + 33/(200*d)*q + O(q^2)] sage: MF.quasi_part_gens(r=1)[0] == MF.E2()*MF.E4() True sage: MF.quasi_part_gens(r=2) [] sage: MF.quasi_part_gens(r=3) [1 - 27/(200*d)*q + O(q^2)] sage: MF.quasi_part_gens(r=3)[0] == MF.E2()^3 True
sage: from sage.modular.modform_hecketriangle.space import QuasiCuspForms, CuspForms sage: MF = QuasiCuspForms(n=5, k=18, ep=-1) sage: MF.default_prec(4) sage: MF.dimension() 8 sage: MF.quasi_part_gens(r=0) [q - 34743/(640000*d^2)*q^3 + O(q^4), q^2 - 69/(200*d)*q^3 + O(q^4)] sage: MF.quasi_part_gens(r=1) [q - 9/(200*d)*q^2 + 37633/(640000*d^2)*q^3 + O(q^4), q^2 + 1/(200*d)*q^3 + O(q^4)] sage: MF.quasi_part_gens(r=2) [q - 1/(4*d)*q^2 - 24903/(640000*d^2)*q^3 + O(q^4)] sage: MF.quasi_part_gens(r=3) [q + 1/(10*d)*q^2 - 7263/(640000*d^2)*q^3 + O(q^4)] sage: MF.quasi_part_gens(r=4) [q - 11/(20*d)*q^2 + 53577/(640000*d^2)*q^3 + O(q^4)] sage: MF.quasi_part_gens(r=5) [q - 1/(5*d)*q^2 + 4017/(640000*d^2)*q^3 + O(q^4)]
sage: MF.quasi_part_gens(r=1)[0] == MF.E2() * CuspForms(n=5, k=16, ep=1).gen(0) True sage: MF.quasi_part_gens(r=1)[1] == MF.E2() * CuspForms(n=5, k=16, ep=1).gen(1) True sage: MF.quasi_part_gens(r=3)[0] == MF.E2()^3 * MF.Delta() True
sage: MF = QuasiCuspForms(n=infinity, k=18, ep=-1) sage: MF.quasi_part_gens(r=1, min_exp=-2) == MF.quasi_part_gens(r=1, min_exp=1) True sage: MF.quasi_part_gens(r=1) [q - 8*q^2 - 8*q^3 + 5952*q^4 + O(q^5), q^2 - 8*q^3 + 208*q^4 + O(q^5), q^3 - 16*q^4 + O(q^5)]
sage: MF = QuasiWeakModularForms(n=infinity, k=4, ep=1) sage: MF.quasi_part_gens(r=2, min_exp=2, order_1=-2)[0] == MF.E2()^2 * MF.E4()^(-2) * MF.f_inf()^2 True sage: [v.order_at(-1) for v in MF.quasi_part_gens(r=0, min_exp=2, order_1=-2)] [-2, -2] """
from warnings import warn warn("This function only determines generators of (quasi) weakly modular forms!")
# For modular forms spaces the quasi parts are all zero except for r=0 return []
# The lower bounds on the powers of f_inf and E4 determine # how large powers of E2 we can fit in... else:
# If r is not specified we gather all generators for all possible r's
return [] else:
r""" Return the dimension of the subspace of ``self`` generated by ``self.quasi_part_gens(r, min_exp, max_exp, order_1)``.
See :meth:`quasi_part_gens` for more details.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiModularForms, QuasiCuspForms, QuasiWeakModularForms sage: MF = QuasiModularForms(n=5, k=6, ep=-1) sage: [v.as_ring_element() for v in MF.gens()] [f_rho^2*f_i, f_rho^3*E2, E2^3] sage: MF.dimension() 3 sage: MF.quasi_part_dimension(r=0) 1 sage: MF.quasi_part_dimension(r=1) 1 sage: MF.quasi_part_dimension(r=2) 0 sage: MF.quasi_part_dimension(r=3) 1
sage: MF = QuasiCuspForms(n=5, k=18, ep=-1) sage: MF.dimension() 8 sage: MF.quasi_part_dimension(r=0) 2 sage: MF.quasi_part_dimension(r=1) 2 sage: MF.quasi_part_dimension(r=2) 1 sage: MF.quasi_part_dimension(r=3) 1 sage: MF.quasi_part_dimension(r=4) 1 sage: MF.quasi_part_dimension(r=5) 1 sage: MF.quasi_part_dimension(min_exp=2, max_exp=2) 2
sage: MF = QuasiCuspForms(n=infinity, k=18, ep=-1) sage: MF.quasi_part_dimension(r=1, min_exp=-2) 3 sage: MF.quasi_part_dimension() 12 sage: MF.quasi_part_dimension(order_1=3) 2
sage: MF = QuasiWeakModularForms(n=infinity, k=4, ep=1) sage: MF.quasi_part_dimension(min_exp=2, order_1=-2) 4 sage: [v.order_at(-1) for v in MF.quasi_part_gens(r=0, min_exp=2, order_1=-2)] [-2, -2] """
from warnings import warn warn("This function only determines the dimension of some (quasi) weakly subspace!")
# For modular forms spaces the quasi parts are all zero except for r=0 return ZZ(0)
# The lower bounds on the powers of f_inf and E4 determine # how large powers of E2 we can fit in... else:
# If r is not specified we calculate the total dimension over all possible r's
return ZZ(0)
else:
return ZZ(0) else:
r""" Tries to construct an element of self with the given Fourier expansion. The assumption is made that the specified Fourier expansion corresponds to a weakly holomorphic modular form.
If the precision is too low to determine the element an exception is raised.
INPUT:
- ``laurent_series`` -- A Laurent or Power series.
- ``order_1`` -- A lower bound for the order at ``-1`` of the form (default: 0). If ``n!=infinity`` this parameter is ignored.
- ``check`` -- If ``True`` (default) then the series expansion of the constructed form is compared against the given series.
- ``rationalize`` -- If ``True`` (default: ``False``) then the series is `rationalized` beforehand. Note that in non-exact or non-arithmetic cases this is experimental and extremely unreliable!
OUTPUT:
If possible: An element of self with the same initial Fourier expansion as ``laurent_series``.
Note: For modular spaces it is also possible to call ``self(laurent_series)`` instead.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import CuspForms sage: Delta = CuspForms(k=12).Delta() sage: qexp = Delta.q_expansion(prec=2) sage: qexp.parent() Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: qexp q + O(q^2) sage: CuspForms(k=12).construct_form(qexp) == Delta True
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms sage: J_inv = WeakModularForms(n=7).J_inv() sage: qexp2 = J_inv.q_expansion(prec=1) sage: qexp2.parent() Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: qexp2 d*q^-1 + 151/392 + O(q) sage: WeakModularForms(n=7).construct_form(qexp2) == J_inv True
sage: MF = WeakModularForms(n=5, k=62/3, ep=-1) sage: MF.default_prec(MF._l1+1) sage: d = MF.get_d() sage: MF.weight_parameters() (2, 3) sage: el2 = d*MF.F_basis(2) + 2*MF.F_basis(1) + MF.F_basis(-2) sage: qexp2 = el2.q_expansion() sage: qexp2.parent() Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: qexp2 q^-2 + 2*q + d*q^2 + O(q^3) sage: WeakModularForms(n=5, k=62/3, ep=-1).construct_form(qexp2) == el2 True
sage: MF = WeakModularForms(n=infinity, k=-2, ep=-1) sage: el3 = MF.f_i()/MF.f_inf() + MF.f_i()*MF.f_inf()/MF.E4()^2 sage: MF.quasi_part_dimension(min_exp=-1, order_1=-2) 3 sage: prec = MF._l1 + 3 sage: qexp3 = el3.q_expansion(prec) sage: qexp3 q^-1 - 1/(4*d) + ((1024*d^2 - 33)/(1024*d^2))*q + O(q^2) sage: MF.construct_form(qexp3, order_1=-2) == el3 True sage: MF.construct_form(el3.q_expansion(prec + 1), order_1=-3) == el3 True
sage: WF = WeakModularForms(n=14) sage: qexp = WF.J_inv().q_expansion_fixed_d(d_num_prec=1000) sage: qexp.parent() Laurent Series Ring in q over Real Field with 1000 bits of precision sage: WF.construct_form(qexp, rationalize=True) == WF.J_inv() doctest:...: UserWarning: Using an experimental rationalization of coefficients, please check the result for correctness! True """
raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!") else: raise ValueError("The Laurent coefficients are not in the proper form yet. Try rationalize_series(laurent_series) beforehand (experimental).")
raise ValueError("Insufficient precision: {} < {} = order_inf!".format(laurent_series.prec(), order_inf + 1))
return self(0)
coefficients[j] * self.F_basis_pol(exponents[j], order_1=order_1)\ for j in range(ZZ(len(coefficients))) ])
raise ValueError("The Laurent series {} does not correspond to a form of {}".format(laurent_series, self.reduce_type(["weak"])))
r""" Return a base change matrix which transforms coordinate vectors with respect to a certain basis into a vector corresponding to Laurent coefficients of a series.
This is a helper function used to construct weakly holomorphic quasi forms based on their initial Laurent coefficients (see :meth:`construct_quasi_form`).
INPUT:
- ``min_exp`` -- An integer (default: 0), namely the lower bound for the order at infinity resp. the exponent of the Laurent series.
- ``order_1`` -- A lower bound for the order at ``-1`` of all quasi parts of the subspace (default: 0). If ``n!=infinity`` this parameter is ignored.
- ``incr_prec_by`` -- An integer (default: 0) which specifies how much the precision should be increased compared to the size of the corresponding basis.
OUTPUT:
The corresponding base change matrix.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1) sage: A = QF._quasi_form_matrix(min_exp=-1) sage: A[3] (-1215/(65536*d^3), -2171/(131072*d^2), 134099/(16777216*d^3), -811/(131072*d^2), 15889/(8388608*d^3), -8851/(8388608*d^3))
sage: MF = ModularForms(k=36) sage: MF._quasi_form_matrix(min_exp=2) [1 0] [0 1]
sage: QuasiModularForms(k=2)._quasi_form_matrix() [1]
sage: QF = QuasiWeakModularForms(n=infinity, k=-2, ep=-1) sage: A = QF._quasi_form_matrix(min_exp=-1, order_1=0) sage: A [ 1 1] [-1/(4*d) 0] """
# We have to add + 1 to get a correct upper bound in all cases # since corresponding weak space might have a higher l1 (+1) than # ``self``, even if the weight is smaller
# a non-trivial incr_prec_by will be added in case the resulting matrix does not have full rank
# So far this case never happened but potentially A could be singular! # In this case we want to increase the row size until A has maximal # rank (i.e. column size).
# This is done up increasing the precision of everything by about 20% # of the column size until A has maximal rank: if (incr_prec_by == 0): from sage.misc.misc import verbose verbose("Encountered a base change matrix with not-yet-maximal rank (rare, please report)!") incr_prec_by += column_size//ZZ(5) + 1 return self._quasi_form_matrix(min_exp=min_exp, order_1=order_1, incr_prec_by=incr_prec_by)
# At this point the matrix has maximal rank but might be too big. # Since we are interested in the (exact) required size resp. precision # we have to decrease the (row) size as much as possible while keeping # maximal rank. We cannot simply choose pivots/etc since we want to # keep a simple correspondence to Fourier coefficients!
# We start by using an initial binary search to delete some unnecessary rows: while (A.rank() == column_size): row_size = A.dimensions()[0]
# to avoid infinite loops if (row_size == column_size): return A
B = A A = A.delete_rows([r for r in range(column_size + (row_size-column_size)//2 - 1, row_size)])
# Next we simply delete row by row. Note that A is still modified here... while (B.rank() == column_size): A = B row_size = B.dimensions()[0] B = B.delete_rows([row_size-1])
return A
r""" Return an upper bound for the required precision for Laurent series to uniquely determine a corresponding (quasi) form in ``self`` with the given lower bound ``min_exp`` for the order at infinity (for each quasi part).
.. NOTE::
For ``n=infinity`` only the holomorphic case (``min_exp >= 0``) is supported (in particular a non-negative order at ``-1`` is assumed).
INPUT:
- ``min_exp`` -- An integer (default: 0), namely the lower bound for the order at infinity resp. the exponent of the Laurent series.
- ``order_1`` -- A lower bound for the order at ``-1`` for all quasi parts (default: 0). If ``n!=infinity`` this parameter is ignored.
OUTPUT:
An integer, namely an upper bound for the number of required Laurent coefficients. The bound should be precise or at least pretty sharp.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1) sage: QF.required_laurent_prec(min_exp=-1) 5
sage: MF = ModularForms(k=36) sage: MF.required_laurent_prec(min_exp=2) 4
sage: QuasiModularForms(k=2).required_laurent_prec() 1
sage: QuasiWeakModularForms(n=infinity, k=2, ep=-1).required_laurent_prec(order_1=-1) 6 """
r""" Try to construct an element of self with the given Fourier expansion. The assumption is made that the specified Fourier expansion corresponds to a weakly holomorphic quasi modular form.
If the precision is too low to determine the element an exception is raised.
INPUT:
- ``laurent_series`` -- A Laurent or Power series.
- ``order_1`` -- A lower bound for the order at ``-1`` for all quasi parts of the form (default: 0). If ``n!=infinity`` this parameter is ignored.
- ``check`` -- If ``True`` (default) then the series expansion of the constructed form is compared against the given (rationalized) series.
- ``rationalize`` -- If ``True`` (default: ``False``) then the series is `rationalized` beforehand. Note that in non-exact or non-arithmetic cases this is experimental and extremely unreliable!
OUTPUT:
If possible: An element of self with the same initial Fourier expansion as ``laurent_series``.
Note: For non modular spaces it is also possible to call ``self(laurent_series)`` instead. Also note that this function works much faster if a corresponding (cached) ``q_basis`` is available.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms, QuasiCuspForms sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1) sage: el = QF.quasi_part_gens(min_exp=-1)[4] sage: prec = QF.required_laurent_prec(min_exp=-1) sage: prec 5 sage: qexp = el.q_expansion(prec=prec) sage: qexp q^-1 - 19/(64*d) - 7497/(262144*d^2)*q + 15889/(8388608*d^3)*q^2 + 543834047/(1649267441664*d^4)*q^3 + 711869853/(43980465111040*d^5)*q^4 + O(q^5) sage: qexp.parent() Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: constructed_el = QF.construct_quasi_form(qexp) sage: constructed_el.parent() QuasiWeakModularForms(n=8, k=10/3, ep=-1) over Integer Ring sage: el == constructed_el True
If a q_basis is available the construction uses a different algorithm which we also check::
sage: basis = QF.q_basis(min_exp=-1) sage: QF(qexp) == constructed_el True
sage: MF = ModularForms(k=36) sage: el2 = MF.quasi_part_gens(min_exp=2)[1] sage: prec = MF.required_laurent_prec(min_exp=2) sage: prec 4 sage: qexp2 = el2.q_expansion(prec=prec + 1) sage: qexp2 q^3 - 1/(24*d)*q^4 + O(q^5) sage: qexp2.parent() Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: constructed_el2 = MF.construct_quasi_form(qexp2) sage: constructed_el2.parent() ModularForms(n=3, k=36, ep=1) over Integer Ring sage: el2 == constructed_el2 True
sage: QF = QuasiModularForms(k=2) sage: q = QF.get_q() sage: qexp3 = 1 + O(q) sage: QF(qexp3) 1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 + O(q^5) sage: QF(qexp3) == QF.E2() True
sage: QF = QuasiWeakModularForms(n=infinity, k=2, ep=-1) sage: el4 = QF.f_i() + QF.f_i()^3/QF.E4() sage: prec = QF.required_laurent_prec(order_1=-1) sage: qexp4 = el4.q_expansion(prec=prec) sage: qexp4 2 - 7/(4*d)*q + 195/(256*d^2)*q^2 - 903/(4096*d^3)*q^3 + 41987/(1048576*d^4)*q^4 - 181269/(33554432*d^5)*q^5 + O(q^6) sage: QF.construct_quasi_form(qexp4, check=False) == el4 False sage: QF.construct_quasi_form(qexp4, order_1=-1) == el4 True
sage: QF = QuasiCuspForms(n=8, k=22/3, ep=-1) sage: el = QF(QF.f_inf()*QF.E2()) sage: qexp = el.q_expansion_fixed_d(d_num_prec=1000) sage: qexp.parent() Power Series Ring in q over Real Field with 1000 bits of precision sage: QF.construct_quasi_form(qexp, rationalize=True) == el True """
raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!") else: raise ValueError("The Laurent coefficients are not in the proper form yet. Try rationalize_series(laurent_series) beforehand (experimental).")
raise ValueError("Due to the behavior at infinity the given Laurent series cannot possibly be an element of {}".format(self))
# if a q_basis is available we can construct the form much faster
raise ValueError("Insufficient precision: {} < {}!".format(laurent_series.prec(), min_exp + size))
else:
raise ValueError("Insufficient precision: {} < {}!".format(laurent_series.prec(), min_exp + row_size))
except ValueError: raise ValueError("The Laurent series {} does not correspond to a (quasi) form of {}".format(laurent_series, self.reduce_type(["quasi", "weak"])))
# We have to add + 1 to get a correct upper bound in all cases # since corresponding weak space might have a higher l1 (+1) than # ``self``, even if the weight is smaller
raise ValueError("The Laurent series {} does not correspond to a form of {}".format(laurent_series, self.reduce_type(["quasi", "weak"])))
r""" Try to return a (basis) element of ``self`` with a Laurent series of the form ``q^m + O(q^N)``, where ``N=self.required_laurent_prec(min_exp)``.
If ``m==None`` the whole basis (with varying ``m``'s) is returned if it exists.
INPUT:
- ``m`` -- An integer, indicating the desired initial Laurent exponent of the element. If ``m==None`` (default) then the whole basis is returned.
- ``min_exp`` -- An integer, indicating the minimal Laurent exponent (for each quasi part) of the subspace of ``self`` which should be considered (default: 0).
- ``order_1`` -- A lower bound for the order at ``-1`` of all quasi parts of the subspace (default: 0). If ``n!=infinity`` this parameter is ignored.
OUTPUT:
The corresponding basis (if ``m==None``) resp. the corresponding basis vector (if ``m!=None``). If the basis resp. element doesn't exist an exception is raised.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiWeakModularForms, ModularForms, QuasiModularForms sage: QF = QuasiWeakModularForms(n=8, k=10/3, ep=-1) sage: QF.default_prec(QF.required_laurent_prec(min_exp=-1)) sage: q_basis = QF.q_basis(min_exp=-1) sage: q_basis [q^-1 + O(q^5), 1 + O(q^5), q + O(q^5), q^2 + O(q^5), q^3 + O(q^5), q^4 + O(q^5)] sage: QF.q_basis(m=-1, min_exp=-1) q^-1 + O(q^5)
sage: MF = ModularForms(k=36) sage: MF.q_basis() == MF.gens() True
sage: QF = QuasiModularForms(k=6) sage: QF.required_laurent_prec() 3 sage: QF.q_basis() [1 - 20160*q^3 - 158760*q^4 + O(q^5), q - 60*q^3 - 248*q^4 + O(q^5), q^2 + 8*q^3 + 30*q^4 + O(q^5)]
sage: QF = QuasiWeakModularForms(n=infinity, k=-2, ep=-1) sage: QF.q_basis(order_1=-1) [1 - 168*q^2 + 2304*q^3 - 19320*q^4 + O(q^5), q - 18*q^2 + 180*q^3 - 1316*q^4 + O(q^5)] """
from warnings import warn warn("This function only determines elements / a basis of (quasi) weakly modular forms!")
# If A is square it should automatically be invertible (by the previous procedures)
else: raise ValueError("Unfortunately a q_basis doesn't exist in this case (this is rare/interesting, please report)") else: raise ValueError("Index out of range: m={} < {}=min_exp".format(m, min_exp))
# If the whole basis is available, then use it
raise ValueError("Index out of range: m={} >= {}=dimension + min_exp".format(m, column_len + min_exp))
else: raise ValueError("Index out of range: m={} >= {}=required_precision + min_exp".format(m, row_len + min_exp))
except ValueError: raise ValueError("Unfortunately the q_basis vector (m={}, min_exp={}) doesn't exist in this case (this is rare/interesting, please report)".format(m, min_exp))
r""" Try to return a Laurent series with coefficients in ``self.coeff_ring()`` that matches the given Laurent series.
We give our best but there is absolutely no guarantee that it will work!
INPUT:
- ``laurent_series`` -- A Laurent series. If the Laurent coefficients already coerce into ``self.coeff_ring()`` with a formal parameter then the Laurent series is returned as is.
Otherwise it is assumed that the series is normalized in the sense that the first non-trivial coefficient is a power of ``d`` (e.g. ``1``).
- ``coeff_bound`` -- Either ``None`` resp. ``0`` or a positive real number (default: ``1e-10``). If specified ``coeff_bound`` gives a lower bound for the size of the initial Laurent coefficients. If a coefficient is smaller it is assumed to be zero.
For calculations with very small coefficients (less than ``1e-10``) ``coeff_bound`` should be set to something even smaller or just ``0``.
Non-exact calculations often produce non-zero coefficients which are supposed to be zero. In those cases this parameter helps a lot.
- ``denom_factor`` -- An integer (default: 1) whose factor might occur in the denominator of the given Laurent coefficients (in addition to naturally occuring factors).
OUTPUT:
A Laurent series over ``self.coeff_ring()`` corresponding to the given Laurent series.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import WeakModularForms, ModularForms, QuasiCuspForms sage: WF = WeakModularForms(n=14) sage: qexp = WF.J_inv().q_expansion_fixed_d(d_num_prec=1000) sage: qexp.parent() Laurent Series Ring in q over Real Field with 1000 bits of precision sage: qexp_int = WF.rationalize_series(qexp) sage: qexp_int.add_bigoh(3) d*q^-1 + 37/98 + 2587/(38416*d)*q + 899/(117649*d^2)*q^2 + O(q^3) sage: qexp_int == WF.J_inv().q_expansion() True sage: WF.rationalize_series(qexp_int) == qexp_int True sage: WF(qexp_int) == WF.J_inv() True
sage: WF.rationalize_series(qexp.parent()(1)) 1 sage: WF.rationalize_series(qexp_int.parent()(1)).parent() Laurent Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring
sage: MF = ModularForms(n=infinity, k=4) sage: qexp = MF.E4().q_expansion_fixed_d() sage: qexp.parent() Power Series Ring in q over Rational Field sage: qexp_int = MF.rationalize_series(qexp) sage: qexp_int.parent() Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: qexp_int == MF.E4().q_expansion() True sage: MF.rationalize_series(qexp_int) == qexp_int True sage: MF(qexp_int) == MF.E4() True
sage: QF = QuasiCuspForms(n=8, k=22/3, ep=-1) sage: el = QF(QF.f_inf()*QF.E2()) sage: qexp = el.q_expansion_fixed_d(d_num_prec=1000) sage: qexp.parent() Power Series Ring in q over Real Field with 1000 bits of precision sage: qexp_int = QF.rationalize_series(qexp) sage: qexp_int.parent() Power Series Ring in q over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: qexp_int == el.q_expansion() True sage: QF.rationalize_series(qexp_int) == qexp_int True sage: QF(qexp_int) == el True """
# If the coefficients already coerce to our coefficient ring # and are in polynomial form we simply return the Laurent series else: raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!") # Else the case that the Laurent series is exact but the group is non-arithmetic # shouldn't occur (except for trivial cases) prec = self.default_num_prec() dvalue = self.group().dvalue().n(prec) # For arithmetic groups the coefficients are exact though (so is d) else:
# This messes up doctests! :-(
return -self.rationalize_series(-laurent_series, coeff_bound=coeff_bound) else: else:
raise ValueError("The Laurent series is not normalized correctly!")
# TODO: This is not a good enough estimate, see e.g. E12 # (however for exact base rings + arithmetic groups we don't need it)
return ZZ(1/dvalue)**m
# TODO: figure out a correct bound for the required precision warn("The precision from coefficient m={} on is too low!".format(m))
else:
# DEFAULT METHODS (should be overwritten in concrete classes)
r""" Return an element of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms sage: el = QuasiMeromorphicModularForms(k=2, ep=-1).an_element() sage: el.parent() QuasiMeromorphicModularForms(n=3, k=2, ep=-1) over Integer Ring sage: el.is_zero() True sage: el O(q^5) """
# this seems ok, so might as well leave it as is for everything #return self.F_simple()
def dimension(self): r""" Return the dimension of ``self``.
.. NOTE::
This method should be overloaded by subclasses.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import QuasiMeromorphicModularForms sage: QuasiMeromorphicModularForms(k=2, ep=-1).dimension() +Infinity """
r""" Return the rank of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=4, k=24, ep=-1) sage: MF.rank() 3 sage: MF.subspace([MF.gen(0), MF.gen(2)]).rank() 2 """
r""" Return the degree of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=4, k=24, ep=-1) sage: MF.degree() 3 sage: MF.subspace([MF.gen(0), MF.gen(2)]).degree() # defined in subspace.py 3 """
r""" This method should be overloaded by subclasses.
Return the coordinate vector of the element ``v`` with respect to ``self.gens()``.
NOTE:
Elements use this method (from their parent) to calculate their coordinates.
INPUT:
- ``v`` -- An element of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=4, k=24, ep=-1) sage: MF.coordinate_vector(MF.gen(0)).parent() # defined in space.py Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: MF.coordinate_vector(MF.gen(0)) # defined in space.py (1, 0, 0) sage: subspace = MF.subspace([MF.gen(0), MF.gen(2)]) sage: subspace.coordinate_vector(subspace.gen(0)).parent() # defined in subspace.py Vector space of dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: subspace.coordinate_vector(subspace.gen(0)) # defined in subspace.py (1, 0) """
def ambient_coordinate_vector(self, v): r""" Return the coordinate vector of the element ``v`` in ``self.module()`` with respect to the basis from ``self.ambient_space``.
NOTE:
Elements use this method (from their parent) to calculate their coordinates.
INPUT:
- ``v`` -- An element of ``self``.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: MF = ModularForms(n=4, k=24, ep=-1) sage: MF.ambient_coordinate_vector(MF.gen(0)).parent() Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring sage: MF.ambient_coordinate_vector(MF.gen(0)) (1, 0, 0) sage: subspace = MF.subspace([MF.gen(0), MF.gen(2)]) sage: subspace.ambient_coordinate_vector(subspace.gen(0)).parent() Vector space of degree 3 and dimension 2 over Fraction Field of Univariate Polynomial Ring in d over Integer Ring Basis matrix: [1 0 0] [0 0 1] sage: subspace.ambient_coordinate_vector(subspace.gen(0)) (1, 0, 0) """
r""" This method should be overloaded by subclasses.
Return a basis of ``self``.
Note that the coordinate vector of elements of ``self`` are with respect to this basis.
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: ModularForms(k=12).gens() # defined in space.py [1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + O(q^5), q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)] """
raise NotImplementedError("No generators are implemented yet for {}!".format(self))
r""" Return the ``k``'th basis element of ``self`` if possible (default: ``k=0``).
EXAMPLES::
sage: from sage.modular.modform_hecketriangle.space import ModularForms sage: ModularForms(k=12).gen(1).parent() ModularForms(n=3, k=12, ep=1) over Integer Ring sage: ModularForms(k=12).gen(1) q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5) """
else: raise ValueError("Invalid index: k={} does not satisfy 0 <= k <= {}!".format(k, self.dimension())) |