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 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 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 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 __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.")