def _isomorphism(self, prec=20): r""" Return the isomorphism between ``self.curve()`` and the given curve in the form of a list ``[u,r,s,t]`` of `p`-adic numbers. For this to exist the given curve has to have split multiplicative reduction over `\QQ_p`. More precisely, if `E` has coordinates `x` and `y` and the Tate curve has coordinates `X`, `Y` with `Y^2 + XY = X^3 + s_4 X +s_6` then `X = u^2 x +r` and `Y = u^3 y +s u^2 x +t`. INPUT: - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq._isomorphism(prec=5) [2 + 3*5^2 + 2*5^3 + 4*5^4 + O(5^5), 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^5), 3 + 2*5 + 5^2 + 5^3 + 2*5^4 + O(5^5), 2 + 5 + 3*5^2 + 5^3 + 5^4 + O(5^5)] """ if not self.is_split(): raise RuntimeError("The curve must have split multiplicative " "reduction") C = self._Csquare(prec=prec + 4).sqrt() R = Qp(self._p, prec) C = R(C) s = (C * R(self._E.a1()) - R.one()) / R(2) r = (C ** 2 * R(self._E.a2()) + s + s ** 2) / R(3) t = (C ** 3 * R(self._E.a3()) - r) / R(2) return [C, r, s, t]
def _isomorphism(self, prec=20): r""" Return the isomorphism between ``self.curve()`` and the given curve in the form of a list ``[u,r,s,t]`` of `p`-adic numbers. For this to exist the given curve has to have split multiplicative reduction over `\QQ_p`. More precisely, if `E` has coordinates `x` and `y` and the Tate curve has coordinates `X`, `Y` with `Y^2 + XY = X^3 + s_4 X +s_6` then `X = u^2 x +r` and `Y = u^3 y +s u^2 x +t`. INPUT: - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq._isomorphism(prec=5) [2 + 3*5^2 + 2*5^3 + 4*5^4 + O(5^5), 4 + 3*5 + 4*5^2 + 2*5^3 + O(5^5), 3 + 2*5 + 5^2 + 5^3 + 2*5^4 + O(5^5), 2 + 5 + 3*5^2 + 5^3 + 5^4 + O(5^5)] """ if not self.is_split(): raise RuntimeError("The curve must have split multiplicative " "reduction") C = self._Csquare(prec=prec + 4).sqrt() R = Qp(self._p, prec) C = R(C) s = (C * R(self._E.a1()) - R.one()) / R(2) r = (C**2 * R(self._E.a2()) + s + s**2) / R(3) t = (C**3 * R(self._E.a3()) - r) / R(2) return [C, r, s, t]
def lift(self, P, prec=20): r""" Given a point `P` in the formal group of the elliptic curve `E` with split multiplicative reduction, this produces an element `u` in `\QQ_p^{\times}` mapped to the point `P` by the Tate parametrisation. The algorithm return the unique such element in `1+p\ZZ_p`. INPUT: - ``P`` - a point on the elliptic curve. - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: e = EllipticCurve('130a1') sage: eq = e.tate_curve(5) sage: P = e([-6,10]) sage: l = eq.lift(12*P, prec=10); l 1 + 4*5 + 5^3 + 5^4 + 4*5^5 + 5^6 + 5^7 + 4*5^8 + 5^9 + O(5^10) Now we map the lift l back and check that it is indeed right.:: sage: eq.parametrisation_onto_original_curve(l) (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^20)) sage: e5 = e.change_ring(Qp(5,9)) sage: e5(12*P) (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^9)) """ p = self._p R = Qp(self._p, prec) if not self._E == P.curve(): raise ValueError("The point must lie on the original curve.") if not self.is_split(): raise ValueError( "The curve must have split multiplicative reduction.") if P.is_zero(): return R.one() if P[0].valuation(p) >= 0: raise ValueError("The point must lie in the formal group.") Eq = self.curve(prec=prec) C, r, s, t = self._isomorphism(prec=prec) xx = r + C**2 * P[0] yy = t + s * C**2 * P[0] + C**3 * P[1] try: Eq([xx, yy]) except Exception: raise RuntimeError("Bug : Point %s does not lie on the curve " % (xx, yy)) tt = -xx / yy eqhat = Eq.formal() eqlog = eqhat.log(prec + 3) z = eqlog(tt) u = ZZ.one() fac = ZZ.one() for i in range(1, 2 * prec + 1): fac *= i u += z**i / fac return u
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) """ qE = getattr(self, "_q", None) if qE and qE.precision_relative() >= prec: return Qp(self._p, prec=prec)(qE) 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 lift(self, P, prec=20): r""" Given a point `P` in the formal group of the elliptic curve `E` with split multiplicative reduction, this produces an element `u` in `\QQ_p^{\times}` mapped to the point `P` by the Tate parametrisation. The algorithm return the unique such element in `1+p\ZZ_p`. INPUT: - ``P`` - a point on the elliptic curve. - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: e = EllipticCurve('130a1') sage: eq = e.tate_curve(5) sage: P = e([-6,10]) sage: l = eq.lift(12*P, prec=10); l 1 + 4*5 + 5^3 + 5^4 + 4*5^5 + 5^6 + 5^7 + 4*5^8 + 5^9 + O(5^10) Now we map the lift l back and check that it is indeed right.:: sage: eq.parametrisation_onto_original_curve(l) (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^20)) sage: e5 = e.change_ring(Qp(5,9)) sage: e5(12*P) (4*5^-2 + 2*5^-1 + 4*5 + 3*5^3 + 5^4 + 2*5^5 + 4*5^6 + O(5^7) : 2*5^-3 + 5^-1 + 4 + 4*5 + 5^2 + 3*5^3 + 4*5^4 + O(5^6) : 1 + O(5^9)) """ p = self._p R = Qp(self._p, prec) if not self._E == P.curve(): raise ValueError("The point must lie on the original curve.") if not self.is_split(): raise ValueError("The curve must have split multiplicative reduction.") if P.is_zero(): return R.one() if P[0].valuation(p) >= 0: raise ValueError("The point must lie in the formal group.") Eq = self.curve(prec=prec) C, r, s, t = self._isomorphism(prec=prec) xx = r + C ** 2 * P[0] yy = t + s * C ** 2 * P[0] + C ** 3 * P[1] try: Eq([xx, yy]) except Exception: raise RuntimeError("Bug : Point %s does not lie on the curve " % (xx, yy)) tt = -xx / yy eqhat = Eq.formal() eqlog = eqhat.log(prec + 3) z = eqlog(tt) u = ZZ.one() fac = ZZ.one() for i in range(1, 2 * prec + 1): fac *= i u += z ** i / fac return u
def completions(self, p, M): r""" If `K` is the base_ring of self, this function takes all maps `K-->Q_p` and applies them to self return a list of (modular symbol,map: `K-->Q_p`) as map varies over all such maps. .. NOTE:: This only returns all completions when `p` splits completely in `K` INPUT: - ``p`` -- prime - ``M`` -- precision OUTPUT: - A list of tuples (modular symbol,map: `K-->Q_p`) as map varies over all such maps EXAMPLES:: sage: from sage.modular.pollack_stevens.space import ps_modsym_from_simple_modsym_space sage: D = ModularSymbols(67,2,1).cuspidal_submodule().new_subspace().decomposition()[1] sage: f = ps_modsym_from_simple_modsym_space(D) sage: f.completions(41,10) [(Modular symbol with values in Sym^0 Q_41^2, Ring morphism: From: Number Field in alpha with defining polynomial x^2 + 3*x + 1 To: 41-adic Field with capped relative precision 10 Defn: alpha |--> 5 + 22*41 + 19*41^2 + 10*41^3 + 28*41^4 + 22*41^5 + 9*41^6 + 25*41^7 + 40*41^8 + 8*41^9 + O(41^10)), (Modular symbol with values in Sym^0 Q_41^2, Ring morphism: From: Number Field in alpha with defining polynomial x^2 + 3*x + 1 To: 41-adic Field with capped relative precision 10 Defn: alpha |--> 33 + 18*41 + 21*41^2 + 30*41^3 + 12*41^4 + 18*41^5 + 31*41^6 + 15*41^7 + 32*41^9 + O(41^10))] """ K = self.base_ring() f = K.defining_polynomial() R = Qp(p,M+10)['x'] x = R.gen() v = R(f).roots() if len(v) == 0: L = Qp(p,M).extension(f,names='a') a = L.gen() V = self.parent().change_ring(L) Dist = V.coefficient_module() psi = K.hom([K.gen()],L) embedded_sym = self.__class__(self._map.apply(psi,codomain=Dist, to_moments=True),V, construct=True) ans = [embedded_sym,psi] return ans #raise ValueError, "No coercion possible -- no prime over p has degree 1" else: roots = [r[0] for r in v] ans = [] V = self.parent().change_ring(Qp(p, M)) Dist = V.coefficient_module() for r in roots: psi = K.hom([r],Qp(p,M)) embedded_sym = self.__class__(self._map.apply(psi, codomain=Dist, to_moments=True), V, construct=True) ans.append((embedded_sym,psi)) return ans
def parametrisation_onto_tate_curve(self, u, prec=None): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the Tate curve under the `p`-adic uniformisation of `E`. INPUT: - ``u`` -- a non-zero `p`-adic number. - ``prec`` -- the `p`-adic precision, default is the relative precision of ``u`` otherwise 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10), prec=10) (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10)) (5^-2 + 4*5^-1 + 1 + 2*5 + 3*5^2 + 2*5^5 + 3*5^6 + O(5^7) : 4*5^-3 + 2*5^-1 + 4 + 2*5 + 3*5^4 + 2*5^5 + O(5^6) : 1 + O(5^10)) sage: eq.parametrisation_onto_tate_curve(1+5+5^2+O(5^10), prec=20) Traceback (most recent call last): ... ValueError: Requested more precision than the precision of u """ if prec is None: prec = getattr(u, "precision_relative", lambda: 20)() u = Qp(self._p, prec)(u) if prec > u.precision_relative(): raise ValueError( "Requested more precision than the precision of u") if u == 1: return self.curve(prec=prec)(0) q = self.parameter(prec=prec) un = u * q**(-(u.valuation() / q.valuation()).floor()) precn = (prec / q.valuation()).floor() + 4 # formulas in Silverman II (Advanced Topics in the Arithmetic # of Elliptic curves, p. 425) xx = un / (1 - un)**2 + sum([ q**n * un / (1 - q**n * un)**2 + q**n / un / (1 - q**n / un)**2 - 2 * q**n / (1 - q**n)**2 for n in range(1, precn) ]) yy = un**2 / (1 - un)**3 + sum([ q**(2 * n) * un**2 / (1 - q**n * un)**3 - q**n / un / (1 - q**n / un)**3 + q**n / (1 - q**n)**2 for n in range(1, precn) ]) return self.curve(prec=prec)([xx, yy])
def padic_regulator(self, prec=20): r""" Compute the canonical `p`-adic regulator on the extended Mordell-Weil group as in [MTT]_ (with the correction of [Wer]_ and sign convention in [SW]_.) The `p`-adic Birch and Swinnerton-Dyer conjecture predicts that this value appears in the formula for the leading term of the `p`-adic L-function. INPUT: - ``prec`` -- the `p`-adic precision, default is 20. REFERENCES: [MTT]_ .. [Wer] Annette Werner, Local heights on abelian varieties and rigid analytic uniformization, Doc. Math. 3 (1998), 301-319. [SW]_ EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.padic_regulator() 2*5^-1 + 1 + 2*5 + 2*5^2 + 3*5^3 + 3*5^6 + 5^7 + 3*5^9 + 3*5^10 + 3*5^12 + 4*5^13 + 3*5^15 + 2*5^16 + 3*5^18 + 4*5^19 + O(5^20) """ prec = prec + 4 K = Qp(self._p, prec=prec) rank = self._E.rank() if rank == 0: return K.one() if not self.is_split(): raise NotImplementedError( "The p-adic regulator is not implemented for non-split multiplicative reduction." ) basis = self._E.gens() M = matrix.matrix(K, rank, rank, 0) height = self.padic_height(prec=prec) point_height = [height(P) for P in basis] for i in range(rank): for j in range(i + 1, rank): M[i, j] = M[j, i] = (-point_height[i] - point_height[j] + height(basis[i] + basis[j])) / 2 for i in range(rank): M[i, i] = point_height[i] return M.determinant()
def get_ulog(ualg, K, p, prec): QQp = Qp(p,prec) K = ualg.parent() try: phi = K.hom([K.gen().minpoly().roots(QQp)[0][0]]) Kp = QQp except IndexError: Kp = QQp.extension(K.gen().minpoly(),names=str(K.gen())+'_p') ap = Kp.gen() phi = K.hom([ap]) return phi(ualg).log(p_branch = 0)
def padic_regulator(self, prec=20): r""" Compute the canonical `p`-adic regulator on the extended Mordell-Weil group as in [MTT]_ (with the correction of [Wer]_ and sign convention in [SW]_.) The `p`-adic Birch and Swinnerton-Dyer conjecture predicts that this value appears in the formula for the leading term of the `p`-adic L-function. INPUT: - ``prec`` -- the `p`-adic precision, default is 20. REFERENCES: [MTT]_ .. [Wer] Annette Werner, Local heights on abelian varieties and rigid analytic uniformization, Doc. Math. 3 (1998), 301-319. [SW]_ EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.padic_regulator() 2*5^-1 + 1 + 2*5 + 2*5^2 + 3*5^3 + 3*5^6 + 5^7 + 3*5^9 + 3*5^10 + 3*5^12 + 4*5^13 + 3*5^15 + 2*5^16 + 3*5^18 + 4*5^19 + O(5^20) """ prec = prec + 4 K = Qp(self._p, prec=prec) rank = self._E.rank() if rank == 0: return K.one() if not self.is_split(): raise NotImplementedError("The p-adic regulator is not implemented for non-split multiplicative reduction.") basis = self._E.gens() M = matrix.matrix(K, rank, rank, 0) height = self.padic_height(prec=prec) point_height = [height(P) for P in basis] for i in range(rank): for j in range(i + 1, rank): M[i, j] = M[j, i] = (- point_height[i] - point_height[j] + height(basis[i] + basis[j])) / 2 for i in range(rank): M[i, i] = point_height[i] return M.determinant()
def logp_fcn(p, p_prec, a): r""" INPUT: - ``p``: prime - ``p_prec: desired ``p``-adic precision - ``z`` OUTPUT: - The ``p``-adic logarithm of this is the *function* on Z_p^* which sends z to log_p(z) using a power series truncated at p_prec terms""" R = Qp(p, 2 * p_prec) a = a / R.teichmuller(a) return sum([((-1) ** (m - 1)) * ((a - 1) ** m) / m for m in range(1, p_prec)])
def completion(self, p, prec, extras={}): if p == infinity.Infinity: from sage.rings.real_mpfr import create_RealField return create_RealField(prec, **extras) else: from sage.rings.padics.factory import Qp return Qp(p, prec, **extras)
def fraction_field(self, print_mode=None): r""" Returns the fraction field of ``self``. INPUT: - ``print_mode`` - a dictionary containing print options. Defaults to the same options as this ring. OUTPUT: - the fraction field of ``self``. EXAMPLES:: sage: R = Zp(5, print_mode='digits') sage: K = R.fraction_field(); repr(K(1/3))[3:] '31313131313131313132' sage: L = R.fraction_field({'max_ram_terms':4}); repr(L(1/3))[3:] '3132' """ if self.is_field() and print_mode is None: return self from sage.rings.padics.factory import Qp if self.is_floating_point(): mode = 'floating-point' else: mode = 'capped-rel' return Qp(self.prime(), self.precision_cap(), mode, print_mode=self._modified_print_mode(print_mode), names=self._uniformizer_print())
def E2(self, prec=20): r""" Return the value of the `p`-adic Eisenstein series of weight 2 evaluated on the elliptic curve having split multiplicative reduction. INPUT: - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.E2(prec=10) 4 + 2*5^2 + 2*5^3 + 5^4 + 2*5^5 + 5^7 + 5^8 + 2*5^9 + O(5^10) sage: T = EllipticCurve('14').tate_curve(7) sage: T.E2(30) 2 + 4*7 + 7^2 + 3*7^3 + 6*7^4 + 5*7^5 + 2*7^6 + 7^7 + 5*7^8 + 6*7^9 + 5*7^10 + 2*7^11 + 6*7^12 + 4*7^13 + 3*7^15 + 5*7^16 + 4*7^17 + 4*7^18 + 2*7^20 + 7^21 + 5*7^22 + 4*7^23 + 4*7^24 + 3*7^25 + 6*7^26 + 3*7^27 + 6*7^28 + O(7^30) """ p = self._p Csq = self._Csquare(prec=prec) qE = self._q n = qE.valuation() R = Qp(p, prec) e2 = Csq * (1 - 24 * sum( [qE**i / (1 - qE**i)**2 for i in range(1, (prec / n).floor() + 5)])) return R(e2)
def __init__(self, base, ideal=None): """ The Python constructor. EXAMPLES:: sage: Berkovich_Cp_Affine(3) Affine Berkovich line over Cp(3) of precision 20 """ if base in ZZ: if base.is_prime(): base = Qp(base) # change to Qpbar else: raise ValueError("non-prime passed into Berkovich space") if is_AffineSpace(base): base = base.base_ring() if base in NumberFields(): if ideal is None: raise ValueError('passed a number field but not an ideal') if base is not QQ: if not isinstance(ideal, NumberFieldFractionalIdeal): raise ValueError( 'ideal was not an ideal of a number field') if ideal.number_field() != base: raise ValueError('passed number field ' + \ '%s but ideal was an ideal of %s' %(base, ideal.number_field())) prime = ideal.smallest_integer() else: if ideal not in QQ: raise ValueError('ideal was not an element of QQ') prime = ideal if not ideal.is_prime(): raise ValueError('passed non prime ideal') self._base_type = 'number field' elif isinstance(base, sage.rings.abc.pAdicField): # change base to Qpbar prime = base.prime() ideal = None self._base_type = 'padic field' else: raise ValueError("base of Berkovich Space must be a padic field " + \ "or a number field") self._ideal = ideal self._p = prime Parent.__init__(self, base=base, category=TopologicalSpaces())
def padic_regulator(self, prec=20): r""" Computes the canonical `p`-adic regulator on the extended Mordell-Weil group as in [MTT] (with the correction of [Wer] and sign convention in [SW].) The `p`-adic Birch and Swinnerton-Dyer conjecture predicts that this value appears in the formula for the leading term of the `p`-adic L-function. INPUT: - ``prec`` - the `p`-adic precision, default is 20. REFERENCES: - [MTT] B. Mazur, J. Tate, and J. Teitelbaum, On `p`-adic analogues of the conjectures of Birch and Swinnerton-Dyer, Inventiones mathematicae 84, (1986), 1-48. - [Wer] Annette Werner, Local heights on abelian varieties and rigid analytic unifomization, Doc. Math. 3 (1998), 301-319. - [SW] William Stein and Christian Wuthrich, Computations About Tate-Shafarevich Groups using Iwasawa theory, preprint 2009. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.padic_regulator() 2*5^-1 + 1 + 2*5 + 2*5^2 + 3*5^3 + 3*5^6 + 5^7 + 3*5^9 + 3*5^10 + 3*5^12 + 4*5^13 + 3*5^15 + 2*5^16 + 3*5^18 + 4*5^19 + O(5^20) """ prec = prec + 4 K = Qp(self._p, prec=prec) rank = self._E.rank() if rank == 0: return K(1) if not self.is_split(): raise NotImplementedError( "The p-adic regulator is not implemented for non-split multiplicative reduction." ) basis = self._E.gens() M = matrix.matrix(K, rank, rank, 0) height = self.padic_height(prec=prec) point_height = [height(P) for P in basis] for i in range(rank): for j in range(i + 1, rank): M[i, j] = M[j, i] = (-point_height[i] - point_height[j] + height(basis[i] + basis[j])) / 2 for i in range(rank): M[i, i] = point_height[i] return M.determinant()
def __init__(self, base, ideal=None): """ The Python constructor. EXAMPLES:: sage: Berkovich_Cp_Projective(3) Projective Berkovich line over Cp(3) of precision 20 """ if base in ZZ: if base.is_prime(): base = ProjectiveSpace(Qp(base), 1) else: raise ValueError("non-prime passed into Berkovich space") if base in NumberFields() or isinstance(base, sage.rings.abc.pAdicField): base = ProjectiveSpace(base, 1) if not is_ProjectiveSpace(base): try: base = ProjectiveSpace(base) except: raise ValueError( "base of projective Berkovich space must be projective space" ) if not isinstance(base.base_ring(), sage.rings.abc.pAdicField): if base.base_ring() not in NumberFields(): raise ValueError("base of projective Berkovich space must be " + \ "projective space over Qp or a number field") else: if ideal is None: raise ValueError('passed a number field but not an ideal') if base.base_ring() is not QQ: if not isinstance(ideal, NumberFieldFractionalIdeal): raise ValueError('ideal was not a number field ideal') if ideal.number_field() != base.base_ring(): raise ValueError('passed number field ' + \ '%s but ideal was an ideal of %s' %(base.base_ring(), ideal.number_field())) prime = ideal.smallest_integer() else: if ideal not in QQ: raise ValueError('ideal was not an element of QQ') prime = ideal if not ideal.is_prime(): raise ValueError('passed non prime ideal') self._base_type = 'number field' else: prime = base.base_ring().prime() ideal = None self._base_type = 'padic field' if base.dimension_relative() != 1: raise ValueError("base of projective Berkovich space must be " + \ "projective space of dimension 1 over Qp or a number field") self._p = prime self._ideal = ideal Parent.__init__(self, base=base, category=TopologicalSpaces())
def test_formula_display45(Lp, p, E, K, remove_numpoints=False): from sage.arith.misc import algdep prec = Lp.parent().precision_cap() + 100 QQp = Qp(p, prec) hK = K.class_number() EFp = p + 1 - E.ap(p) phi = K.hom([K.gen().minpoly().roots(QQp)[0][0]]) u = phi((K.ideal(p).factor()[0][0]**hK).gens_reduced()[0]) if u.valuation() == 0: u = phi((K.ideal(p).factor()[1][0]**hK).gens_reduced()[0]) assert u.valuation() > 0 ulog = u.log(0) PH = E.heegner_point(K.discriminant()) PH = PH.point_exact(200) # Hard-coded, DEBUG H = PH[0].parent() H1, H_to_H1, K_to_H1, _ = H.composite_fields(K, both_maps=True)[0] kgen = K_to_H1(K.gen()) sigmas = [o for o in H1.automorphisms() if o(kgen) == kgen] EH1 = E.change_ring(H1) EK = E.change_ring(K) PK = EH1(0) for sigma in sigmas: PK += EH1(sigma(H_to_H1(PH[0])), sigma(H_to_H1(PH[1]))) PK = EK(K(PK[0]), K(PK[1])) nn = 1 while True: nPK = nn * PK PKpn = E.change_ring(QQp)((phi(nPK[0]), phi(nPK[1]))) try: tvar = -phi(nPK[0] / nPK[1]) logPK = E.change_ring(QQp).formal_group().log(prec)(tvar) / nn break except (ZeroDivisionError, ValueError): nn += 1 print 'nn=', nn assert PK.order() == Infinity print "------------------------------------" print "p = %s, cond(E) = %s, disc(K) = %s" % (p, E.conductor(), K.discriminant()) print "------------------------------------" print "h_K = %s" % hK print "# E(F_p) = %s" % EFp if remove_numpoints: EFp = 1 print " (not taking them into account)" print "PK = %s" % PK ratio = Lp / ((EFp**2 * logPK**2) / (p * (p - 1) * hK * ulog)) print "ratio = %s" % algdep(ratio, 1).roots(QQ)[0][0] return ratio
def log_of_heegner_point(E,K,p,prec): QQp = Qp(p,prec) try: phi = K.hom([K.gen().minpoly().roots(QQp)[0][0]]) Kp = QQp except IndexError: Kp = QQp.extension(K.gen().minpoly(),names=str(K.gen())+'_p') ap = Kp.gen() phi = K.hom([ap]) PH = E.heegner_point(K.discriminant()) PH = PH.point_exact(2000) # Hard-coded, DEBUG H = PH[0].parent() try: H1, H_to_H1, K_to_H1, _ = H.composite_fields(K,both_maps = True)[0] Hrel = H1.relativize(K_to_H1,'b') def tr(x): return x.trace(K) / Hrel.relative_degree() except AttributeError: H1, H_to_H1, K_to_H1 = K, lambda x:x, lambda x:x Hrel = K def tr(x): return x Kgen = K.gen(0) sigmas = [sigma for sigma in Hrel.automorphisms() if sigma(Kgen) == Kgen] EH1 = E.change_ring(H1) EHrel = E.change_ring(Hrel) EK = E.change_ring(K) PK = EHrel(0) for sigma in sigmas: PK += EHrel([Hrel(sigma(H_to_H1(PH[0]))),Hrel(sigma(H_to_H1(PH[1])))]) EFp = (p**Kp.degree()+1-E.ap(p)) PK = EK([tr(PK[0]),tr(PK[1])]) n = 1 nPK = PK while not (phi(nPK[0]).valuation() < 0 and phi(nPK[1]).valuation() < 0): n += 1 nPK += PK tvar = -phi(nPK[0]/nPK[1]) logPK = E.change_ring(Kp).formal_group().log(prec)(tvar) / n return logPK
def teichmuller(self, prec): r""" Return Teichmuller lifts to the given precision. INPUT: - ``prec`` - a positive integer. OUTPUT: - a list of `p`-adic numbers, the cached Teichmuller lifts EXAMPLES:: sage: L = EllipticCurve('11a').padic_lseries(7) sage: L.teichmuller(1) [0, 1, 2, 3, 4, 5, 6] sage: L.teichmuller(2) [0, 1, 30, 31, 18, 19, 48] """ p = self._p K = Qp(p, prec, print_mode='series') return [Integer(0)] + \ [a.residue(prec).lift() for a in K.teichmuller_system()]
def psi(self): r""" The embedding $\Q(\alpha) \into \Q_p(a)$ sending $\alpha \mapsto a$. """ K_f = self._hecke_eigenvalue_field p = self._p # kbar = K_f.residue_field(p) Q = Qp(p) ###split case pOK = K_f.factor(p) if (len(pOK) == 2 and pOK[0][1] == 1): R = Q['x'] r1, r2 = R(K_f.defining_polynomial()).roots() psi1 = K_f.hom([r1[0]]) psi2 = K_f.hom([r2[0]]) return [psi1, psi2] else: F = Q.extension(K_f.defining_polynomial(), names='a') a = F.gen() psi = self._psis = [K_f.hom([a])] return psi
def psi(self): """ The embedding $\Q(\alpha) \into \Q_p(a)$ sending $\alpha \mapsto a$. """ K_f = self._hecke_eigenvalue_field p = self._p # kbar = K_f.residue_field(p) Q = Qp(p) ###split case pOK = K_f.factor(p) if (len(pOK) == 2 and pOK[0][1] == 1): R = Q['x'] r1, r2 = R(K_f.defining_polynomial()).roots() psi1 = K_f.hom([r1[0]]) psi2 = K_f.hom([r2[0]]) return [psi1, psi2] else: F = Q.extension(K_f.defining_polynomial(),names='a') a = F.gen() psi = self._psis = [K_f.hom([a])] return psi
def automorphy_factor_vector(p, a, c, k, chi, p_prec, var_prec, R): """ EXAMPLES:: sage: from sage.modular.pollack_stevens.families_util import automorphy_factor_vector sage: automorphy_factor_vector(3, 1, 3, 0, None, 4, 3, PowerSeriesRing(ZpCA(3), 'w')) [1 + O(3^20), O(3^21) + (3 + 3^2 + 2*3^3 + O(3^21))*w + (3^2 + 2*3^3 + O(3^22))*w^2, O(3^22) + (3^2 + 2*3^3 + O(3^22))*w + (2*3^2 + O(3^22))*w^2, O(3^22) + (3^2 + 3^3 + O(3^22))*w + (2*3^3 + O(3^23))*w^2] sage: automorphy_factor_vector(3, 1, 3, 2, None, 4, 3, PowerSeriesRing(ZpCA(3), 'w')) [1 + O(3^20), O(3^21) + (3 + 3^2 + 2*3^3 + O(3^21))*w + (3^2 + 2*3^3 + O(3^22))*w^2, O(3^22) + (3^2 + 2*3^3 + O(3^22))*w + (2*3^2 + O(3^22))*w^2, O(3^22) + (3^2 + 3^3 + O(3^22))*w + (2*3^3 + O(3^23))*w^2] sage: p, a, c, k, chi, p_prec, var_prec, R = 11, -3, 11, 0, None, 6, 4, PowerSeriesRing(ZpCA(11, 6), 'w') sage: automorphy_factor_vector(p, a, c, k, chi, p_prec, var_prec, R) [1 + O(11^6) + (7*11^2 + 4*11^3 + 11^4 + 9*11^5 + 3*11^6 + 10*11^7 + O(11^8))*w + (2*11^3 + 2*11^5 + 2*11^6 + 6*11^7 + 8*11^8 + O(11^9))*w^2 + (6*11^4 + 4*11^5 + 5*11^6 + 6*11^7 + 4*11^9 + O(11^10))*w^3, O(11^7) + (7*11 + 11^2 + 2*11^3 + 3*11^4 + 4*11^5 + 3*11^6 + O(11^7))*w + (2*11^2 + 4*11^3 + 5*11^4 + 10*11^5 + 10*11^6 + 2*11^7 + O(11^8))*w^2 + (6*11^3 + 6*11^4 + 2*11^5 + 9*11^6 + 9*11^7 + 2*11^8 + O(11^9))*w^3, O(11^8) + (3*11^2 + 4*11^4 + 2*11^5 + 6*11^6 + 10*11^7 + O(11^8))*w + (8*11^2 + 7*11^3 + 8*11^4 + 8*11^5 + 11^6 + O(11^8))*w^2 + (3*11^3 + 9*11^4 + 10*11^5 + 5*11^6 + 10*11^7 + 11^8 + O(11^9))*w^3, O(11^9) + (8*11^3 + 3*11^4 + 3*11^5 + 7*11^6 + 2*11^7 + 6*11^8 + O(11^9))*w + (10*11^3 + 6*11^5 + 7*11^6 + O(11^9))*w^2 + (4*11^3 + 11^4 + 8*11^8 + O(11^9))*w^3, O(11^10) + (2*11^4 + 9*11^5 + 8*11^6 + 5*11^7 + 4*11^8 + 6*11^9 + O(11^10))*w + (6*11^5 + 3*11^6 + 5*11^7 + 7*11^8 + 4*11^9 + O(11^10))*w^2 + (2*11^4 + 8*11^6 + 2*11^7 + 9*11^8 + 7*11^9 + O(11^10))*w^3, O(11^11) + (2*11^5 + 10*11^6 + 10*11^7 + 10*11^8 + 10*11^9 + 10*11^10 + O(11^11))*w + (5*11^5 + 10*11^6 + 10*11^7 + 10*11^8 + 10*11^9 + 10*11^10 + O(11^11))*w^2 + (2*11^5 + 10*11^6 + 10*11^7 + 10*11^8 + 10*11^9 + 10*11^10 + O(11^11))*w^3] sage: k = 2 sage: automorphy_factor_vector(p, a, c, k, chi, p_prec, var_prec, R) [9 + 6*11^2 + 11^3 + 9*11^4 + 8*11^5 + O(11^6) + (8*11^2 + 8*11^3 + 10*11^4 + 6*11^5 + 5*11^7 + O(11^8))*w + (7*11^3 + 11^4 + 8*11^5 + 9*11^7 + 10*11^8 + O(11^9))*w^2 + (10*11^4 + 7*11^5 + 7*11^6 + 3*11^7 + 8*11^8 + 4*11^9 + O(11^10))*w^3, O(11^7) + (8*11 + 3*11^2 + 6*11^3 + 11^4 + 6*11^5 + 11^6 + O(11^7))*w + (7*11^2 + 4*11^3 + 5*11^4 + 10*11^6 + 5*11^7 + O(11^8))*w^2 + (10*11^3 + 3*11^4 + 4*11^5 + 7*11^6 + 10*11^7 + 3*11^8 + O(11^9))*w^3, O(11^8) + (5*11^2 + 2*11^3 + 10*11^4 + 3*11^5 + 8*11^6 + 7*11^7 + O(11^8))*w + (6*11^2 + 3*11^3 + 5*11^4 + 11^5 + 5*11^6 + 9*11^7 + O(11^8))*w^2 + (5*11^3 + 6*11^4 + 5*11^5 + 2*11^6 + 9*11^7 + 6*11^8 + O(11^9))*w^3, O(11^9) + (6*11^3 + 11^5 + 8*11^6 + 9*11^7 + 2*11^8 + O(11^9))*w + (2*11^3 + 8*11^4 + 4*11^5 + 6*11^6 + 11^7 + 8*11^8 + O(11^9))*w^2 + (3*11^3 + 11^4 + 3*11^5 + 11^6 + 5*11^7 + 6*11^8 + O(11^9))*w^3, O(11^10) + (7*11^4 + 5*11^5 + 3*11^6 + 10*11^7 + 10*11^8 + 11^9 + O(11^10))*w + (10*11^5 + 9*11^6 + 6*11^7 + 6*11^8 + 10*11^9 + O(11^10))*w^2 + (7*11^4 + 11^5 + 7*11^6 + 5*11^7 + 6*11^8 + 2*11^9 + O(11^10))*w^3, O(11^11) + (7*11^5 + 3*11^6 + 8*11^8 + 5*11^9 + 8*11^10 + O(11^11))*w + (11^5 + 6*11^6 + 7*11^7 + 11^8 + 2*11^10 + O(11^11))*w^2 + (7*11^5 + 3*11^6 + 8*11^8 + 5*11^9 + 8*11^10 + O(11^11))*w^3] """ S = PolynomialRing(R, 'z') z = S.gens()[0] w = R.gen() aut = S(1) for n in range(1, var_prec): ## RP: I doubled the precision in "z" here to account for the loss of precision from plugging in arg in below ## This should be done better. LB = logpp_binom(n, p, ceil(p_prec * (p - 1) / (p - 2))) ta = ZZ(Qp(p, 2 * max(p_prec, var_prec)).teichmuller(a)) arg = (a / ta - 1) / p + c / (p * ta) * z aut += LB(arg).truncate(p_prec) * (w**n) aut *= (ta**k) #if not (chi is None): # aut *= chi(a) aut = aut.list() len_aut = len(aut) if len_aut == p_prec: return aut elif len_aut > p_prec: return aut[:p_prec] return aut + [R.zero_element()] * (p_prec - len_aut)
def change_precision(self, new_prec): """ Returns a FamiliesOfOMS coefficient module with same input data as self, but with precision cap ``new_prec`` """ #print new_prec if new_prec == self._prec_cap: return self base_coeffs = self.base_ring().base_ring() if new_prec[0] > base_coeffs.precision_cap(): #THERE'S NO WAY TO EXTEND PRECISION ON BASE RING!!! This is a crappy hack: if base_coeffs.is_field(): base_coeffs = Qp(self.prime(), new_prec[0]) else: base_coeffs = ZpCA(self.prime(), new_prec[0]) return FamiliesOfOverconvergentDistributions(self._k, prec_cap = new_prec, base_coeffs=base_coeffs, character=self._character, adjuster=self._adjuster, act_on_left=self.action().is_left(), dettwist=self._dettwist, variable_name = self.base_ring().variable_name())
def completion(self, p, prec, extras={}): r""" Return the completion of `\QQ` at `p`. EXAMPLES:: sage: QQ.completion(infinity, 53) Real Field with 53 bits of precision sage: QQ.completion(5, 15, {'print_mode': 'bars'}) 5-adic Field with capped relative precision 15 """ if p == infinity.Infinity: from sage.rings.real_mpfr import create_RealField return create_RealField(prec, **extras) else: from sage.rings.padics.factory import Qp return Qp(p, prec, **extras)
def parametrisation_onto_original_curve(self, u, prec=None): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the original curve under the `p`-adic uniformisation of `E`. INPUT: - ``u`` -- a non-zero `p`-adic number. - ``prec`` -- the `p`-adic precision, default is the relative precision of ``u`` otherwise 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10)) (4*5^-2 + 4*5^-1 + 4 + 2*5^3 + 3*5^4 + 2*5^6 + O(5^7) : 3*5^-3 + 5^-2 + 4*5^-1 + 1 + 4*5 + 5^2 + 3*5^5 + O(5^6) : 1 + O(5^10)) sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10), prec=20) Traceback (most recent call last): ... ValueError: Requested more precision than the precision of u Here is how one gets a 4-torsion point on `E` over `\QQ_5`:: sage: R = Qp(5,30) sage: i = R(-1).sqrt() sage: T = eq.parametrisation_onto_original_curve(i, prec=30); T (2 + 3*5 + 4*5^2 + 2*5^3 + 5^4 + 4*5^5 + 2*5^7 + 5^8 + 5^9 + 5^12 + 3*5^13 + 3*5^14 + 5^15 + 4*5^17 + 5^18 + 3*5^19 + 2*5^20 + 4*5^21 + 5^22 + 3*5^23 + 3*5^24 + 4*5^25 + 3*5^26 + 3*5^27 + 3*5^28 + 3*5^29 + O(5^30) : 3*5 + 5^2 + 5^4 + 3*5^5 + 3*5^7 + 2*5^8 + 4*5^9 + 5^10 + 2*5^11 + 4*5^13 + 2*5^14 + 4*5^15 + 4*5^16 + 3*5^17 + 2*5^18 + 4*5^20 + 2*5^21 + 2*5^22 + 4*5^23 + 4*5^24 + 4*5^25 + 5^26 + 3*5^27 + 2*5^28 + O(5^30) : 1 + O(5^30)) sage: 4*T (0 : 1 + O(5^30) : 0) """ if not self.is_split(): raise ValueError("The curve must have split multiplicative " "reduction.") if prec is None: prec = getattr(u, "precision_relative", lambda: 20)() P = self.parametrisation_onto_tate_curve(u, prec=prec) C, r, s, t = self._inverse_isomorphism(prec=prec) xx = r + C**2 * P[0] yy = t + s * C**2 * P[0] + C**3 * P[1] R = Qp(self._p, prec) E_over_Qp = self._E.base_extend(R) return E_over_Qp([xx, yy])
def _height(P, check=True): if check: assert P.curve( ) == self._E, "the point P must lie on the curve from which the height function was created" Q = n * P cQ = denominator(Q[0]) q = self.parameter(prec=prec) nn = q.valuation() precp = prec + nn + 2 uQ = self.lift(Q, prec=precp) si = self.__padic_sigma_square(uQ, prec=precp) q = self.parameter(prec=precp) nn = q.valuation() qEu = q / p**nn res = -(log(si * self._Csquare(prec=precp) / cQ) + log(uQ)**2 / log(qEu)) / n**2 R = Qp(self._p, prec) return R(res)
def parametrisation_onto_original_curve(self, u, prec=20): r""" Given an element `u` in `\QQ_p^{\times}`, this computes its image on the original curve under the `p`-adic uniformisation of `E`. INPUT: - ``u`` - a non-zero `p`-adic number. - ``prec`` - the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.parametrisation_onto_original_curve(1+5+5^2+O(5^10)) (4*5^-2 + 4*5^-1 + 4 + 2*5^3 + 3*5^4 + 2*5^6 + O(5^7) : 3*5^-3 + 5^-2 + 4*5^-1 + 1 + 4*5 + 5^2 + 3*5^5 + O(5^6) : 1 + O(5^20)) Here is how one gets a 4-torsion point on `E` over `\QQ_5`:: sage: R = Qp(5,10) sage: i = R(-1).sqrt() sage: T = eq.parametrisation_onto_original_curve(i); T (2 + 3*5 + 4*5^2 + 2*5^3 + 5^4 + 4*5^5 + 2*5^7 + 5^8 + 5^9 + O(5^10) : 3*5 + 5^2 + 5^4 + 3*5^5 + 3*5^7 + 2*5^8 + 4*5^9 + O(5^10) : 1 + O(5^20)) sage: 4*T (0 : 1 + O(5^20) : 0) """ if not self.is_split(): raise ValueError( "The curve must have split multiplicative reduction.") P = self.parametrisation_onto_tate_curve(u, prec=20) isom = self._inverse_isomorphism(prec=prec) C = isom[0] r = isom[1] s = isom[2] t = isom[3] xx = r + C**2 * P[0] yy = t + s * C**2 * P[0] + C**3 * P[1] R = Qp(self._p, prec) E_over_Qp = self._E.base_extend(R) return E_over_Qp([xx, yy])
def find_Apow_and_ord(A, E, p, prec): f_degree = A.change_ring( GF(p)).charpoly().splitting_field(names='a').degree() r = (p**f_degree - 1) * p**prec Apow = take_power(A, r - 1) Ar = multiply_and_reduce(Apow, A) Ar = ech_form(Ar, p) Ar.change_ring(Qp(p, prec)) ord_basis = [] for o in Ar.rows(): if o.is_zero(): break ord_basis.append(o) try: E = E.apply_map(lambda x: x.lift()) except AttributeError: pass ord_basis_qexp = Matrix(ord_basis).apply_map( lambda x: x.lift()).change_ring(QQ) * E return Apow, ord_basis_qexp
def change_precision(self, new_prec): """ Returns an OMS coefficient module with same input data as self, but with precision cap ``new_prec`` """ if new_prec == self._prec_cap: return self base = self.base_ring() if new_prec > base.precision_cap(): #THERE'S NO WAY TO EXTEND PRECISION ON BASE RING!!! This is a crappy hack: if self.base_ring().is_field(): base = Qp(self.prime(), new_prec) else: base = ZpCA(self.prime(), new_prec) return OverconvergentDistributions(self._k, prec_cap=new_prec, base=base, character=self._character, adjuster=self._adjuster, act_on_left=self.action().is_left(), dettwist=self._dettwist)
def define_qexpansions_from_dirichlet_character(p, prec, eps, num_coefficients, magma): QQp = Qp(p,prec) N = eps.modulus() g1qexp = sage_character_to_magma(eps,N=N,magma=magma).ModularForms(1).EisensteinSeries()[1].qExpansion(num_coefficients + 20).Eltseq().sage() # DEBUG den = lcm([QQ(o).denominator() for o in g1qexp]) g1qexp = [ZZ(den * o) for o in g1qexp] print len(g1qexp) g0 = ModFormqExp(g1qexp, QQp, weight=1, character = eps, level = N) weight = 1 alpha = 1 qexp_plus = [QQp(o) for o in g1qexp] qexp_minus = [QQp(o) for o in g1qexp] for i in range(len(g1qexp) // p): qexp_plus[p * i] += g1qexp[i] qexp_minus[p * i] -= g1qexp[i] gammaplus = ModFormqExp(qexp_plus, QQp, weight=1, level = N) gammaminus = ModFormqExp(qexp_minus, QQp, weight=1, level = N) return gammaplus, gammaminus, g0
def curve(self, prec=20): r""" Return the `p`-adic elliptic curve of the form `y^2+x y = x^3 + s_4 x+s_6`. This curve with split multiplicative reduction is isomorphic to the given curve over the algebraic closure of `\QQ_p`. INPUT: - ``prec`` -- the `p`-adic precision, default is 20. EXAMPLES:: sage: eq = EllipticCurve('130a1').tate_curve(5) sage: eq.curve(prec=5) Elliptic Curve defined by y^2 + (1+O(5^5))*x*y = x^3 + (2*5^4+5^5+2*5^6+5^7+3*5^8+O(5^9))*x + (2*5^3+5^4+2*5^5+5^7+O(5^8)) over 5-adic Field with capped relative precision 5 """ Eq = getattr(self, "__curve", None) if Eq and Eq.a6().precision_relative() >= prec: return Eq.change_ring(Qp(self._p, prec)) qE = self.parameter(prec=prec) precp = prec + 2 tate_a4 = -5 * self.__sk(3, precp) tate_a6 = (tate_a4 - 7 * self.__sk(5, precp)) / 12 R = qE.parent() Eq = EllipticCurve( [R.one(), R.zero(), R.zero(), R(tate_a4), R(tate_a6)]) self.__curve = Eq return Eq
def test_formula_display45(Lp, p, E, K, outfile=None): from sage.arith.misc import algdep prec = Lp.parent().precision_cap() + 100 QQp = Qp(p,prec) hK = K.class_number() EFp = p+1 - E.ap(p) phi = K.hom([K.gen().minpoly().roots(QQp)[0][0]]) ualg = (K.ideal(p).factor()[0][0]**hK).gens_reduced()[0] ulog = get_ulog(ualg, K, p, prec) logPK = log_of_heegner_point(E,K,p,prec) fwrite("------------------------------------", outfile) fwrite("p = %s, cond(E) = %s, disc(K) = %s"%(p,E.conductor(),K.discriminant()), outfile) fwrite("------------------------------------", outfile) fwrite("h_K = %s"%hK, outfile) fwrite("# E(F_p) = %s"%EFp, outfile) fwrite("u satisfies: %s"%ualg.minpoly(), outfile) fwrite("ulog = %s"%ulog, outfile) fwrite("logPK = %s"%logPK, outfile) ratio = Lp / ( (EFp**2 * logPK**2 ) / (p * (p-1) * hK * ulog) ) fwrite("ratio = %s"%ratio, outfile) fwrite("ratio ~ %s"%algdep(ratio, 1).roots(QQ)[0][0], outfile) return ratio
def logp_fcn(p, p_prec, z): """this is the *function* on Z_p^* which sends z to log_p(z) using a power series truncated at p_prec terms""" R = Qp(p, 2 * p_prec) z = z / R.teichmuller(z) return sum([((-1) ** (m - 1)) * ((z - 1) ** m) / m for m in range(1, p_prec)])
def python(z, locals=None): """ Return the closest Python/Sage equivalent of the given pari object. INPUT: - `z` -- pari object - `locals` -- optional dictionary used in fallback cases that involve sage_eval The component parts of a t_COMPLEX may be t_INT, t_REAL, t_INTMOD, t_FRAC, t_PADIC. The components need not have the same type (e.g. if z=2+1.2*I then z.real() is t_INT while z.imag() is t_REAL(). They are converted as follows: t_INT: ZZ[i] t_FRAC: QQ(i) t_REAL: ComplexField(prec) for equivalent precision t_INTMOD, t_PADIC: raise NotImplementedError EXAMPLES:: sage: a = pari('(3+I)').python(); a i + 3 sage: a.parent() Maximal Order in Number Field in i with defining polynomial x^2 + 1 sage: a = pari('2^31-1').python(); a 2147483647 sage: a.parent() Integer Ring sage: a = pari('12/34').python(); a 6/17 sage: a.parent() Rational Field sage: a = pari('1.234').python(); a 1.23400000000000000 sage: a.parent() Real Field with 64 bits of precision sage: a = pari('(3+I)/2').python(); a 1/2*i + 3/2 sage: a.parent() Number Field in i with defining polynomial x^2 + 1 Conversion of complex numbers: the next example is converting from an element of the Symbolic Ring, which goes via the string representation:: sage: I = SR(I) sage: a = pari(1.0+2.0*I).python(); a 1.00000000000000000 + 2.00000000000000000*I sage: type(a) <type 'sage.rings.complex_number.ComplexNumber'> sage: a.parent() Complex Field with 64 bits of precision For architecture-independent complex numbers, start from a suitable ComplexField:: sage: z = pari(CC(1.0+2.0*I)); z 1.00000000000000 + 2.00000000000000*I sage: a=z.python(); a 1.00000000000000000 + 2.00000000000000000*I sage: a.parent() Complex Field with 64 bits of precision Vectors and matrices:: sage: a = pari('[1,2,3,4]') sage: a [1, 2, 3, 4] sage: a.type() 't_VEC' sage: b = a.python(); b [1, 2, 3, 4] sage: type(b) <type 'list'> sage: a = pari('[1,2;3,4]') sage: a.type() 't_MAT' sage: b = a.python(); b [1 2] [3 4] sage: b.parent() Full MatrixSpace of 2 by 2 dense matrices over Integer Ring sage: a = pari('Vecsmall([1,2,3,4])') sage: a.type() 't_VECSMALL' sage: a.python() [1, 2, 3, 4] We use the locals dictionary:: sage: f = pari('(2/3)*x^3 + x - 5/7 + y') sage: x,y=var('x,y') sage: import sage.libs.pari.gen_py sage: sage.libs.pari.gen_py.python(f, {'x':x, 'y':y}) 2/3*x^3 + x + y - 5/7 sage: sage.libs.pari.gen_py.python(f) Traceback (most recent call last): ... NameError: name 'x' is not defined Conversion of p-adics:: sage: K = Qp(11,5) sage: x = K(11^-10 + 5*11^-7 + 11^-6); x 11^-10 + 5*11^-7 + 11^-6 + O(11^-5) sage: y = pari(x); y 11^-10 + 5*11^-7 + 11^-6 + O(11^-5) sage: y.sage() 11^-10 + 5*11^-7 + 11^-6 + O(11^-5) sage: pari(K(11^-5)).sage() 11^-5 + O(11^0) """ from sage.libs.pari.pari_instance import prec_words_to_bits t = z.type() if t == "t_REAL": return RealField(prec_words_to_bits(z.precision()))(z) elif t == "t_FRAC": Q = RationalField() return Q(z) elif t == "t_INT": Z = IntegerRing() return Z(z) elif t == "t_COMPLEX": tx = z.real().type() ty = z.imag().type() if tx in ["t_INTMOD", "t_PADIC"] or ty in ["t_INTMOD", "t_PADIC"]: raise NotImplementedError( "No conversion to python available for t_COMPLEX with t_INTMOD or t_PADIC components" ) if tx == "t_REAL" or ty == "t_REAL": xprec = z.real().precision() # will be 0 if exact yprec = z.imag().precision() # will be 0 if exact if xprec == 0: prec = prec_words_to_bits(yprec) elif yprec == 0: prec = prec_words_to_bits(xprec) else: prec = max(prec_words_to_bits(xprec), prec_words_to_bits(yprec)) R = RealField(prec) C = ComplexField(prec) return C(R(z.real()), R(z.imag())) if tx == "t_FRAC" or ty == "t_FRAC": return QuadraticField(-1, 'i')([python(c) for c in list(z)]) if tx == "t_INT" or ty == "t_INT": return QuadraticField( -1, 'i').ring_of_integers()([python(c) for c in list(z)]) raise NotImplementedError( "No conversion to python available for t_COMPLEX with components %s" % (tx, ty)) elif t == "t_VEC": return [python(x) for x in z.python_list()] elif t == "t_VECSMALL": return z.python_list_small() elif t == "t_MAT": from sage.matrix.constructor import matrix return matrix(z.nrows(), z.ncols(), [ python(z[i, j]) for i in range(z.nrows()) for j in range(z.ncols()) ]) elif t == "t_PADIC": from sage.rings.padics.factory import Qp Z = IntegerRing() p = z.padicprime() rprec = Z(z.padicprec(p)) - Z(z._valp()) K = Qp(Z(p), rprec) return K(z.lift()) else: from sage.misc.sage_eval import sage_eval return sage_eval(str(z), locals=locals)
def an_padic(self, p, prec=0, use_twists=True): r""" Returns the conjectural order of `Sha(E/\QQ)`, according to the `p`-adic analogue of the Birch and Swinnerton-Dyer conjecture as formulated in [MTT]_ and [BP]_. REFERENCES: .. [MTT] \B. Mazur, J. Tate, and J. Teitelbaum, On `p`-adic analogues of the conjectures of Birch and Swinnerton-Dyer, Inventiones mathematicae 84, (1986), 1-48. .. [BP] Dominique Bernardi and Bernadette Perrin-Riou, Variante `p`-adique de la conjecture de Birch et Swinnerton-Dyer (le cas supersingulier), C. R. Acad. Sci. Paris, Sér I. Math., 317 (1993), no. 3, 227-232. INPUT: - ``p`` - a prime > 3 - ``prec`` (optional) - the precision used in the computation of the `p`-adic L-Series - ``use_twists`` (default = ``True``) - If ``True`` the algorithm may change to a quadratic twist with minimal conductor to do the modular symbol computations rather than using the modular symbols of the curve itself. If ``False`` it forces the computation using the modular symbols of the curve itself. OUTPUT: `p`-adic number - that conjecturally equals `\# Sha(E/\QQ)`. If ``prec`` is set to zero (default) then the precision is set so that at least the first `p`-adic digit of conjectural `\# Sha(E/\QQ)` is determined. EXAMPLES: Good ordinary examples:: sage: EllipticCurve('11a1').sha().an_padic(5) # rank 0 1 + O(5^22) sage: EllipticCurve('43a1').sha().an_padic(5) # rank 1 1 + O(5) sage: EllipticCurve('389a1').sha().an_padic(5,4) # rank 2, long time (2s on sage.math, 2011) 1 + O(5^3) sage: EllipticCurve('858k2').sha().an_padic(7) # rank 0, non trivial sha, long time (10s on sage.math, 2011) 7^2 + O(7^24) sage: EllipticCurve('300b2').sha().an_padic(3) # 9 elements in sha, long time (2s on sage.math, 2011) 3^2 + O(3^24) sage: EllipticCurve('300b2').sha().an_padic(7, prec=6) # long time 2 + 7 + O(7^8) Exceptional cases:: sage: EllipticCurve('11a1').sha().an_padic(11) # rank 0 1 + O(11^22) sage: EllipticCurve('130a1').sha().an_padic(5) # rank 1 1 + O(5) Non-split, but rank 0 case (:trac:`7331`):: sage: EllipticCurve('270b1').sha().an_padic(5) # rank 0, long time (2s on sage.math, 2011) 1 + O(5^22) The output has the correct sign:: sage: EllipticCurve('123a1').sha().an_padic(41) # rank 1, long time (3s on sage.math, 2011) 1 + O(41) Supersingular cases:: sage: EllipticCurve('34a1').sha().an_padic(5) # rank 0 1 + O(5^22) sage: EllipticCurve('53a1').sha().an_padic(5) # rank 1, long time (11s on sage.math, 2011) 1 + O(5) Cases that use a twist to a lower conductor:: sage: EllipticCurve('99a1').sha().an_padic(5) 1 + O(5) sage: EllipticCurve('240d3').sha().an_padic(5) # sha has 4 elements here 4 + O(5) sage: EllipticCurve('448c5').sha().an_padic(7,prec=4, use_twists=False) # long time (2s on sage.math, 2011) 2 + 7 + O(7^6) sage: EllipticCurve([-19,34]).sha().an_padic(5) # see trac #6455, long time (4s on sage.math, 2011) 1 + O(5) Test for :trac:`15737`:: sage: E = EllipticCurve([-100,0]) sage: s = E.sha() sage: s.an_padic(13) 1 + O(13^20) """ try: return self.__an_padic[(p,prec)] except AttributeError: self.__an_padic = {} except KeyError: pass E = self.Emin tam = E.tamagawa_product() tors = E.torsion_order()**2 r = E.rank() if r > 0 : reg = E.padic_regulator(p) else: if E.is_supersingular(p): reg = vector([ Qp(p,20)(1), 0 ]) else: reg = Qp(p,20)(1) if use_twists and p > 2: Et, D = E.minimal_quadratic_twist() # trac 6455 : we have to assure that the twist back is allowed D = ZZ(D) if D % p == 0: D = ZZ(D/p) for ell in D.prime_divisors(): if ell % 2 == 1: if Et.conductor() % ell**2 == 0: D = ZZ(D/ell) ve = valuation(D,2) de = ZZ( (D/2**ve).abs() ) if de % 4 == 3: de = -de Et = E.quadratic_twist(de) # now check individually if we can twist by -1 or 2 or -2 Nmin = Et.conductor() Dmax = de for DD in [-4*de,8*de,-8*de]: Et = E.quadratic_twist(DD) if Et.conductor() < Nmin and valuation(Et.conductor(),2) <= valuation(DD,2): Nmin = Et.conductor() Dmax = DD D = Dmax Et = E.quadratic_twist(D) lp = Et.padic_lseries(p) else : lp = E.padic_lseries(p) D = 1 if r == 0 and D == 1: # short cut for rank 0 curves, we do not # to compute the p-adic L-function, the leading # term will be the L-value divided by the Neron # period. ms = E.modular_symbol(sign=+1, normalize='L_ratio') lstar = ms(0)/E.real_components() bsd = tam/tors if prec == 0: #prec = valuation(lstar/bsd, p) prec = 20 shan = Qp(p,prec=prec+2)(lstar/bsd) elif E.is_ordinary(p): K = reg.parent() lg = log(K(1+p)) if (E.is_good(p) or E.ap(p) == -1): if not E.is_good(p): eps = 2 else: eps = (1-arith.kronecker_symbol(D,p)/lp.alpha())**2 # according to the p-adic BSD this should be equal to the leading term of the p-adic L-series divided by sha: bsdp = tam * reg * eps/tors/lg**r else: r += 1 # exceptional zero eq = E.tate_curve(p) Li = eq.L_invariant() # according to the p-adic BSD (Mazur-Tate-Teitelbaum) # this should be equal to the leading term of the p-adic L-series divided by sha: bsdp = tam * reg * Li/tors/lg**r v = bsdp.valuation() if v > 0: verbose("the prime is irregular for this curve.") # determine how much prec we need to prove at least the # triviality of the p-primary part of Sha if prec == 0: n = max(v,2) bounds = lp._prec_bounds(n,r+1) while bounds[r] <= v: n += 1 bounds = lp._prec_bounds(n,r+1) verbose("set precision to %s"%n) else: n = max(2,prec) not_yet_enough_prec = True while not_yet_enough_prec: lps = lp.series(n,quadratic_twist=D,prec=r+1) lstar = lps[r] if (lstar != 0) or (prec != 0): not_yet_enough_prec = False else: n += 1 verbose("increased precision to %s"%n) shan = lstar/bsdp elif E.is_supersingular(p): K = reg[0].parent() lg = log(K(1+p)) # according to the p-adic BSD this should be equal to the leading term of the D_p - valued # L-series : bsdp = tam /tors/lg**r * reg # note this is an element in Q_p^2 verbose("the algebraic leading terms : %s"%bsdp) v = [bsdp[0].valuation(),bsdp[1].valuation()] if prec == 0: n = max(min(v)+2,3) else: n = max(3,prec) verbose("...computing the p-adic L-series") not_yet_enough_prec = True while not_yet_enough_prec: lps = lp.Dp_valued_series(n,quadratic_twist=D,prec=r+1) lstar = [lps[0][r],lps[1][r]] verbose("the leading terms : %s"%lstar) if (lstar[0] != 0 or lstar[1] != 0) or ( prec != 0): not_yet_enough_prec = False else: n += 1 verbose("increased precision to %s"%n) verbose("...putting things together") if bsdp[0] != 0: shan0 = lstar[0]/bsdp[0] else: shan0 = 0 # this should actually never happen if bsdp[1] != 0: shan1 = lstar[1]/bsdp[1] else: shan1 = 0 # this should conjecturally only happen when the rank is 0 verbose("the two values for Sha : %s"%[shan0,shan1]) # check consistency (the first two are only here to avoid a bug in the p-adic L-series # (namely the coefficients of zero-relative precision are treated as zero) if shan0 != 0 and shan1 != 0 and shan0 - shan1 != 0: raise RuntimeError("There must be a bug in the supersingular routines for the p-adic BSD.") #take the better if shan1 == 0 or shan0.precision_relative() > shan1.precision_relative(): shan = shan0 else: shan = shan1 else: raise ValueError("The curve has to have semi-stable reduction at p.") self.__an_padic[(p,prec)] = shan return shan
def an_padic(self, p, prec=0, use_twists=True): r""" Returns the conjectural order of `Sha(E/\QQ)`, according to the `p`-adic analogue of the Birch and Swinnerton-Dyer conjecture as formulated in [MTT]_ and [BP]_. REFERENCES: .. [MTT] B. Mazur, J. Tate, and J. Teitelbaum, On `p`-adic analogues of the conjectures of Birch and Swinnerton-Dyer, Inventiones mathematicae 84, (1986), 1-48. .. [BP] Dominique Bernardi and Bernadette Perrin-Riou, Variante `p`-adique de la conjecture de Birch et Swinnerton-Dyer (le cas supersingulier), C. R. Acad. Sci. Paris, Ser I. Math, 317 (1993), no 3, 227-232. .. [SW] William Stein and Christian Wuthrich, Computations About Tate-Shafarevich Groups using Iwasawa theory, preprint 2009. INPUT: - ``p`` - a prime > 3 - ``prec`` (optional) - the precision used in the computation of the `p`-adic L-Series - ``use_twists`` (default = ``True``) - If ``True`` the algorithm may change to a quadratic twist with minimal conductor to do the modular symbol computations rather than using the modular symbols of the curve itself. If ``False`` it forces the computation using the modular symbols of the curve itself. OUTPUT: `p`-adic number - that conjecturally equals `\# Sha(E/\QQ)`. If ``prec`` is set to zero (default) then the precision is set so that at least the first `p`-adic digit of conjectural `\# Sha(E/\QQ)` is determined. EXAMPLES: Good ordinary examples:: sage: EllipticCurve('11a1').sha().an_padic(5) # rank 0 1 + O(5^2) sage: EllipticCurve('43a1').sha().an_padic(5) # rank 1 1 + O(5) sage: EllipticCurve('389a1').sha().an_padic(5,4) # rank 2, long time (2s on sage.math, 2011) 1 + O(5^3) sage: EllipticCurve('858k2').sha().an_padic(7) # rank 0, non trivial sha, long time (10s on sage.math, 2011) Traceback (most recent call last): # 32-bit (see ticket :trac: `112111`) ... # 32-bit OverflowError: Python int too large to convert to C long # 32-bit 7^2 + O(7^6) # 64-bit sage: EllipticCurve('300b2').sha().an_padic(3) # 9 elements in sha, long time (2s on sage.math, 2011) 3^2 + O(3^6) sage: EllipticCurve('300b2').sha().an_padic(7, prec=6) # long time 2 + 7 + O(7^8) Exceptional cases:: sage: EllipticCurve('11a1').sha().an_padic(11) # rank 0 1 + O(11^2) sage: EllipticCurve('130a1').sha().an_padic(5) # rank 1 1 + O(5) Non-split, but rank 0 case (:trac:`7331`):: sage: EllipticCurve('270b1').sha().an_padic(5) # rank 0, long time (2s on sage.math, 2011) 1 + O(5^2) The output has the correct sign:: sage: EllipticCurve('123a1').sha().an_padic(41) # rank 1, long time (3s on sage.math, 2011) 1 + O(41) Supersingular cases:: sage: EllipticCurve('34a1').sha().an_padic(5) # rank 0 1 + O(5^2) sage: EllipticCurve('53a1').sha().an_padic(5) # rank 1, long time (11s on sage.math, 2011) 1 + O(5) Cases that use a twist to a lower conductor:: sage: EllipticCurve('99a1').sha().an_padic(5) 1 + O(5) sage: EllipticCurve('240d3').sha().an_padic(5) # sha has 4 elements here 4 + O(5) sage: EllipticCurve('448c5').sha().an_padic(7,prec=4, use_twists=False) # long time (2s on sage.math, 2011) 2 + 7 + O(7^6) sage: EllipticCurve([-19,34]).sha().an_padic(5) # see :trac: `6455`, long time (4s on sage.math, 2011) 1 + O(5) """ try: return self.__an_padic[(p,prec)] except AttributeError: self.__an_padic = {} except KeyError: pass E = self.Emin tam = E.tamagawa_product() tors = E.torsion_order()**2 reg = E.padic_regulator(p) # todo : here we should cache the rank computation r = E.rank() if use_twists and p > 2: Et, D = E.minimal_quadratic_twist() # trac 6455 : we have to assure that the twist back is allowed D = ZZ(D) if D % p == 0: D = D/p for ell in D.prime_divisors(): if ell % 2 == 1: if Et.conductor() % ell**2 == 0: D = D/ell ve = valuation(D,2) de = (D/2**ve).abs() if de % 4 == 3: de = -de Et = E.quadratic_twist(de) # now check individually if we can twist by -1 or 2 or -2 Nmin = Et.conductor() Dmax = de for DD in [-4*de,8*de,-8*de]: Et = E.quadratic_twist(DD) if Et.conductor() < Nmin and valuation(Et.conductor(),2) <= valuation(DD,2): Nmin = Et.conductor() Dmax = DD D = Dmax Et = E.quadratic_twist(D) lp = Et.padic_lseries(p) else : lp = E.padic_lseries(p) D = 1 if r == 0 and D == 1: # short cut for rank 0 curves, we do not # to compute the p-adic L-function, the leading # term will be the L-value divided by the Neron # period. ms = E.modular_symbol(sign=+1, normalize='L_ratio') lstar = ms(0)/E.real_components() bsd = tam/tors if prec == 0: prec = valuation(lstar/bsd, p) shan = Qp(p,prec=prec+2)(lstar/bsd) elif E.is_ordinary(p): K = reg.parent() lg = log(K(1+p)) if (E.is_good(p) or E.ap(p) == -1): if not E.is_good(p): eps = 2 else: eps = (1-arith.kronecker_symbol(D,p)/lp.alpha())**2 # according to the p-adic BSD this should be equal to the leading term of the p-adic L-series divided by sha: bsdp = tam * reg * eps/tors/lg**r else: r += 1 # exceptional zero eq = E.tate_curve(p) Li = eq.L_invariant() # according to the p-adic BSD (Mazur-Tate-Teitelbaum) # this should be equal to the leading term of the p-adic L-series divided by sha: bsdp = tam * reg * Li/tors/lg**r v = bsdp.valuation() if v > 0: verbose("the prime is irregular.") # determine how much prec we need to prove at least the triviality of # the p-primary part of Sha if prec == 0: n = max(v,2) bounds = lp._prec_bounds(n,r+1) while bounds[r] <= v: n += 1 bounds = lp._prec_bounds(n,r+1) verbose("set precision to %s"%n) else: n = max(2,prec) not_yet_enough_prec = True while not_yet_enough_prec: lps = lp.series(n,quadratic_twist=D,prec=r+1) lstar = lps[r] if (lstar != 0) or (prec != 0): not_yet_enough_prec = False else: n += 1 verbose("increased precision to %s"%n) shan = lstar/bsdp elif E.is_supersingular(p): K = reg[0].parent() lg = log(K(1+p)) # according to the p-adic BSD this should be equal to the leading term of the D_p - valued # L-series : bsdp = tam /tors/lg**r * reg # note this is an element in Q_p^2 verbose("the algebraic leading terms : %s"%bsdp) v = [bsdp[0].valuation(),bsdp[1].valuation()] if prec == 0: n = max(min(v)+2,3) else: n = max(3,prec) verbose("...computing the p-adic L-series") not_yet_enough_prec = True while not_yet_enough_prec: lps = lp.Dp_valued_series(n,quadratic_twist=D,prec=r+1) lstar = [lps[0][r],lps[1][r]] verbose("the leading terms : %s"%lstar) if (lstar[0] != 0 or lstar[1] != 0) or ( prec != 0): not_yet_enough_prec = False else: n += 1 verbose("increased precision to %s"%n) verbose("...putting things together") if bsdp[0] != 0: shan0 = lstar[0]/bsdp[0] else: shan0 = 0 # this should actually never happen if bsdp[1] != 0: shan1 = lstar[1]/bsdp[1] else: shan1 = 0 # this should conjecturally only happen when the rank is 0 verbose("the two values for Sha : %s"%[shan0,shan1]) # check consistency (the first two are only here to avoid a bug in the p-adic L-series # (namely the coefficients of zero-relative precision are treated as zero) if shan0 != 0 and shan1 != 0 and shan0 - shan1 != 0: raise RuntimeError("There must be a bug in the supersingular routines for the p-adic BSD.") #take the better if shan1 == 0 or shan0.precision_relative() > shan1.precision_relative(): shan = shan0 else: shan = shan1 else: raise ValueError("The curve has to have semi-stable reduction at p.") self.__an_padic[(p,prec)] = shan return shan
def alpha(self, prec=20): r""" Return a `p`-adic root `\alpha` of the polynomial `x^2 - a_p x + p` with `ord_p(\alpha) < 1`. In the ordinary case this is just the unit root. INPUT: - ``prec`` - positive integer, the `p`-adic precision of the root. EXAMPLES: """ try: return self._alpha[prec] except AttributeError: self._alpha = {} except KeyError: pass J = self._J p = self._p Q = Qp(p) try: a_p = self._ap except AttributeError: a_p = self._ap = self.ap() try: psis = self._psis except AttributeError: psis = self._psis = self.psi() K_f = self.hecke_eigenvalue_field() if len(psis) == 1: F = Q.extension(K_f.defining_polynomial(),names='a') a = F.gen() G = K_f.embeddings(K_f) if G[0](K_f.gen()) == K_f.gen(): conj_map = G[1] else: conj_map = G[0] v = self._dual_eigenvector v_conj = vector(conj_map(a) for a in v) a_p_conj = conj_map(a_p) R = F['x'] x = R.gen() psi = psis[0] a_p_padic = psi(a_p) a_p_conj_padic = psi(a_p_conj) f = x**2 - (a_p_padic)*x + p fconj = x**2 - (a_p_conj_padic)*x + p norm_f = f*fconj norm_f_basefield = norm_f.change_ring(Q) FF = norm_f_basefield().factor() root0 = -f.gcd(FF[0][0])[0] root1 = -f.gcd(FF[1][0])[0] if root0.valuation() < 1: padic_lseries_alpha = [root0] else: padic_lseries_alpha = [root1] else: a_p_conj_padic = [] a_p_padic = [] for psi in psis: a_p_padic = a_p_padic + [psi(a_p)] R = Q['x'] x = R.gen() padic_lseries_alpha = [] for aps in a_p_padic: f = R(x**2 - aps*x + p) roots = f.roots() root0 = roots[0][0] root1 = roots[1][0] if root0.valuation() < 1: padic_lseries_alpha = padic_lseries_alpha + [root0] else: padic_lseries_alpha = padic_lseries_alpha + [root1] return padic_lseries_alpha
def hilbert_symbol_negative_at_S(self, S, b, check=True): r""" Returns an integer that has a negative Hilbert symbol with respect to a given rational number and a given set of primes (or places). The function is algorithm 3.4.1 in [Kir2016]_. It finds an integer `a` that has negative Hilbert symbol with respect to a given rational number exactly at a given set of primes (or places). INPUT: - ``S`` -- a list of rational primes, the infinite place as real embedding of `\QQ` or as -1 - ``b`` -- a non-zero rational number which is a non-square locally at every prime in ``S``. - ``check`` -- ``bool`` (default:``True``) perform additional checks on input and confirm the output. OUTPUT: - An integer `a` that has negative Hilbert symbol `(a,b)_p` for every place `p` in `S` and no other place. EXAMPLES:: sage: QQ.hilbert_symbol_negative_at_S([-1,5,3,2,7,11,13,23], -10/7) -9867 sage: QQ.hilbert_symbol_negative_at_S([3, 5, QQ.places()[0], 11], -15) -33 sage: QQ.hilbert_symbol_negative_at_S([3, 5], 2) 15 TESTS:: sage: QQ.hilbert_symbol_negative_at_S(5/2, -2) Traceback (most recent call last): ... TypeError: first argument must be a list or integer :: sage: QQ.hilbert_symbol_negative_at_S([1, 3], 0) Traceback (most recent call last): ... ValueError: second argument must be nonzero :: sage: QQ.hilbert_symbol_negative_at_S([-1, 3, 5], 2) Traceback (most recent call last): ... ValueError: list should be of even cardinality :: sage: QQ.hilbert_symbol_negative_at_S([1, 3], 2) Traceback (most recent call last): ... ValueError: all entries in list must be prime or -1 for infinite place :: sage: QQ.hilbert_symbol_negative_at_S([5, 7], 2) Traceback (most recent call last): ... ValueError: second argument must be a nonsquare with respect to every finite prime in the list :: sage: QQ.hilbert_symbol_negative_at_S([1, 3], sqrt(2)) Traceback (most recent call last): ... TypeError: second argument must be a rational number :: sage: QQ.hilbert_symbol_negative_at_S([-1, 3], 2) Traceback (most recent call last): ... ValueError: if the infinite place is in the list, the second argument must be negative AUTHORS: - Simon Brandhorst, Juanita Duque, Anna Haensch, Manami Roy, Sandi Rudzinski (10-24-2017) """ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.padics.factory import Qp from sage.modules.free_module import VectorSpace from sage.matrix.constructor import matrix from sage.sets.primes import Primes from sage.arith.misc import hilbert_symbol, is_prime # input checks if not type(S) is list: raise TypeError("first argument must be a list or integer") # -1 is used for the infinite place infty = -1 for i in range(len(S)): if S[i] == self.places()[0]: S[i] = -1 if not b in self: raise TypeError("second argument must be a rational number") b = self(b) if b == 0: raise ValueError("second argument must be nonzero") if len(S) % 2: raise ValueError("list should be of even cardinality") for p in S: if p != infty: if check and not is_prime(p): raise ValueError("all entries in list must be prime" " or -1 for infinite place") R = Qp(p) if R(b).is_square(): raise ValueError( "second argument must be a nonsquare with" " respect to every finite prime in the list") elif b > 0: raise ValueError("if the infinite place is in the list, " "the second argument must be negative") # L is the list of primes that we need to consider, b must have # nonzero valuation for each prime in L, this is the set S' # in Kirschmer's algorithm L = [] L = [p[0] for p in b.factor() if p[0] not in S] # We must also consider 2 to be in L if 2 not in L and 2 not in S: L.append(2) # This adds the infinite place to L if b < 0 and infty not in S: L.append(infty) P = S + L # This constructs the vector v in the algorithm. This is the vector # that we are searching for. It represents the case when the Hilbert # symbol is negative for all primes in S and positive # at all primes in S' V = VectorSpace(GF(2), len(P)) v = V([1] * len(S) + [0] * len(L)) # Compute the map phi of Hilbert symbols at all the primes # in S and S' # For technical reasons, a Hilbert symbol of -1 is # respresented as 1 and a Hilbert symbol of 1 # is represented as 0 def phi(x): v = [(1 - hilbert_symbol(x, b, p)) // 2 for p in P] return V(v) M = matrix(GF(2), [phi(p) for p in P + [-1]]) # We search through all the primes for q in Primes(): # Only look at this prime if it is not in our list if q in P: continue # The algorithm terminates when the vector v is in the # subspace of V generated by the image of the phi map # on the set of generators w = phi(q) W = M.stack(matrix(w)) if v in W.row_space(): break Pq = P + [-1] + [q] l = W.solve_left(v) a = self.prod([Pq[i]**ZZ(l[i]) for i in range(l.degree())]) if check: assert phi(a) == v, "oops" return a
def padic_H_value(self, p, f, t, prec=None): """ Return the `p`-adic trace of Frobenius, computed using the Gross-Koblitz formula. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``prec`` -- precision (optional, default 20) OUTPUT: an integer EXAMPLES: From Benasque report [Benasque2009]_, page 8:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] [0, -476] sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] From [Roberts2015]_ (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 sage: H.padic_H_value(13,1,1/t) 0 REFERENCES: - [MagmaHGM]_ """ alpha = self._alpha beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() return(H.padic_H_value(p, f, ~t, prec)) t = QQ(t) gamma = self.gamma_array() q = p ** f # m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} m = defaultdict(lambda: 0) for r in range(q-1): u = QQ((r, q-1)) if u in beta: m[r] = beta.count(u) M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 if prec is None: prec = (self.weight()*f)//2 + ceil(log(self.degree(),p)) + 1 # For some reason, working in Qp instead of Zp is much faster; # it appears to avoid some costly conversions. p_ring = Qp(p, prec=prec) teich = p_ring.teichmuller(M / t) gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True, algorithm='sage', parent=p_ring) for r in range(q-1)] sigma = sum( ((-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv for v, gv in gamma.items()) // (p - 1)) * prod(gauss_table[(v * r) % (q - 1)][1] ** gv for v, gv in gamma.items()) * teich ** r) << (f*(D+m[0]-m[r])) for r in range(q-1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma return IntegerModRing(p**prec)(resu).lift_centered()