def parameter(self, prec=20): r""" Return the Tate parameter `q` such that the curve is isomorphic over the algebraic closure of `\QQ_p` to the curve `\QQ_p^{\times}/q^{\ZZ}`. INPUT: - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parameter(prec=5) 3*5^3 + 3*5^4 + 2*5^5 + 2*5^6 + 3*5^7 + O(5^8) """ try: qE = self._q if qE.absolute_precision() >= prec: return qE except AttributeError: pass E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] j = (E4.q_expansion(prec + 3))**3 / Delta.q_expansion(prec + 3) jinv = (1 / j).power_series() q_in_terms_of_jinv = jinv.reverse() R = Qp(self._p, prec=prec) qE = q_in_terms_of_jinv(R(1 / self._E.j_invariant())) self._q = qE return qE
def parameter(self, prec=20): r""" Return the Tate parameter `q` such that the curve is isomorphic over the algebraic closure of `\QQ_p` to the curve `\QQ_p^{\times}/q^{\ZZ}`. INPUT: - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parameter(prec=5) 3*5^3 + 3*5^4 + 2*5^5 + 2*5^6 + 3*5^7 + O(5^8) """ try: qE = self._q if qE.absolute_precision() >= prec: return qE except AttributeError: pass E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] j = (E4.q_expansion(prec + 3)) ** 3 / Delta.q_expansion(prec + 3) jinv = (1 / j).power_series() q_in_terms_of_jinv = jinv.reverse() R = Qp(self._p, prec=prec) qE = q_in_terms_of_jinv(R(1 / self._E.j_invariant())) self._q = qE return qE
def tate_parameter(E, p, prec = 20, R = None): if R is None: R = Qp(p,prec) jE = E.j_invariant() E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] j = (E4.q_expansion(prec+3))**3/Delta.q_expansion(prec+3) jinv = (1/j).power_series() q_in_terms_of_jinv = jinv.reversion() return q_in_terms_of_jinv(R(1/E.j_invariant()))
def getcoords(E, u, prec=20, R=None): if R is None: R = u.parent() u = R(u) p = R.prime() jE = E.j_invariant() # Calculate the Tate parameter E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] j = (E4.q_expansion(prec + 7)) ** 3 / Delta.q_expansion(prec + 7) qE = (1 / j).power_series().reversion()(R(1 / jE)) # Normalize the period by appropriate powers of qE un = u * qE ** (-(u.valuation() / qE.valuation()).floor()) precn = (prec / qE.valuation()).floor() + 4 # formulas in Silverman II (Advanced Topics in the Arithmetic of Elliptic curves, p. 425) xx = un / (1 - un) ** 2 + sum( [ qE ** n * un / (1 - qE ** n * un) ** 2 + qE ** n / un / (1 - qE ** n / un) ** 2 - 2 * qE ** n / (1 - qE ** n) ** 2 for n in range(1, precn) ] ) yy = un ** 2 / (1 - un) ** 3 + sum( [ qE ** (2 * n) * un ** 2 / (1 - qE ** n * un) ** 3 - qE ** n / un / (1 - qE ** n / un) ** 3 + qE ** n / (1 - qE ** n) ** 2 for n in range(1, precn) ] ) sk = lambda q, k, pprec: sum([n ** k * q ** n / (1 - q ** n) for n in range(1, pprec + 1)]) n = qE.valuation() precp = ((prec + 4) / n).floor() + 2 tate_a4 = -5 * sk(qE, 3, precp) tate_a6 = (tate_a4 - 7 * sk(qE, 5, precp)) / 12 Eq = EllipticCurve([R(1), R(0), R(0), tate_a4, tate_a6]) C2 = (Eq.c4() * E.c6()) / (Eq.c6() * E.c4()) C = R(C2).square_root() s = (C - R(E.a1())) / R(2) r = (s * (C - s) - R(E.a2())) / 3 t = (r * (2 * s - C) - R(E.a3())) / 2 return (r + C2 * xx, t + s * C2 * xx + C * C2 * yy)
def getcoords(E, u, prec=20, R=None): if R is None: R = u.parent() u = R(u) p = R.prime() jE = E.j_invariant() # Calculate the Tate parameter E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] j = (E4.q_expansion(prec + 7))**3 / Delta.q_expansion(prec + 7) qE = (1 / j).power_series().reversion()(R(1 / jE)) # Normalize the period by appropriate powers of qE un = u * qE**(-(u.valuation() / qE.valuation()).floor()) precn = (prec / qE.valuation()).floor() + 4 # formulas in Silverman II (Advanced Topics in the Arithmetic of Elliptic curves, p. 425) xx = un / (1 - un)**2 + sum([ qE**n * un / (1 - qE**n * un)**2 + qE**n / un / (1 - qE**n / un)**2 - 2 * qE**n / (1 - qE**n)**2 for n in range(1, precn) ]) yy = un**2 / (1 - un)**3 + sum([ qE**(2 * n) * un**2 / (1 - qE**n * un)**3 - qE**n / un / (1 - qE**n / un)**3 + qE**n / (1 - qE**n)**2 for n in range(1, precn) ]) sk = lambda q, k, pprec: sum( [n**k * q**n / (1 - q**n) for n in range(1, pprec + 1)]) n = qE.valuation() precp = ((prec + 4) / n).floor() + 2 tate_a4 = -5 * sk(qE, 3, precp) tate_a6 = (tate_a4 - 7 * sk(qE, 5, precp)) / 12 Eq = EllipticCurve([R(1), R(0), R(0), tate_a4, tate_a6]) C2 = (Eq.c4() * E.c6()) / (Eq.c6() * E.c4()) C = R(C2).square_root() s = (C - R(E.a1())) / R(2) r = (s * (C - s) - R(E.a2())) / 3 t = (r * (2 * s - C) - R(E.a3())) / 2 return (r + C2 * xx, t + s * C2 * xx + C * C2 * yy)
def modular_ratio_space(chi): r""" Compute the space of 'modular ratios', i.e. meromorphic modular forms f level N and character chi such that f * E is a holomorphic cusp form for every Eisenstein series E of weight 1 and character 1/chi. Elements are returned as q-expansions up to precision R, where R is one greater than the weight 3 Sturm bound. EXAMPLES:: sage: chi = DirichletGroup(31,QQ).0 sage: sage.modular.modform.weight1.modular_ratio_space(chi) [q - 8/3*q^3 + 13/9*q^4 + 43/27*q^5 - 620/81*q^6 + 1615/243*q^7 + 3481/729*q^8 + O(q^9), q^2 - 8/3*q^3 + 13/9*q^4 + 70/27*q^5 - 620/81*q^6 + 1858/243*q^7 + 2752/729*q^8 + O(q^9)] """ from sage.modular.modform.constructor import EisensteinForms, CuspForms if chi(-1) == 1: return [] N = chi.modulus() chi = chi.minimize_base_ring() K = chi.base_ring() R = Gamma0(N).sturm_bound(3) + 1 verbose("Working precision is %s" % R, level=1) verbose("Coeff field is %s" % K, level=1) V = K**R I = V d = I.rank() t = verbose("Calculating Eisenstein forms in weight 1...", level=1) B0 = EisensteinForms(~chi, 1).q_echelon_basis(prec=R) B = [b + B0[0] for b in B0] verbose("Done (dimension %s)" % len(B), level=1, t=t) t = verbose("Calculating in weight 2...", level=1) C = CuspForms(Gamma0(N), 2).q_echelon_basis(prec=R) verbose("Done (dimension %s)" % len(C), t=t, level=1) t = verbose("Computing candidate space", level=1) for b in B: quots = (c / b for c in C) W = V.span(V(x.padded_list(R)) for x in quots) I = I.intersection(W) if I.rank() < d: verbose(" Cut down to dimension %s" % I.rank(), level=1) d = I.rank() if I.rank() == 0: break verbose("Done: intersection is %s-dimensional" % I.dimension(), t=t, level=1) A = PowerSeriesRing(K, 'q') return [A(x.list()).add_bigoh(R) for x in I.gens()]
def modular_ratio_to_prec(chi, qexp, prec): r""" Given a q-expansion of a modular ratio up to sufficient precision to determine it uniquely, compute it to greater precision. EXAMPLES:: sage: from sage.modular.modform.weight1 import modular_ratio_to_prec sage: R.<q> = QQ[[]] sage: modular_ratio_to_prec(DirichletGroup(31,QQ).0, q-q^2-q^5-q^7+q^8+O(q^9), 20) q - q^2 - q^5 - q^7 + q^8 + q^9 + q^10 + q^14 - q^16 - q^18 - q^19 + O(q^20) """ if prec <= qexp.prec(): return qexp.add_bigoh(prec) from sage.modular.modform.constructor import EisensteinForms, CuspForms B = EisensteinForms(~chi, 1).gen(0).qexp(prec) fB = qexp * B fB_elt = CuspForms(chi.level(), 2, base_ring=qexp.base_ring())(fB) return fB_elt.qexp(prec) / B
def hecke_stable_subspace(chi, aux_prime=ZZ(2)): r""" Compute a q-expansion basis for S_1(chi). Results are returned as q-expansions to a certain fixed (and fairly high) precision. If more precision is required this can be obtained with :func:`modular_ratio_to_prec`. EXAMPLES:: sage: from sage.modular.modform.weight1 import hecke_stable_subspace sage: hecke_stable_subspace(DirichletGroup(59, QQ).0) [q - q^3 + q^4 - q^5 - q^7 - q^12 + q^15 + q^16 + 2*q^17 - q^19 - q^20 + q^21 + q^27 - q^28 - q^29 + q^35 + O(q^40)] """ # Deal quickly with the easy cases. if chi(-1) == 1: return [] N = chi.modulus() H = chi.kernel() G = GammaH(N, H) try: if ArithmeticSubgroup.dimension_cusp_forms(G, 1) == 0: verbose("no wt 1 cusp forms for N=%s, chi=%s by Riemann-Roch" % (N, chi._repr_short_()), level=1) return [] except NotImplementedError: pass from sage.modular.modform.constructor import EisensteinForms chi = chi.minimize_base_ring() K = chi.base_ring() # Auxiliary prime for Hecke stability method l = aux_prime while l.divides(N): l = l.next_prime() verbose("Auxiliary prime: %s" % l, level=1) # Compute working precision R = l * Gamma0(N).sturm_bound(l + 2) t = verbose("Computing modular ratio space", level=1) mrs = modular_ratio_space(chi) t = verbose("Computing modular ratios to precision %s" % R, level=1) qexps = [modular_ratio_to_prec(chi, f, R) for f in mrs] verbose("Done", t=t, level=1) # We want to compute the largest subspace of I stable under T_l. To do # this, we compute I intersect T_l(I) modulo q^(R/l), and take its preimage # under T_l, which is then well-defined modulo q^R. from sage.modular.modform.hecke_operator_on_qexp import hecke_operator_on_qexp t = verbose("Computing Hecke-stable subspace", level=1) A = PowerSeriesRing(K, 'q') r = R // l V = K**R W = K**r Tl_images = [hecke_operator_on_qexp(f, l, 1, chi) for f in qexps] qvecs = [V(x.padded_list(R)) for x in qexps] qvecs_trunc = [W(x.padded_list(r)) for x in qexps] Tvecs = [W(x.padded_list(r)) for x in Tl_images] I = V.submodule(qvecs) Iimage = W.span(qvecs_trunc) TlI = W.span(Tvecs) Jimage = Iimage.intersection(TlI) J = I.Hom(W)(Tvecs).inverse_image(Jimage) verbose("Hecke-stable subspace is %s-dimensional" % J.dimension(), t=t, level=1) if J.rank() == 0: return [] # The theory does not guarantee that J is exactly S_1(chi), just that it is # intermediate between S_1(chi) and M_1(chi). In every example I know of, # it is equal to S_1(chi), but just for honesty, we check this anyway. t = verbose("Checking cuspidality", level=1) JEis = V.span( V(x.padded_list(R)) for x in EisensteinForms(chi, 1).q_echelon_basis(prec=R)) D = JEis.intersection(J) if D.dimension() != 0: raise ArithmeticError("Got non-cuspidal form!") verbose("Done", t=t, level=1) qexps = Sequence(A(x.list()).add_bigoh(R) for x in J.gens()) return qexps