def riemann_sum(self,f,center=1,level=0,E=None): r""" This function evaluates the integral of the funtion ``f`` with respect to the measure determined by ``self``. EXAMPLES: This example illustrates ... :: """ R1=LaurentSeriesRing(f.base_ring(),'r1') R1.set_default_prec(self._parent._k-1) R2=PolynomialRing(f.base_ring(),'r2') if E is None: E=self._parent._X._BT.get_balls(center,level) else: E=self._parent._X._BT.subdivide(E,level) value=0 ii=0 for e in E: ii+=1 exp=R1([e[1,1],e[1,0]])**(self._parent._k-2)*e.determinant()**(-(self._parent._k-2)/2)*f(R1([e[0,1],e[0,0]])/R1([e[1,1],e[1,0]])).truncate(self._parent._k-1) new=self.evaluate(e).l_act_by(e.inverse()).evaluate(exp) value+=new return value
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 integrate(self,f,center=1,level=0,method='moments'): r""" Calculate .. MATH:: \int_{\PP^1(\QQ_p)} f(x)d\mu(x) were `\mu` is the measure associated to ``self``. INPUT: - ``f`` - An analytic function. - ``center`` - 2x2 matrix over Qp (default: 1) - ``level`` - integer (default: 0) - ``method`` - string (default: 'moments'). Which method of integration to use. Either 'moments' or 'riemann_sum'. EXAMPLES: :: AUTHORS: - Marc Masdeu (2012-02-20) - Cameron Franc (2012-02-20) """ E=self._parent._X._BT.get_balls(center,level) R1=LaurentSeriesRing(f.base_ring(),'r1') R2=PolynomialRing(f.base_ring(),'r2') value=0 ii=0 if(method=='riemann_sum'): R1.set_default_prec(self._parent._U.weight()+1) for e in E: ii+=1 #print ii,"/",len(E) exp=((R1([e[1,1],e[1,0]]))**(self._parent._U.weight())*e.determinant()**(-(self._parent._U.weight())/2))*f(R1([e[0,1],e[0,0]])/R1([e[1,1],e[1,0]])) #exp=R2([tmp[jj] for jj in range(self._parent._k-1)]) new=self.evaluate(e).evaluate(exp.truncate(self._parent._U.weight()+1)) value+=new elif(method=='moments'): R1.set_default_prec(self._parent._U.dimension()) for e in E: ii+=1 #print ii,"/",len(E) tmp=((R2([e[1,1],e[1,0]]))**(self._parent._U.weight())*e.determinant()**(-(self._parent._U.weight())/2))*f(R2([e[0,1],e[0,0]])/R2([e[1,1],e[1,0]])) exp=R1(tmp.numerator())/R1(tmp.denominator()) new=self.evaluate(e).evaluate(exp) value+=new else: print 'The available methods are either "moments" or "riemann_sum". The latter is only provided for consistency check, and should never be used.' return False return value
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 __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 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 series(self, n): """ Return the Laurent power series associated with the CFiniteSequence, with precision `n`. INPUT: - ``n`` -- a nonnegative integer EXAMPLES:: sage: r = CFiniteSequence.from_recurrence([-1,2],[0,1]) sage: s = r.series(4); s x + 2*x^2 + 3*x^3 + 4*x^4 + O(x^5) sage: type(s) <type 'sage.rings.laurent_series_ring_element.LaurentSeries'> """ R = LaurentSeriesRing(QQ, 'x') R.set_default_prec(n) return R(self.ogf())
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 __init__(self, base_ring, name=None, default_prec=None, sparse=False, category=None): CommutativeRing.__init__(self, base_ring, names=name, category=getattr(self, '_default_category', Fields())) # If self is R(( x^(1/e) )) then the corresponding Laurent series # ring will be R(( x )) self._laurent_series_ring = LaurentSeriesRing( base_ring, name=name, default_prec=default_prec, sparse=sparse)
def linear_relation(self, List, Psi, verbose=True, prec=None): for Phi in List: assert Phi.valuation() >= 0, "Symbols must be integral" assert Psi.valuation() >= 0 R = self.base() Rbase = R.base() w = R.gen() d = len(List) if d == 0: if Psi.is_zero(): return [None, R(1)] else: return [None, 0] if prec is None: M, var_prec = Psi.precision_absolute() else: M, var_prec = prec p = self.prime() V = R**d RSR = LaurentSeriesRing(Rbase, R.variable_name()) VSR = RSR**self.source().ngens() List_TMs = [VSR(Phi.list_of_total_measures()) for Phi in List] Psi_TMs = VSR(Psi.list_of_total_measures()) A = Matrix(RSR, List_TMs).transpose() try: sol = V([vv.power_series() for vv in A.solve_right(Psi_TMs)]) except ValueError: #try "least squares" if verbose: print "Trying least squares." sol = (A.transpose() * A).solve_right(A.transpose() * Psi_TMs) #check precision (could make this better, checking each power of w) p_prec = M diff = Psi_TMs - sum([sol[i] * List_TMs[i] for i in range(len(List_TMs))]) for i in diff: for j in i.list(): if p_prec > j.valuation(): p_prec = j.valuation() if verbose: print "p-adic precision is now", p_prec #Is this right? sol = V([R([j.add_bigoh(p_prec) for j in i.list()]) for i in sol]) return [sol, R(-1)]
def series(self, n): """ Return the Laurent power series associated with the CFiniteSequence, with precision `n`. INPUT: - `n` -- a nonnegative integer EXAMPLES:: sage: C.<x> = CFiniteSequences(QQ) sage: r = C.from_recurrence([-1,2],[0,1]) sage: s = r.series(4); s x + 2*x^2 + 3*x^3 + 4*x^4 + O(x^5) sage: type(s) <class 'sage.rings.laurent_series_ring_element.LaurentSeries'> """ R = LaurentSeriesRing(QQ, 'x', default_prec=n) return R(self.ogf())
def completion(self, p, prec=20, extras=None): """ EXAMPLES:: sage: P.<x>=LaurentPolynomialRing(QQ) sage: P Univariate Laurent Polynomial Ring in x over Rational Field sage: PP=P.completion(x) sage: PP Laurent Series Ring in x over Rational Field sage: f=1-1/x sage: PP(f) -x^-1 + 1 sage: 1/PP(f) -x - x^2 - x^3 - x^4 - x^5 - x^6 - x^7 - x^8 - x^9 - x^10 - x^11 - x^12 - x^13 - x^14 - x^15 - x^16 - x^17 - x^18 - x^19 - x^20 + O(x^21) """ if str(p) == self._names[0] and self._n == 1: from sage.rings.laurent_series_ring import LaurentSeriesRing return LaurentSeriesRing(self.base_ring(), name=self._names[0]) else: raise TypeError("Cannot complete %s with respect to %s" % (self, p))
def __init__(self, ogf, *args, **kwargs): """ Create a C-finite sequence given its ordinary generating function. INPUT: - ``ogf`` -- the ordinary generating function, a fraction of polynomials over the rationals OUTPUT: - A CFiniteSequence object EXAMPLES:: sage: R.<x> = QQ[] sage: CFiniteSequence((2-x)/(1-x-x^2)) # the Lucas sequence C-finite sequence, generated by (-x + 2)/(-x^2 - x + 1) sage: CFiniteSequence(x/(1-x)^3) # triangular numbers C-finite sequence, generated by x/(-x^3 + 3*x^2 - 3*x + 1) Polynomials are interpreted as finite sequences, or recurrences of degree 0:: sage: CFiniteSequence(x^2-4*x^5) Finite sequence [1, 0, 0, -4], offset = 2 sage: CFiniteSequence(1) Finite sequence [1], offset = 0 This implementation allows any polynomial fraction as o.g.f. by interpreting any power of `x` dividing the o.g.f. numerator or denominator as a right or left shift of the sequence offset:: sage: CFiniteSequence(x^2+3/x) Finite sequence [3, 0, 0, 1], offset = -1 sage: CFiniteSequence(1/x+4/x^3) Finite sequence [4, 0, 1], offset = -3 sage: P = LaurentPolynomialRing(QQ.fraction_field(), 'X') sage: X=P.gen() sage: CFiniteSequence(1/(1-X)) C-finite sequence, generated by 1/(-x + 1) The o.g.f. is always normalized to get a denominator constant coefficient of `+1`:: sage: CFiniteSequence(1/(x-2)) C-finite sequence, generated by -1/2/(-1/2*x + 1) TESTS:: sage: P.<x> = QQ[] sage: CFiniteSequence(0.1/(1-x)) Traceback (most recent call last): ... ValueError: O.g.f. base not rational. sage: P.<x,y> = QQ[] sage: CFiniteSequence(x*y) Traceback (most recent call last): ... NotImplementedError: Multidimensional o.g.f. not implemented. """ self._br = ogf.base_ring() if (self._br <> QQ) and (self._br <> ZZ) and not is_FiniteField(self._br): raise ValueError('O.g.f. base not proper.') P = PolynomialRing(self._br, 'x') if ogf in QQ: ogf = P(ogf) if hasattr(ogf,'numerator'): try: num = P(ogf.numerator()) den = P(ogf.denominator()) except TypeError: if ogf.numerator().parent().ngens() > 1: raise NotImplementedError('Multidimensional o.g.f. not implemented.') else: raise ValueError('Numerator and denominator must be polynomials.') else: num = P(ogf) den = 1 # Transform the ogf numerator and denominator to canonical form # to get the correct offset, degree, and recurrence coeffs and # start values. self._off = 0 self._deg = 0 if isinstance (ogf, FractionFieldElement) and den == 1: ogf = num # case p(x)/1: fall through if isinstance (ogf, (FractionFieldElement, FpTElement)): x = P.gen() if num.constant_coefficient() == 0: self._off = num.valuation() num = P(num / x**self._off) elif den.constant_coefficient() == 0: self._off = -den.valuation() den = P(den * x**self._off) f = den.constant_coefficient() num = P(num / f) den = P(den / f) f = gcd(num, den) num = P(num / f) den = P(den / f) self._deg = den.degree() self._c = [-den.list()[i] for i in range(1, self._deg + 1)] if self._off >= 0: num = x**self._off * num else: den = x**(-self._off) * den # determine start values (may be different from _get_item_ values) R = LaurentSeriesRing(self._br, 'x') rem = num % den alen = max(self._deg, num.degree() + 1) R.set_default_prec (alen) if den <> 1: self._a = R(num/(den+O(x**alen))).list() self._aa = R(rem/(den+O(x**alen))).list()[:self._deg] # needed for _get_item_ else: self._a = num.list() if len(self._a) < alen: self._a.extend([0] * (alen - len(self._a))) super(CFiniteSequence, self).__init__(P.fraction_field(), num, den, *args, **kwargs) elif ogf.parent().is_integral_domain(): super(CFiniteSequence, self).__init__(ogf.parent().fraction_field(), P(ogf), 1, *args, **kwargs) self._c = [] self._off = P(ogf).valuation() if ogf == 0: self._a = [0] else: self._a = ogf.parent()((ogf / (ogf.parent().gen())**self._off)).list() else: raise ValueError("Cannot convert a " + str(type(ogf)) + " to CFiniteSequence.")
def S(P, m): PP = P.parent() from sage.rings.laurent_series_ring import LaurentSeriesRing LS = LaurentSeriesRing(PP.base_ring(), name='z', default_prec=m) irP = 1 / LS(P.reverse()) return PP(irP.list())
def __init__(self, parent, ogf): r""" Initialize the C-Finite sequence. The ``__init__`` method can only be called by the :class:`CFiniteSequences` class. By Default, a class call reaches the ``__classcall_private__`` which first creates a proper parent and then call the ``__init__``. INPUT: - ``ogf`` -- the ordinary generating function, a fraction of polynomials over the rationals - ``parent`` -- the parent of the C-Finite sequence, an occurrence of :class:`CFiniteSequences` OUTPUT: - A CFiniteSequence object TESTS:: sage: C.<x> = CFiniteSequences(QQ) sage: C((2-x)/(1-x-x^2)) # indirect doctest C-finite sequence, generated by (x - 2)/(x^2 + x - 1) """ br = parent.base_ring() ogf = parent.fraction_field()(ogf) P = parent.polynomial_ring() num = ogf.numerator() den = ogf.denominator() FieldElement.__init__(self, parent) if den == 1: self._c = [] self._off = num.valuation() self._deg = 0 if ogf == 0: self._a = [0] else: self._a = num.shift(-self._off).list() else: # Transform the ogf numerator and denominator to canonical form # to get the correct offset, degree, and recurrence coeffs and # start values. self._off = 0 self._deg = 0 if num.constant_coefficient() == 0: self._off = num.valuation() num = num.shift(-self._off) elif den.constant_coefficient() == 0: self._off = -den.valuation() den = den.shift(self._off) f = den.constant_coefficient() num = P(num / f) den = P(den / f) f = num.gcd(den) num = P(num / f) den = P(den / f) self._deg = den.degree() self._c = [-den[i] for i in range(1, self._deg + 1)] if self._off >= 0: num = num.shift(self._off) else: den = den.shift(-self._off) # determine start values (may be different from _get_item_ values) alen = max(self._deg, num.degree() + 1) R = LaurentSeriesRing(br, parent.variable_name(), default_prec=alen) rem = num % den if den != 1: self._a = R(num / den).list() self._aa = R(rem / den).list()[:self._deg] # needed for _get_item_ else: self._a = num.list() if len(self._a) < alen: self._a.extend([0] * (alen - len(self._a))) ogf = num / den self._ogf = ogf
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)