def compute_wp_pari(E,prec): r""" Computes the Weierstrass `\wp`-function via calling the corresponding function in pari. EXAMPLES:: sage: E = EllipticCurve([0,1]) sage: E.weierstrass_p(algorithm='pari') z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20) sage: E = EllipticCurve(GF(101),[5,4]) sage: E.weierstrass_p(prec=30, algorithm='pari') z^-2 + 100*z^2 + 86*z^4 + 34*z^6 + 50*z^8 + 82*z^10 + 45*z^12 + 70*z^14 + 33*z^16 + 87*z^18 + 33*z^20 + 36*z^22 + 45*z^24 + 40*z^26 + 12*z^28 + O(z^30) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari sage: compute_wp_pari(E, prec= 20) z^-2 + 100*z^2 + 86*z^4 + 34*z^6 + 50*z^8 + 82*z^10 + 45*z^12 + 70*z^14 + 33*z^16 + 87*z^18 + O(z^20) """ ep = E._pari_() wpp = ep.ellwp(n=prec) k = E.base_ring() R = LaurentSeriesRing(k,'z') z = R.gen() wp = z**(-2) for i in xrange(prec): wp += k(wpp[i]) * z**i wp = wp.add_bigoh(prec) return wp
def compute_wp_pari(E, prec): r""" Computes the Weierstrass `\wp`-function via calling the corresponding function in pari. EXAMPLES:: sage: E = EllipticCurve([0,1]) sage: E.weierstrass_p(algorithm='pari') z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20) sage: E = EllipticCurve(GF(101),[5,4]) sage: E.weierstrass_p(prec=30, algorithm='pari') z^-2 + 100*z^2 + 86*z^4 + 34*z^6 + 50*z^8 + 82*z^10 + 45*z^12 + 70*z^14 + 33*z^16 + 87*z^18 + 33*z^20 + 36*z^22 + 45*z^24 + 40*z^26 + 12*z^28 + O(z^30) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari sage: compute_wp_pari(E, prec= 20) z^-2 + 100*z^2 + 86*z^4 + 34*z^6 + 50*z^8 + 82*z^10 + 45*z^12 + 70*z^14 + 33*z^16 + 87*z^18 + O(z^20) """ ep = E._pari_() wpp = ep.ellwp(n=prec) k = E.base_ring() R = LaurentSeriesRing(k, 'z') z = R.gen() wp = z**(-2) for i in xrange(prec): wp += k(wpp[i]) * z**i wp = wp.add_bigoh(prec) return wp
def compute_wp_quadratic(k, A, B, prec): r""" Computes the truncated Weierstrass function of an elliptic curve defined by short Weierstrass model: `y^2 = x^3 + Ax + B`. Uses an algorithm that is of complexity `O(prec^2)`. Let p be the characteristic of the underlying field. Then we must have either p = 0, or p > prec + 2. INPUT: - ``k`` - the field of definition of the curve - ``A`` - and - ``B`` - the coefficients of the elliptic curve - ``prec`` - the precision to which we compute the series. OUTPUT: A Laurent series aproximating the Weierstrass `\wp`-function to precision ``prec``. ALGORITHM: This function uses the algorithm described in section 3.2 of [BMSS]. REFERENCES: [BMSS] Boston, Morain, Salvy, Schost, "Fast Algorithms for Isogenies." EXAMPLES:: sage: E = EllipticCurve([7,0]) sage: E.weierstrass_p(prec=10, algorithm='quadratic') z^-2 - 7/5*z^2 + 49/75*z^6 + O(z^10) sage: E = EllipticCurve(GF(103),[1,2]) sage: E.weierstrass_p(algorithm='quadratic') z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + 55*z^10 + 73*z^12 + 11*z^14 + 17*z^16 + 50*z^18 + O(z^20) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_quadratic sage: compute_wp_quadratic(E.base_ring(), E.a4(), E.a6(), prec=10) z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + O(z^10) """ m = (prec + 1) // 2 c = [0 for j in range(m)] c[0] = -A / 5 c[1] = -B / 7 # first Z represent z^2 R = LaurentSeriesRing(k, 'z') Z = R.gen() pe = Z**-1 + c[0] * Z + c[1] * Z**2 for i in range(3, m): t = 0 for j in range(1, i - 1): t += c[j - 1] * c[i - 2 - j] ci = (3 * t) / ((i - 2) * (2 * i + 3)) pe += ci * Z**i c[i - 1] = ci return pe(Z**2).add_bigoh(prec)
def compute_wp_quadratic(k, A, B, prec): r""" Computes the truncated Weierstrass function of an elliptic curve defined by short Weierstrass model: `y^2 = x^3 + Ax + B`. Uses an algorithm that is of complexity `O(prec^2)`. Let p be the characteristic of the underlying field. Then we must have either p = 0, or p > prec + 2. INPUT: - ``k`` - the field of definition of the curve - ``A`` - and - ``B`` - the coefficients of the elliptic curve - ``prec`` - the precision to which we compute the series. OUTPUT: A Laurent series aproximating the Weierstrass `\wp`-function to precision ``prec``. ALGORITHM: This function uses the algorithm described in section 3.2 of [BMSS]. REFERENCES: [BMSS] Boston, Morain, Salvy, Schost, "Fast Algorithms for Isogenies." EXAMPLES:: sage: E = EllipticCurve([7,0]) sage: E.weierstrass_p(prec=10, algorithm='quadratic') z^-2 - 7/5*z^2 + 49/75*z^6 + O(z^10) sage: E = EllipticCurve(GF(103),[1,2]) sage: E.weierstrass_p(algorithm='quadratic') z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + 55*z^10 + 73*z^12 + 11*z^14 + 17*z^16 + 50*z^18 + O(z^20) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_quadratic sage: compute_wp_quadratic(E.base_ring(), E.a4(), E.a6(), prec=10) z^-2 + 41*z^2 + 88*z^4 + 11*z^6 + 57*z^8 + O(z^10) """ m = (prec + 1)//2 c = [0 for j in range(m)] c[0] = -A/5 c[1] = -B/7 # first Z represent z^2 R = LaurentSeriesRing(k,'z') Z = R.gen() pe = Z**-1 + c[0]*Z + c[1]*Z**2 for i in range(3, m): t = 0 for j in range(1, i - 1): t += c[j-1]*c[i-2-j] ci = (3*t)/((i-2)*(2*i+3)) pe += ci * Z**i c[i-1] = ci return pe(Z**2).add_bigoh(prec)
def __init__(self, f, x0, singular_data, order=None): r"""Initialize a PuiseuxTSeries using a set of :math:`\pi = \{\tau\}` data. Parameters ---------- f, x, y : polynomial A plane algebraic curve. x0 : complex The x-center of the Puiseux series expansion. singular_data : list The output of :func:`singular`. t : variable The variable in which the Puiseux t series is represented. """ R = f.parent() x, y = R.gens() extension_polynomial, xpart, ypart = singular_data L = LaurentSeriesRing(ypart.base_ring(), 't') t = L.gen() self.f = f self.t = t self._xpart = xpart self._ypart = ypart # store x-part attributes. handle the centered at infinity case self.x0 = x0 if x0 == infinity: x0 = QQ(0) self.center = x0 # extract and store information about the x-part of the puiseux series xpart = xpart(t, 0) xpartshift = xpart - x0 ramification_index, xcoefficient = xpartshift.laurent_polynomial( ).dict().popitem() self.xcoefficient = xcoefficient self.ramification_index = QQ(ramification_index).numerator() self.xpart = xpart # extract and store information about the y-part of the puiseux series self.ypart = L(ypart(t, 0)) self._initialize_extension(extension_polynomial) # determine the initial order. See the order property val = L(ypart(t, O(t))).prec() self._singular_order = 0 if val == infinity else val self._regular_order = self._p.degree(x) # extend to have at least two elements self.extend(nterms=1) # the curve, x-part, and terms output by puiseux make the puiseux # series unique. any mutability only adds terms self.__parent = self.ypart.parent() self._hash = hash((self.f, self.xpart, self.ypart))
def __init__(self, f, x0, singular_data, order=None): r"""Initialize a PuiseuxTSeries using a set of :math:`\pi = \{\tau\}` data. Parameters ---------- f, x, y : polynomial A plane algebraic curve. x0 : complex The x-center of the Puiseux series expansion. singular_data : list The output of :func:`singular`. t : variable The variable in which the Puiseux t series is represented. """ R = f.parent() x,y = R.gens() extension_polynomial, xpart, ypart = singular_data L = LaurentSeriesRing(ypart.base_ring(), 't') t = L.gen() self.f = f self.t = t self._xpart = xpart self._ypart = ypart # store x-part attributes. handle the centered at infinity case self.x0 = x0 if x0 == infinity: x0 = QQ(0) self.center = x0 # extract and store information about the x-part of the puiseux series xpart = xpart(t,0) xpartshift = xpart - x0 ramification_index, xcoefficient = xpartshift.laurent_polynomial().dict().popitem() self.xcoefficient = xcoefficient self.ramification_index = QQ(ramification_index).numerator() self.xpart = xpart # extract and store information about the y-part of the puiseux series self.ypart = L(ypart(t,0)) self._initialize_extension(extension_polynomial) # determine the initial order. See the order property val = L(ypart(t,O(t))).prec() self._singular_order = 0 if val == infinity else val self._regular_order = self._p.degree(x) # extend to have at least two elements self.extend(nterms=1) # the curve, x-part, and terms output by puiseux make the puiseux # series unique. any mutability only adds terms self.__parent = self.ypart.parent() self._hash = hash((self.f, self.xpart, self.ypart))
def _sa_coefficients_lambda_(K, beta=0): r""" Return the coefficients `\lambda_{k, \ell}(\beta)` used in singularity analysis. INPUT: - ``K`` -- an integer. - ``beta`` -- (default: `0`) the order of the logarithmic singularity. OUTPUT: A dictionary mapping pairs of indices to rationals. .. SEEALSO:: :meth:`~AsymptoticExpansionGenerators.SingularityAnalysis` TESTS:: sage: from sage.rings.asymptotic.asymptotic_expansion_generators \ ....: import _sa_coefficients_lambda_ sage: _sa_coefficients_lambda_(3) {(0, 0): 1, (1, 1): -1, (1, 2): 1/2, (2, 2): 1, (2, 3): -5/6, (2, 4): 1/8, (3, 3): -1, (3, 4): 13/12, (4, 4): 1} sage: _sa_coefficients_lambda_(3, beta=1) {(0, 0): 1, (1, 1): -2, (1, 2): 1/2, (2, 2): 3, (2, 3): -4/3, (2, 4): 1/8, (3, 3): -4, (3, 4): 29/12, (4, 4): 5} """ from sage.rings.laurent_series_ring import LaurentSeriesRing from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ V = LaurentSeriesRing(QQ, names='v', default_prec=K) v = V.gen() T = PowerSeriesRing(V, names='t', default_prec=2*K-1) t = T.gen() S = (t - (1+1/v+beta) * (1+v*t).log()).exp() return dict(((k + L.valuation(), ell), c) for ell, L in enumerate(S.list()) for k, c in enumerate(L.list()))
def local_coordinates_at_infinity(self, prec=20, name='t'): """ For the genus `g` hyperelliptic curve `y^2 = f(x)`, return `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is the local parameter at infinity INPUT: - ``prec`` -- desired precision of the local coordinates - ``name`` -- generator of the power series ring (default: ``t``) OUTPUT: `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x^g/y` is the local parameter at infinity EXAMPLES:: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^5-5*x^2+1) sage: x,y = H.local_coordinates_at_infinity(10) sage: x t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12) sage: y t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12) :: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^3-x+1) sage: x,y = H.local_coordinates_at_infinity(10) sage: x t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12) sage: y t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12) AUTHOR: - Jennifer Balakrishnan (2007-12) """ g = self.genus() pol = self.hyperelliptic_polynomials()[0] K = LaurentSeriesRing(self.base_ring(), name, default_prec=prec + 2) t = K.gen() L = PolynomialRing(K, 'x') x = L.gen() i = 0 w = (x**g / t)**2 - pol wprime = w.derivative(x) if pol.degree() == 2 * g + 1: x = t**-2 else: x = t**-1 for i in range((RR(log(prec + 2) / log(2))).ceil()): x = x - w(x) / wprime(x) y = x**g / t return x + O(t**(prec + 2)), y + O(t**(prec + 2))
def _sa_coefficients_lambda_(K, beta=0): r""" Return the coefficients `\lambda_{k, \ell}(\beta)` used in singularity analysis. INPUT: - ``K`` -- an integer. - ``beta`` -- (default: `0`) the order of the logarithmic singularity. OUTPUT: A dictionary mapping pairs of indices to rationals. .. SEEALSO:: :meth:`~AsymptoticExpansionGenerators.SingularityAnalysis` TESTS:: sage: from sage.rings.asymptotic.asymptotic_expansion_generators \ ....: import _sa_coefficients_lambda_ sage: _sa_coefficients_lambda_(3) {(0, 0): 1, (1, 1): -1, (1, 2): 1/2, (2, 2): 1, (2, 3): -5/6, (2, 4): 1/8, (3, 3): -1, (3, 4): 13/12, (4, 4): 1} sage: _sa_coefficients_lambda_(3, beta=1) {(0, 0): 1, (1, 1): -2, (1, 2): 1/2, (2, 2): 3, (2, 3): -4/3, (2, 4): 1/8, (3, 3): -4, (3, 4): 29/12, (4, 4): 5} """ from sage.rings.laurent_series_ring import LaurentSeriesRing from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ V = LaurentSeriesRing(QQ, names='v', default_prec=K) v = V.gen() T = PowerSeriesRing(V, names='t', default_prec=2 * K - 1) t = T.gen() S = (t - (1 + 1 / v + beta) * (1 + v * t).log()).exp() return dict(((k + L.valuation(), ell), c) for ell, L in enumerate(S.list()) for k, c in enumerate(L.list()))
def local_coordinates_at_infinity(self, prec = 20, name = 't'): """ For the genus `g` hyperelliptic curve `y^2 = f(x)`, return `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is the local parameter at infinity INPUT: - ``prec`` -- desired precision of the local coordinates - ``name`` -- generator of the power series ring (default: ``t``) OUTPUT: `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x^g/y` is the local parameter at infinity EXAMPLES:: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^5-5*x^2+1) sage: x,y = H.local_coordinates_at_infinity(10) sage: x t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12) sage: y t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12) :: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^3-x+1) sage: x,y = H.local_coordinates_at_infinity(10) sage: x t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12) sage: y t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12) AUTHOR: - Jennifer Balakrishnan (2007-12) """ g = self.genus() pol = self.hyperelliptic_polynomials()[0] K = LaurentSeriesRing(self.base_ring(), name, default_prec=prec+2) t = K.gen() L = PolynomialRing(K,'x') x = L.gen() i = 0 w = (x**g/t)**2-pol wprime = w.derivative(x) x = t**-2 for i in range((RR(log(prec+2)/log(2))).ceil()): x = x - w(x)/wprime(x) y = x**g/t return x+O(t**(prec+2)) , y+O(t**(prec+2))
def test_LaurentSeries_V(self): L = LaurentSeriesRing(QQ, 't') t = L.gen() l = 1 * t**(-3) + 2 + 3 * t**1 + 4 * t**2 + 5 * t**9 m = LaurentSeries_V(l, 1) self.assertEqual(l, m) m = LaurentSeries_V(l, 2) self.assertEqual(m.exponents(), [-6, 0, 2, 4, 18]) self.assertEqual(m.coefficients(), [1, 2, 3, 4, 5]) m = LaurentSeries_V(l, -1) self.assertEqual(m.exponents(), [-9, -2, -1, 0, 3]) self.assertEqual(m.coefficients(), [5, 4, 3, 2, 1]) m = LaurentSeries_V(l, -3) self.assertEqual(m.exponents(), [-27, -6, -3, 0, 9]) self.assertEqual(m.coefficients(), [5, 4, 3, 2, 1])
def test_LaurentSeries_V(self): L = LaurentSeriesRing(QQ,'t') t = L.gen() l = 1*t**(-3) + 2 + 3*t**1 + 4*t**2 + 5*t**9 m = LaurentSeries_V(l,1) self.assertEqual(l, m) m = LaurentSeries_V(l, 2) self.assertEqual(m.exponents(), [-6,0,2,4,18]) self.assertEqual(m.coefficients(), [1,2,3,4,5]) m = LaurentSeries_V(l, -1) self.assertEqual(m.exponents(), [-9,-2,-1,0,3]) self.assertEqual(m.coefficients(), [5,4,3,2,1]) m = LaurentSeries_V(l, -3) self.assertEqual(m.exponents(), [-27,-6,-3,0,9]) self.assertEqual(m.coefficients(), [5,4,3,2,1])
def compute_wp_pari(E,prec): r""" Computes the Weierstrass `\wp`-function with the ``ellwp`` function from PARI. EXAMPLES:: sage: E = EllipticCurve([0,1]) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari sage: compute_wp_pari(E, prec=20) z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20) sage: compute_wp_pari(E, prec=30) z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + 3/38548055*z^22 - 4/8364927935*z^28 + O(z^30) """ ep = E._pari_() wpp = ep.ellwp(n=prec) k = E.base_ring() R = LaurentSeriesRing(k,'z') z = R.gen() wp = z**(-2) for i in range(prec): wp += k(wpp[i]) * z**i wp = wp.add_bigoh(prec) return wp
def compute_wp_pari(E, prec): r""" Computes the Weierstrass `\wp`-function with the ``ellwp`` function from PARI. EXAMPLES:: sage: E = EllipticCurve([0,1]) sage: from sage.schemes.elliptic_curves.ell_wp import compute_wp_pari sage: compute_wp_pari(E, prec=20) z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + O(z^20) sage: compute_wp_pari(E, prec=30) z^-2 - 1/7*z^4 + 1/637*z^10 - 1/84721*z^16 + 3/38548055*z^22 - 4/8364927935*z^28 + O(z^30) """ ep = E.__pari__() wpp = ep.ellwp(n=prec) k = E.base_ring() R = LaurentSeriesRing(k, 'z') z = R.gen() wp = z**(-2) for i in range(prec): wp += k(wpp[i]) * z**i wp = wp.add_bigoh(prec) return wp
def coleman(self,t1,t2,E=None,method='moments',mult=False,delta=-1,level=0): r""" If ``self`` is a `p`-adic automorphic form that corresponds to a rigid modular form, then this computes the coleman integral of this form between two points on the boundary `\PP^1(\QQ_p)` of the `p`-adic upper half plane. INPUT: - ``t1``, ``t2`` - elements of `\PP^1(\QQ_p)` (the endpoints of integration) - ``E`` - (Default: None). If specified, will not compute the covering adapted to ``t1`` and ``t2`` and instead use the given one. In that case, ``E`` should be a list of matrices corresponding to edges describing the open balls to be considered. - ``method`` - string (Default: 'moments'). Tells which algorithm to use (alternative is 'riemann_sum', which is unsuitable for computations requiring high precision) - ``mult`` - boolean (Default: False). Whether to use the multiplicative version. - ``delta`` - integer (Default: -1) - ``level`` - integer (Default: 0) OUTPUT: The result of the coleman integral EXAMPLES: This example illustrates ... :: TESTS: :: sage: p = 7 sage: lev = 2 sage: prec = 20 sage: X = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M = HarmonicCocycles(X,k,prec) # optional - magma sage: B = M.basis() # optional - magma sage: f = 3*B[0] # optional - magma sage: MM = pAutomorphicForms(X,k,prec,overconvergent=True) # optional - magma sage: D = -11 # optional - magma sage: X.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = X.get_CM_points(D,prec=prec) # optional - magma sage: Kp = CM[0].parent() # optional - magma sage: P=CM[0] # optional - magma sage: Q=P.trace()-P # optional - magma sage: F=MM.lift(f, verbose = False) # long time optional - magma sage: J0=F.coleman(P,Q,mult=True) # long time optional - magma sage: E=EllipticCurve([1,0,1,4,-6]) # optional - magma sage: T=E.tate_curve(p) # optional - magma sage: xx,yy=getcoords(T,J0,prec) # long time optional -magma sage: P = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); P # long time optional - magma (7/11 : 58/121*a - 9/11 : 1) sage: p = 13 # optional - magma sage: lev = 2 # optional - magma sage: prec = 20 # optional - magma sage: Y = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M=HarmonicCocycles(Y,k,prec) # optional - magma sage: B=M.basis() # optional - magma sage: f = B[1] # optional - magma sage: g = -4*B[0]+3*B[1] # optional - magma sage: MM = pAutomorphicForms(Y,k,prec,overconvergent=True) # optional - magma sage: D = -11 # optional - magma sage: Y.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = Y.get_CM_points(D,prec=prec) # optional - magma sage: Kp = parent(CM[0]) # optional - magma sage: P = CM[0] # optional - magma sage: Q = P.trace()-P # optional - magma sage: F = MM.lift(f, verbose = False) # long time optional - magma sage: J11 = F.coleman(P,Q,mult = True) # long time optional - magma sage: E = EllipticCurve('26a2') # optional - magma sage: T = E.tate_curve(p) # optional - magma sage: xx,yy = getcoords(T,J11,prec) # long time optional - magma sage: HP = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); HP # long time optional - magma (-137/11 : 2/121*a + 63/11 : 1) AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ if(mult and delta>=0): raise NotImplementedError, "Need to figure out how to implement the multiplicative part." p=self._parent._X._p K=t1.parent() R=PolynomialRing(K,'x') x=R.gen() R1=LaurentSeriesRing(K,'r1') r1=R1.gen() if(E is None): E=self._parent._X._BT.find_covering(t1,t2) # print 'Got %s open balls.'%len(E) value=0 ii=0 value_exp=K(1) if(method=='riemann_sum'): R1.set_default_prec(self._parent._U.weight()+1) for e in E: ii+=1 b=e[0,1] d=e[1,1] y=(b-d*t1)/(b-d*t2) poly=R1(y.log()) #R1(our_log(y)) c_e=self.evaluate(e) new=c_e.evaluate(poly) value+=new if mult: value_exp *= K.teichmuller(y)**Integer(c_e[0].rational_reconstruction()) elif(method=='moments'): R1.set_default_prec(self._parent._U.dimension()) for e in E: ii+=1 f=(x-t1)/(x-t2) a,b,c,d=e.list() y0=f(R1([b,a])/R1([d,c])) #f( (ax+b)/(cx+d) ) y0=p**(-y0(0).valuation())*y0 mu=K.teichmuller(y0(0)) y=y0/mu-1 poly=R1(0) ypow=y for jj in range(1,R1.default_prec()+10): poly+=(-1)**(jj+1)*ypow/jj ypow*=y if(delta>=0): poly*=((r1-t1)**delta*(r1-t2)**(self._parent._n-delta)) c_e=self.evaluate(e) new=c_e.evaluate(poly) value+=new if mult: value_exp *= K.teichmuller((b-d*t1)/(b-d*t2))**Integer(c_e[0].rational_reconstruction()) else: print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should not be used in practice.' return False if mult: return value_exp * value.exp() return value
def coleman(self,t1,t2,poly = None, E = None,method = 'moments',mult = False,level = 0, branch = 0): r""" If ``self`` is a `p`-adic automorphic form that corresponds to a rigid modular form, then this computes the coleman integral of this form between two points on the boundary `\PP^1(\QQ_p)` of the `p`-adic upper half plane. INPUT: - ``t1``, ``t2`` - elements of `\PP^1(\QQ_p)` (the endpoints of integration) - ``E`` - (Default: None). If specified, will not compute the covering adapted to ``t1`` and ``t2`` and instead use the given one. In that case, ``E`` should be a list of matrices corresponding to edges describing the open balls to be considered. - ``method`` - string (Default: 'moments'). Tells which algorithm to use (alternative is 'riemann_sum', which is unsuitable for computations requiring high precision) - ``mult`` - boolean (Default: False). Whether to use the multiplicative version. - ``poly`` - polynomial (Default: None) - ``level`` - integer (Default: 0) OUTPUT: The result of the coleman integral EXAMPLES:: sage: p = 7 sage: lev = 2 sage: prec = 20 sage: X = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M = HarmonicCocycles(X,k,prec) # optional - magma sage: B = M.basis() # optional - magma sage: f = 3*M.decomposition()[0].gen(0) # optional - magma sage: MM = pAutomorphicForms(X,k,prec,overconvergent = True) # optional - magma sage: D = -11 # optional - magma sage: X.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = X.get_CM_points(D,prec = prec) # optional - magma sage: P = CM[0] # optional - magma sage: Q = P.trace()-P # optional - magma sage: F = MM.lift(f, verbose = False) # long time optional - magma sage: J0 = F.coleman(P,Q,mult = True) # long time optional - magma sage: E = EllipticCurve([1,0,1,4,-6]) # optional - magma sage: T = E.tate_curve(p) # optional - magma sage: xx,yy = getcoords(T,J0,prec) # long time optional -magma sage: P = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); P # long time optional - magma (7/11 : 58/121*a - 9/11 : 1) sage: p = 13 # optional - magma sage: lev = 2 # optional - magma sage: prec = 20 # optional - magma sage: Y = BTQuotient(p,lev, use_magma = True) # optional - magma sage: k = 2 # optional - magma sage: M = HarmonicCocycles(Y,k,prec) # optional - magma sage: B = M.basis() # optional - magma sage: f = M.decomposition()[1].gen(0) # optional - magma sage: g = M.decomposition()[0].gen(0) # optional - magma sage: MM = pAutomorphicForms(Y,k,prec,overconvergent = True) # optional - magma sage: D = -11 # optional - magma sage: Y.is_admissible(D) # optional - magma True sage: K.<a> = QuadraticField(D) # optional - magma sage: CM = Y.get_CM_points(D,prec = prec) # optional - magma sage: P = CM[0] # optional - magma sage: Q = P.trace()-P # optional - magma sage: F = MM.lift(f, verbose = False) # long time optional - magma sage: J11 = F.coleman(P,Q,mult = True) # long time optional - magma sage: E = EllipticCurve('26a2') # optional - magma sage: T = E.tate_curve(p) # optional - magma sage: xx,yy = getcoords(T,J11,prec) # long time optional - magma sage: HP = E.base_extend(K).lift_x(algdep(xx,1).roots(QQ)[0][0]); HP # long time optional - magma (-137/11 : 2/121*a + 63/11 : 1) AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ p = self.parent().prime() K = t1.parent() if mult: branch = 0 R = PolynomialRing(K,'x') x = R.gen() R1 = LaurentSeriesRing(K,'r1') r1 = R1.gen() if E is None: E = self.parent()._source._BT.find_covering(t1,t2,level) print 'Got %s open balls.'%len(E) value = K(0) ii = 0 value_exp = K(1) wt = self.parent()._U.weight() dim = self.parent()._U.dimension() if(method == 'riemann_sum'): R1.set_default_prec(wt+1) for e in E: ii += 1 b = e[0,1] d = e[1,1] y = (b-d*t1)/(b-d*t2) pol = R1(y.log(branch = branch)) c_e = self.evaluate(e) new = c_e.evaluate(pol) value += new if mult: value_exp *= K.teichmuller(y)**Integer(c_e[0].rational_reconstruction()) elif method == 'moments': R1.set_default_prec(dim) for e in E: ii += 1 f = (x-t1)/(x-t2) a,b,c,d = e.list() y0 = f((a*r1+b)/(c*r1+d)) pol = y0(0).log(branch = branch)+((y0.derivative()/y0).integral()) if poly is not None: pol *= poly(r1) #((r1-t1)**delta*(r1-t2)**(self.parent()._n-delta)) c_e = self.evaluate(e) new = c_e.evaluate(pol) value += new if mult: base = ((b-d*t1)/(b-d*t2)) pwr = ZZ(c_e[0].rational_reconstruction()) value_exp *= base**pwr else: print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should not be used in practice.' return False if mult: a = value_exp.valuation(p) print 'a=',a return p**a*K.teichmuller(p**(-a)*value_exp) * value.exp(prec = 2*dim) +O(p**(dim+a)) return value +O(p**(dim+value.valuation(p)))
def epsinv(F, target, prec=53, target_tol=0.001, z=None, emb=None): """ Compute a bound on the hyperbolic distance. The true minimum will be within the computed bound. It is computed as the inverse of epsilon_F from [HS2018]_. INPUT: - ``F`` -- binary form of degree at least 3 with no multiple roots - ``target`` -- positive real number. The value we want to attain, i.e., the value we are taking the inverse of - ``prec``-- positive integer. precision to use in CC - ``target_tol`` -- positive real number. The tolerance with which we attain the target value. - ``z`` -- complex number. ``z_0`` covariant for F. - ``emb`` -- embedding into CC OUTPUT: a real number delta satisfying target + target_tol > eps_F(delta) > target. EXAMPLES:: sage: from sage.rings.polynomial.binary_form_reduce import epsinv sage: R.<x,y> = QQ[] sage: epsinv(-2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3, 31.5022020249597) # tol 1e-12 4.02520895942207 """ def coshdelta(z): #The cosh of the hyperbolic distance from z = t+uj to j return (z.norm() + 1) / (2 * z.imag()) def RQ(delta): # this is the quotient R(F_0,z)/R(F_0,z(F)) for a generic z # at distance delta from j. See Lemma 4.2 in [HS2018]. cd = cosh(delta).n(prec=prec) sd = sinh(delta).n(prec=prec) return prod( [cd + (cost * phi[0] + sint * phi[1]) * sd for phi in phis]) def epsF(delta): pol = RQ(delta) #get R quotient in terms of z S = PolynomialRing(C, 'v') g = S([(i - d) * pol[i - d] for i in range(2 * d + 1)]) # take derivative drts = [ e for e in g.roots(ring=C, multiplicities=False) if (e.norm() - 1).abs() < 0.1 ] # find min return min([pol(r / r.abs()).real() for r in drts]) C = ComplexField(prec=prec) R = F.parent() d = F.degree() if z is None: z, th = covariant_z0(F, prec=prec, emb=emb) else: #need to do our own input checking if R.ngens() != 2 or any(sum(t) != d for t in F.exponents()): raise TypeError('must be a binary form') if d < 3: raise ValueError('must be at least degree 3') f = F.subs({R.gen(1): 1}).univariate_polynomial() #now we have a single variable polynomial if (max([ex for p,ex in f.roots(ring=C)]) >= QQ(d)/2)\ or (f.degree() < QQ(d)/2): raise ValueError('cannot have root with multiplicity >= deg(F)/2') R = RealField(prec=prec) PR = PolynomialRing(R, 't') t = PR.gen(0) # compute phi_1, ..., phi_k # first find F_0 and its roots # this change of variables on f moves z(f) to j, i.e. produces F_0 rts = f(z.imag() * t + z.real()).roots(ring=C) phis = [] # stereographic projection of roots for r, e in rts: phis.extend( [[2 * r.real() / (r.norm() + 1), (r.norm() - 1) / (r.norm() + 1)]]) if d != f.degree(): # include roots at infinity phis.extend([(d - f.degree()) * [0, 1]]) # for writing RQ in terms of generic z to minimize LC = LaurentSeriesRing(C, 'u', default_prec=2 * d + 2) u = LC.gen(0) cost = (u + u**(-1)) / 2 sint = (u - u**(-1)) / (2 * C.gen(0)) # first find an interval containing the desired value # then use regula falsi on log eps_F # d -> delta value in interval [0,1] # v in value in interval [1,epsF(1)] dl = R(0.0) vl = R(1.0) du = R(1.0) vu = epsF(du) while vu < target: # compute the next value of epsF for delta = 2*delta dl = du vl = vu du *= 2 vu = epsF(du) # now dl < delta <= du logt = target.log() l2 = (vu.log() - logt).n(prec=prec) l1 = (vl.log() - logt).n(prec=prec) dn = (dl * l2 - du * l1) / (l2 - l1) vn = epsF(dn) dl = du vl = vu du = dn vu = vn while (du - dl).abs() >= target_tol or max(vl, vu) < target: l2 = (vu.log() - logt).n(prec=prec) l1 = (vl.log() - logt).n(prec=prec) dn = (dl * l2 - du * l1) / (l2 - l1) vn = epsF(dn) dl = du vl = vu du = dn vu = vn return max(dl, du)