def __call__(self, x): r""" Evaluate this character at an element of `\ZZ_p^\times`. EXAMPLES:: sage: kappa = pAdicWeightSpace(23)(1 + 23^2 + O(23^20), 4, False) sage: kappa(2) 16 + 7*23 + 7*23^2 + 16*23^3 + 23^4 + 20*23^5 + 15*23^7 + 11*23^8 + 12*23^9 + 8*23^10 + 22*23^11 + 16*23^12 + 13*23^13 + 4*23^14 + 19*23^15 + 6*23^16 + 7*23^17 + 11*23^19 + O(23^20) sage: kappa(-1) 1 + O(23^20) sage: kappa(23) 0 sage: kappa(2 + 2*23 + 11*23^2 + O(23^3)) 16 + 7*23 + O(23^3) """ if not isinstance(x, pAdicGenericElement): x = Qp(self._p)(x) if x.valuation() != 0: return 0 teich = x.parent().teichmuller(x, x.precision_absolute()) xx = x / teich if (xx - 1).valuation() <= 0: raise ArithmeticError verbose("Normalised element is %s" % xx) e = xx.log() / self.parent()._param.log() verbose("Exponent is %s" % e) return teich**(self.t) * (self.w.log() * e).exp()
def __call__(self, x): r""" Evaluate this character at an element of `\ZZ_p^\times`. EXAMPLES:: sage: kappa = pAdicWeightSpace(23)(1 + 23^2 + O(23^20), 4, False) sage: kappa(2) 16 + 7*23 + 7*23^2 + 16*23^3 + 23^4 + 20*23^5 + 15*23^7 + 11*23^8 + 12*23^9 + 8*23^10 + 22*23^11 + 16*23^12 + 13*23^13 + 4*23^14 + 19*23^15 + 6*23^16 + 7*23^17 + 11*23^19 + O(23^20) sage: kappa(-1) 1 + O(23^20) sage: kappa(23) 0 sage: kappa(2 + 2*23 + 11*23^2 + O(23^3)) 16 + 7*23 + O(23^3) """ if not isinstance(x, pAdicGenericElement): x = Qp(self._p)(x) if x.valuation() != 0: return 0 teich = x.parent().teichmuller(x) xx = x / teich if (xx - 1).valuation() <= 0: raise ArithmeticError verbose("Normalised element is %s" % xx) e = xx.log() / self.parent()._param.log() verbose("Exponent is %s" % e) return teich**(self.t) * (self.w.log() * e).exp()
def embed_order(self, p, K, prec, outfile=None, return_all=False): r''' ''' from .limits import find_the_unit_of verbose('Computing quadratic embedding to precision %s' % prec) verbose('Finding module generators') w = module_generators(K)[1] verbose('Done') w_minpoly = w.minpoly().change_ring(Qp(p, prec)) Cp = Qp(p, prec).extension(w_minpoly, names='g') wl = w.list() assert len(wl) == 2 r0 = -wl[0] / wl[1] r1 = 1 / wl[1] assert r0 + r1 * w == K.gen() padic_Kgen = Cp(r0) + Cp(r1) * Cp.gen() try: fwrite( '# d_K = %s, h_K = %s, h_K^- = %s' % (K.discriminant(), K.class_number(), len( K.narrow_class_group())), outfile) except NotImplementedError: pass fwrite('# w_K satisfies: %s' % w.minpoly(), outfile) ##### uk = find_the_unit_of(self.F, K) tu = uk.trace() verb_level = get_verbose() set_verbose(0) for g in self.enumerate_elements(): if g.trace() == tu: gamma = self(g) a, b, c, d = gamma.quaternion_rep.list() rt_list = our_sqrt((d - a)**2 + 4 * b * c, Cp, return_all=True) tau1, tau2 = [(Cp(a - d) + rt) / Cp(2 * c) for rt in rt_list] assert (Cp(c) * tau1**2 + Cp(d - a) * tau1 - Cp(b)) == 0 assert (Cp(c) * tau2**2 + Cp(d - a) * tau2 - Cp(b)) == 0 r, s = uk.coordinates_in_terms_of_powers()(K.gen()) assert r + s * uk == K.gen() assert uk.charpoly() == gamma.quaternion_rep.charpoly() mtx = r + s * gamma.quaternion_rep if mtx.denominator() == 1: break set_verbose(verb_level) emb = K.hom([mtx]) mu = emb(w) fwrite('# \cO_K to R_0 given by w_K |-> %s' % mu, outfile) fwrite('# gamma_psi = %s' % gamma, outfile) fwrite('# tau_psi = %s' % tau1, outfile) fwrite('# (where g satisfies: %s)' % w.minpoly(), outfile) if return_all: return gamma, tau1, tau2 else: return gamma, tau1
def embed_order(self,p,K,prec,outfile = None, return_all = False): r''' ''' from limits import find_the_unit_of verbose('Computing quadratic embedding to precision %s'%prec) verbose('Finding module generators') w = module_generators(K)[1] verbose('Done') w_minpoly = w.minpoly().change_ring(Qp(p,prec)) Cp = Qp(p,prec).extension(w_minpoly,names = 'g') wl = w.list() assert len(wl) == 2 r0 = -wl[0]/wl[1] r1 = 1/wl[1] assert r0 + r1 * w == K.gen() padic_Kgen = Cp(r0)+Cp(r1)*Cp.gen() try: fwrite('# d_K = %s, h_K = %s, h_K^- = %s'%(K.discriminant(),K.class_number(),len(K.narrow_class_group())),outfile) except NotImplementedError: pass fwrite('# w_K satisfies: %s'%w.minpoly(),outfile) ##### uk = find_the_unit_of(self.F,K) tu = uk.trace() verb_level = get_verbose() set_verbose(0) for g in self.enumerate_elements(): if g.trace() == tu: gamma = self(g) a,b,c,d = gamma.quaternion_rep.list() rt_list = our_sqrt((d-a)**2 + 4*b*c,Cp,return_all=True) tau1, tau2 = [(Cp(a-d) + rt)/Cp(2*c) for rt in rt_list] assert (Cp(c)*tau1**2 + Cp(d-a)*tau1-Cp(b)) == 0 assert (Cp(c)*tau2**2 + Cp(d-a)*tau2-Cp(b)) == 0 r,s = uk.coordinates_in_terms_of_powers()(K.gen()) assert r+s*uk == K.gen() assert uk.charpoly() == gamma.quaternion_rep.charpoly() mtx = r + s*gamma.quaternion_rep if mtx.denominator() == 1: break set_verbose(verb_level) emb = K.hom([mtx]) mu = emb(w) fwrite('# \cO_K to R_0 given by w_K |-> %s'%mu,outfile) fwrite('# gamma_psi = %s'%gamma,outfile) fwrite('# tau_psi = %s'%tau1,outfile) fwrite('# (where g satisfies: %s)'%w.minpoly(),outfile) if return_all: return gamma, tau1, tau2 else: return gamma, tau1
def WeightSpace_constructor(p, base_ring=None): r""" Construct the p-adic weight space for the given prime p. A `p`-adic weight is a continuous character `\ZZ_p^\times \to \CC_p^\times`. These are the `\CC_p`-points of a rigid space over `\QQ_p`, which is isomorphic to a disjoint union of copies (indexed by `(\ZZ/p\ZZ)^\times`) of the open unit `p`-adic disc. Note that the "base ring" of a `p`-adic weight is the smallest ring containing the image of `\ZZ`; in particular, although the default base ring is `\QQ_p`, base ring `\QQ` will also work. EXAMPLES:: sage: pAdicWeightSpace(3) # indirect doctest Space of 3-adic weight-characters defined over '3-adic Field with capped relative precision 20' sage: pAdicWeightSpace(3, QQ) Space of 3-adic weight-characters defined over 'Rational Field' sage: pAdicWeightSpace(10) Traceback (most recent call last): ... ValueError: p must be prime """ if base_ring is None: base_ring = Qp(p) if (p, base_ring) in _wscache: m = _wscache[(p, base_ring)]() if m is not None: return m m = WeightSpace_class(p, base_ring) _wscache[(p, base_ring)] = weakref.ref(m) return m
def embed(self, q, prec): if prec is None: return None elif prec == -1: prec = self._prec if self.F == QQ and self.discriminant == 1: return set_immutable(q.change_ring(Qp(self.p, prec))) else: try: q = q.coefficient_tuple() except AttributeError: pass I, J, K = self.local_splitting(prec) f = self._F_to_local return set_immutable((f(q[0]) + f(q[1]) * I + f(q[2]) * J + f(q[3]) * K).change_ring(Qp(self.p, prec)))
def __init__(self,X,k,prec=None,basis_matrix=None,base_field=None): self._k=k self._X=X self._E=self._X.get_edge_list() self._V=self._X.get_vertex_list() if prec is None: self._prec=None if base_field is None: try: self._R= X.get_splitting_field() except AttributeError: raise ValueError, "It looks like you are not using Magma as backend...and still we don't know how to compute splittings in that case!" else: pol=X.get_splitting_field().defining_polynomial().factor()[0][0] self._R=base_field.extension(pol,pol.variable_name()).absolute_field(name='r') self._U=OCVn(self._k-2,self._R) else: self._prec=prec if base_field is None: self._R=Qp(self._X._p,prec=prec) else: self._R=base_field self._U=OCVn(self._k-2,self._R,self._k-1) self.__rank = self._X.dimension_harmonic_cocycles(self._k) if basis_matrix is not None: self.__matrix=basis_matrix self.__matrix.set_immutable() assert self.__rank == self.__matrix.nrows() AmbientHeckeModule.__init__(self, self._R, self.__rank, self._X.prime()*self._X.Nplus()*self._X.Nminus(), weight=self._k) self._populate_coercion_lists_()
def my_algdep(z,n,prec = None): K = z.parent() p = K.prime() z = p**(-z.valuation(p))*z zpows = [K(1)] for ii in range(n): zpows.append(zpows[ii]*z) if prec is None: prec = z.precision_absolute() field_deg = K.degree() M = matrix(Qp(p,prec),field_deg,n+1) for ii in range(field_deg): for jj in range(n+1): M[ii,jj]=O(p^prec) for jj in range(n+1): V = zpows[jj]._ntl_rep().list() for ii in range(len(V)): M[ii,jj]+= ZZ(V[ii])+O(p^prec) argmax = None vmax = -1 Rx = PolynomialRing(QQ,names = 'x') x = Rx.gens()[0] for ii in range(field_deg): lincomb = gp.lindep(M.row(ii).list()) lincomb = Rx([lincomb[ii+1].sage() for ii in range(n+1)]) newval = lincomb.subs(z).valuation() if newval > vmax: argmax = lincomb vmax = newval print vmax return argmax
def __init__(self,X,U,prec=None,t=None,R=None,overconvergent=False): if(R is None): if(not isinstance(U,Integer)): self._R=U.base_ring() else: if(prec is None): prec=100 self._R=Qp(X._p,prec) else: self._R=R #U is a CoefficientModuleSpace if(isinstance(U,Integer)): if(t is None): if(overconvergent): t=prec-U+1 else: t=0 self._U=OCVn(U-2,self._R,U-1+t) else: self._U=U self._X=X self._V=self._X.get_vertex_list() self._E=self._X.get_edge_list() self._prec=self._R.precision_cap() self._n=self._U.weight() Module.__init__(self,base=self._R) self._populate_coercion_lists_()
def get_embedding(self, prec): r""" Returns an embedding of the quaternion algebra into the algebra of 2x2 matrices with coefficients in `\QQ_p`. INPUT: - prec -- Integer. The precision of the splitting. """ if prec == -1: prec = self._prec if self.F == QQ and self.discriminant == 1: R = Qp(self.p, prec) self._F_to_local = QQ.hom([R(1)]) def iota(q): return q.change_ring(R) if prec > self._prec: # DEBUG self._prec = prec else: I, J, K = self.local_splitting(prec) mats = [1, I, J, K] def iota(q): R = I.parent() try: q = q.coefficient_tuple() except AttributeError: q = q.list() return sum(self._F_to_local(a) * b for a, b in zip(q, mats)) return iota
def _compute_padic_splitting(self, prec): verbose('Entering compute_padic_splitting') prime = self.p if self.seed is not None: self.magma.eval('SetSeed(%s)' % self.seed) R = Qp(prime, prec + 10) #Zmod(prime**prec) # B_magma = self.Gpn._get_B_magma() a, b = self.Gpn.B.invariants() if self._hardcode_matrices: self._II = matrix(R, 2, 2, [1, 0, 0, -1]) self._JJ = matrix(R, 2, 2, [0, 1, 1, 0]) goodroot = self.F.gen().minpoly().change_ring(R).roots()[0][0] self._F_to_local = self.F.hom([goodroot]) else: verbose('Calling magma pMatrixRing') if self.F == QQ: _, f = self.magma.pMatrixRing(self.Gpn._Omax_magma, prime * self.Gpn._Omax_magma.BaseRing(), Precision=20, nvals=2) self._F_to_local = QQ.hom([R(1)]) else: _, f = self.magma.pMatrixRing(self.Gpn._Omax_magma, sage_F_ideal_to_magma( self.Gpn._F_magma, self.ideal_p), Precision=20, nvals=2) try: self._goodroot = R( f.Image(B_magma( B_magma.BaseRing().gen(1))).Vector()[1]._sage_()) except SyntaxError: raise SyntaxError( "Magma has trouble finding local splitting") self._F_to_local = None for o, _ in self.F.gen().minpoly().change_ring(R).roots(): if (o - self._goodroot).valuation() > 5: self._F_to_local = self.F.hom([o]) break assert self._F_to_local is not None verbose('Initializing II,JJ,KK') v = f.Image(B_magma.gen(1)).Vector() self._II = matrix(R, 2, 2, [v[i + 1]._sage_() for i in xrange(4)]) v = f.Image(B_magma.gen(2)).Vector() self._JJ = matrix(R, 2, 2, [v[i + 1]._sage_() for i in xrange(4)]) v = f.Image(B_magma.gen(3)).Vector() self._KK = matrix(R, 2, 2, [v[i + 1]._sage_() for i in xrange(4)]) self._II, self._JJ = lift_padic_splitting(self._F_to_local(a), self._F_to_local(b), self._II, self._JJ, prime, prec) self.Gn._F_to_local = self._F_to_local if not self.use_shapiro(): self.Gpn._F_to_local = self._F_to_local self._KK = self._II * self._JJ self._prec = prec return self._II, self._JJ, self._KK
def __init__(self,domain,U,prec = None,t = None,R = None,overconvergent = False): if(R is None): if not isinstance(U,Integer): self._R = U.base_ring() else: if prec is None: prec = 20 self._R = Qp(domain._p,prec) else: self._R = R #U is a CoefficientModuleSpace if isinstance(U,Integer): if t is None: if overconvergent: t = prec-U+1 else: t = 0 self._U = OCVn(U-2,self._R,U-1+t) else: self._U = U self._source = domain self._list = self._source.get_list() # Contains also the opposite edges self._prec = self._R.precision_cap() self._n = self._U.weight() self._p = self._source._p Module.__init__(self,base = self._R) self._populate_coercion_lists_()
def embed_matrix(self, q, prec): if prec is None: return None elif prec == -1: prec = self._prec if self.F == QQ and self.discriminant == 1: return set_immutable(q.change_ring(Qp(self.p, prec))) else: return q.apply_map(self._F_to_local)
def tate_parameter(E, p, prec = 20, R = None): if R is None: R = Qp(p,prec) jE = E.j_invariant() E4 = EisensteinForms(weight=4).basis()[0] Delta = CuspForms(weight=12).basis()[0] j = (E4.q_expansion(prec+3))**3/Delta.q_expansion(prec+3) jinv = (1/j).power_series() q_in_terms_of_jinv = jinv.reversion() return q_in_terms_of_jinv(R(1/E.j_invariant()))
def embed(self, q, prec): if prec is None: return None elif prec == -1: prec = self._prec if self.F == QQ and self.discriminant == 1: return set_immutable(q.change_ring(Qp(self.p, prec))) else: if hasattr(q, 'rows'): return q.apply_map(self._F_to_local) try: return self.Gn.quaternion_to_matrix(q).apply_map( self._F_to_local) except AttributeError: pass try: q = q.coefficient_tuple() except AttributeError: q = q.list() I, J, K = self.local_splitting(prec) f = self._F_to_local return set_immutable((f(q[0]) + f(q[1]) * I + f(q[2]) * J + f(q[3]) * K).change_ring(Qp(self.p, prec)))
def __init__(self, p, base_ring): r""" Initialisation function. EXAMPLES:: sage: pAdicWeightSpace(17) Space of 17-adic weight-characters defined over '17-adic Field with capped relative precision 20' """ ParentWithBase.__init__(self, base=base_ring) p = ZZ(p) if not p.is_prime(): raise ValueError("p must be prime") self._p = p self._param = Qp(p)((p == 2 and 5) or (p + 1))
class HarmonicCocycles(AmbientHeckeModule): Element=HarmonicCocycleElement r""" This object represents a space of Gamma invariant harmonic cocycles valued in a cofficient module. INPUT: - ``X`` - A BTQuotient object - ``k`` - integer - The weight. - ``prec`` - integer (Default: None). If specified, the precision for the coefficient module - ``basis_matrix`` - integer (Default: None) - ``base_field`` - (Default: None) EXAMPLES: :: AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu """ def __init__(self,X,k,prec=None,basis_matrix=None,base_field=None): self._k=k self._X=X self._E=self._X.get_edge_list() self._V=self._X.get_vertex_list() if prec is None: self._prec=None if base_field is None: try: self._R= X.get_splitting_field() except AttributeError: raise ValueError, "It looks like you are not using Magma as backend...and still we don't know how to compute splittings in that case!" else: pol=X.get_splitting_field().defining_polynomial().factor()[0][0] self._R=base_field.extension(pol,pol.variable_name()).absolute_field(name='r') self._U=OCVn(self._k-2,self._R) else: self._prec=prec if base_field is None: self._R=Qp(self._X._p,prec=prec) else: self._R=base_field self._U=OCVn(self._k-2,self._R,self._k-1) self.__rank = self._X.dimension_harmonic_cocycles(self._k) if basis_matrix is not None: self.__matrix=basis_matrix self.__matrix.set_immutable() assert self.__rank == self.__matrix.nrows() AmbientHeckeModule.__init__(self, self._R, self.__rank, self._X.prime()*self._X.Nplus()*self._X.Nminus(), weight=self._k) self._populate_coercion_lists_() def base_extend(self,base_ring): r""" This function extends the base ring of the coefficient module. INPUT: - ``base_ring`` - a ring that has a coerce map from the current base ring EXAMPLES: :: """ if not base_ring.has_coerce_map_from(self.base_ring()): raise ValueError, "No coercion defined" else: return self.change_ring(base_ring) def change_ring(self, new_base_ring): r""" This function changes the base ring of the coefficient module. INPUT: - ``new_base_ring'' - a ring that has a coerce map from the current base ring EXAMPLES: :: """ if not new_base_ring.has_coerce_map_from(self.base_ring()): raise ValueError, "No coercion defined" else: return self.__class__(self._X,self._k,prec=self._prec,basis_matrix=self.basis_matrix().change_ring(base_ring),base_field=new_base_ring) def rank(self): r""" The rank (dimension) of ``self``. EXAMPLES: :: """ return self.__rank def submodule(self,v,check=False): r""" Return the submodule of ``self`` spanned by ``v``. EXAMPLES: """ return HarmonicCocyclesSubmodule(self,v,dual=None,check=check) def is_simple(self): r""" Whether ``self`` is irreducible. EXAMPLES: :: """ return self.rank()==1 def _repr_(self): r""" This returns the representation of self as a string. """ return 'Space of harmonic cocycles of weight %s on %s'%(self._k,self._X) def _latex_(self): r""" A LaTeX representation of ``self``. EXAMPLES: :: """ s='\\text{Space of harmonic cocycles of weight }'+latex(self._k)+'\\text{ on }'+latex(self._X) return s def _an_element_(self): r""" """ return self.basis()[0] def _coerce_map_from_(self, S): r""" Can coerce from other HarmonicCocycles or from pAutomorphicForms """ if isinstance(S,(HarmonicCocycles,pAutomorphicForms)): if(S._k!=self._k): return False if(S._X!=self._X): return False return True return False def __cmp__(self,other): r""" """ try: res=(self.base_ring()==other.base_ring() and self._X==other._X and self._k==other._k) return res except: return False def _element_constructor_(self,x): r""" """ #Code how to coherce x into the space #Admissible values of x? if isinstance(x,HarmonicCocycleElement): return HarmonicCocycleElement(self,x) elif isinstance(x,pAutomorphicForm): tmp=[self._U.element_class(_parent._U,x._F[ii]).l_act_by(self._E[ii].rep) for ii in range(self._nE)] return HarmonicCocycleElement(self,tmp,from_values=True) else: return HarmonicCocycleElement(self,x) def free_module(self): r""" This function returns the underlying free module EXAMPLES: :: """ try: return self.__free_module except AttributeError: pass V = self.base_ring()**self.dimension() self.__free_module = V return V def character(self): r""" Only implemented the trivial character so far. EXAMPLES: """ return lambda x:x def embed_quaternion(self,g): r""" Embed the quaternion element ``g`` into the matrix algebra. EXAMPLES: :: """ return self._X.embed_quaternion(g,exact = self._R.is_exact(), prec = self._prec) def basis_matrix(self): r""" Returns a basis of ``self`` in matrix form. If the coefficient module `M` is of finite rank then the space of Gamma invariant `M` valued harmonic cocycles can be represented as a subspace of the finite rank space of all functions from the finitely many edges in the corresponding BTQuotient into `M`. This function computes this representation of the space of cocycles. OUTPUT: A basis matrix describing the cocycles in the spaced of all `M` valued Gamma invariant functions on the tree. EXAMPLES: :: sage: X = BTQuotient(3,19) sage: C = HarmonicCocycles(X,4,prec = 5) sage: B = C.basis() Traceback (most recent call last): ... RuntimeError: The computed dimension does not agree with the expectation. Consider increasing precision! We try increasing the precision: :: sage: C = HarmonicCocycles(X,4,prec = 20) sage: B = C.basis() sage: len(B) == X.dimension_harmonic_cocycles(4) True AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ try: return self.__matrix except AttributeError: pass nV=len(self._V) nE=len(self._E) stab_conds=[] S=self._X.get_edge_stabs() p=self._X._p d=self._k-1 for e in self._E: try: g=filter(lambda g:g[2],S[e.label])[0] C=self._U.l_matrix_representation(self.embed_quaternion(g[0])) C-=self._U.l_matrix_representation(Matrix(QQ,2,2,p**g[1])) stab_conds.append([e.label,C]) except IndexError: pass n_stab_conds=len(stab_conds) self._M=Matrix(self._R,(nV+n_stab_conds)*d,nE*d,0,sparse=True) for v in self._V: for e in filter(lambda e:e.parity==0,v.leaving_edges): C=sum([self._U.l_matrix_representation(self.embed_quaternion(x[0])) for x in e.links],Matrix(self._R,d,d,0)) self._M.set_block(v.label*d,e.label*d,C) for e in filter(lambda e:e.parity==0,v.entering_edges): C=sum([self._U.l_matrix_representation(self.embed_quaternion(x[0])) for x in e.opposite.links],Matrix(self._R,d,d,0)) self._M.set_block(v.label*d,e.opposite.label*d,C) for kk in range(n_stab_conds): v=stab_conds[kk] self._M.set_block((nV+kk)*d,v[0]*d,v[1]) x1=self._M.right_kernel().matrix() if x1.nrows() != self.rank(): raise RuntimeError, 'The computed dimension does not agree with the expectation. Consider increasing precision!' K=[c for c in x1.rows()] if not self._R.is_exact(): for ii in range(len(K)): s=min([t.valuation() for t in K[ii]]) for jj in range(len(K[ii])): K[ii][jj]=(p**(-s))*K[ii][jj] self.__matrix=Matrix(self._R,len(K),nE*d,K) self.__matrix.set_immutable() return self.__matrix def __apply_atkin_lehner(self,q,f): r""" This function applies an Atkin-Lehner involution to a harmonic cocycle INPUT: - ``q`` - an integer dividing the full level p*Nminus*Nplus - ``f`` - a harmonic cocycle OUTPUT: The harmonic cocycle obtained by hitting f with the Atkin-Lehner at q EXAMPLES: :: """ R=self._R Data=self._X._get_atkin_lehner_data(q) p=self._X._p tmp=[self._U.element_class(self._U,zero_matrix(self._R,self._k-1,1),quick=True) for jj in range(len(self._E))] d1=Data[1] mga=self.embed_quaternion(Data[0]) for jj in range(len(self._E)): t=d1[jj] tmp[jj]+=(t.sign()*f._F[t.label]).l_act_by(p**(-t.power)*mga*t.igamma(self.embed_quaternion)) return HarmonicCocycleElement(self,tmp,from_values=True) def __apply_hecke_operator(self,l,f): r""" This function applies a Hecke operator to a harmonic cocycle. INPUT: - ``l`` - an integer - ``f`` - a harmonic cocycle OUTPUT: A harmonic cocycle which is the result of applying the lth Hecke operator to f EXAMPLES: :: """ R=self._R HeckeData,alpha=self._X._get_hecke_data(l) if(self.level()%l==0): factor=QQ(l**(Integer((self._k-2)/2))/(l+1)) else: factor=QQ(l**(Integer((self._k-2)/2))) p=self._X._p alphamat=self.embed_quaternion(alpha) tmp=[self._U.element_class(self._U,zero_matrix(self._R,self._k-1,1),quick=True) for jj in range(len(self._E))] for ii in range(len(HeckeData)): d1=HeckeData[ii][1] mga=self.embed_quaternion(HeckeData[ii][0])*alphamat for jj in range(len(self._E)): t=d1[jj] tmp[jj]+=(t.sign()*f._F[t.label]).l_act_by(p**(-t.power)*mga*t.igamma(self.embed_quaternion)) return HarmonicCocycleElement(self,[factor*x for x in tmp],from_values=True) def _compute_atkin_lehner_matrix(self,d): r""" When the underlying coefficient module is finite, this function computes the matrix of an Atkin-Lehner involution in the basis provided by the function basis_matrix INPUT: - ``d`` - an integer dividing p*Nminus*Nplus OUTPUT: The matrix of the AL-involution at d in the basis given by self.basis_matrix EXAMPLES: :: """ res=self.__compute_operator_matrix(lambda f:self.__apply_atkin_lehner(d,f)) return res def _compute_hecke_matrix_prime(self,l): r""" When the underlying coefficient module is finite, this function computes the matrix of a (prime) Hecke operator in the basis provided by the function basis_matrix INPUT: - ``l`` - an integer prime OUTPUT: The matrix of T_l acting on the cocycles in the basis given by self.basis_matrix EXAMPLES: :: """ res=self.__compute_operator_matrix(lambda f:self.__apply_hecke_operator(l,f)) return res def __compute_operator_matrix(self,T): r""" Compute the matrix of the operator ``T``. EXAMPLES: :: """ R=self._R A=self.basis_matrix().transpose() basis=self.basis() B=zero_matrix(R,len(self._E)*(self._k-1),self.dimension()) for rr in range(len(basis)): g=T(basis[rr]) B.set_block(0,rr,Matrix(R,len(self._E)*(self._k-1),1,[g._F[e]._val[ii,0] for e in range(len(self._E)) for ii in range(self._k-1) ])) try: res=(A.solve_right(B)).transpose() res.set_immutable() return res except ValueError: print A print B raise ValueError
class pAutomorphicForms(Module): Element=pAutomorphicForm r""" The module of (quaternionic) `p`-adic automorphic forms. EXAMPLES: :: AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ def __init__(self,X,U,prec=None,t=None,R=None,overconvergent=False): if(R is None): if(not isinstance(U,Integer)): self._R=U.base_ring() else: if(prec is None): prec=100 self._R=Qp(X._p,prec) else: self._R=R #U is a CoefficientModuleSpace if(isinstance(U,Integer)): if(t is None): if(overconvergent): t=prec-U+1 else: t=0 self._U=OCVn(U-2,self._R,U-1+t) else: self._U=U self._X=X self._V=self._X.get_vertex_list() self._E=self._X.get_edge_list() self._prec=self._R.precision_cap() self._n=self._U.weight() Module.__init__(self,base=self._R) self._populate_coercion_lists_() def _repr_(self): r""" This returns the representation of self as a string. EXAMPLES: This example illustrates ... :: """ s='Space of automorphic forms on '+str(self._X)+' with values in '+str(self._U) return s def _coerce_map_from_(self, S): r""" Can coerce from other HarmonicCocycles or from pAutomorphicForms """ if(isinstance(S,HarmonicCocycles)): if(S._k-2!=self._n): return False if(S._X!=self._X): return False return True if(isinstance(S,pAutomorphicForms)): if(S._n!=self._n): return False if(S._X!=self._X): return False return True return False def _element_constructor_(self,x): r""" """ #Code how to coherce x into the space #Admissible values of x? if isinstance(x,(HarmonicCocycleElement,pAutomorphicForm)): return pAutomorphicForm(self,x) def _an_element_(self): r""" Returns an element of the module. """ return pAutomorphicForm(self,1) def embed_quaternion(self,g): r""" Returns the image of ``g`` under the embedding of the quaternion algebra into 2x2 matrices. """ return self._X.embed_quaternion(g,prec = self._prec) def lift(self,f, verbose = True): r""" Lifts the harmonic cocycle ``f`` to an overconvegent automorphic form, thus computing all the moments. """ F=self.element_class(self,f) F.improve(verbose = verbose) return F def _apply_Up_operator(self,f,scale=False, fix_lowdeg_terms = True): r""" Apply the Up operator to ``f``. EXAMPLES: :: sage: X = BTQuotient(3,11) sage: M = HarmonicCocycles(X,4,30) sage: A = pAutomorphicForms(X,4,10, overconvergent = True) sage: F = A.lift(M.basis()[0], verbose = False); F p-adic automorphic form on Space of automorphic forms on Quotient of the Bruhat T**s tree of GL_2(QQ_3) with discriminant 11 and level 1 with values in Overconvergent coefficient module of weight n=2 over the ring 3-adic Field with capped relative precision 10 and depth 10: e | c(e) 0 | 3^2 + O(3^12) + O(3^32)*z + O(3^26)*z^2 + (2*3^2 + 3^3 + 2*3^5 + 3^7 + 3^8 + 2*3^9 + O(3^10))*z^3 + (2*3^5 + 2*3^6 + 2*3^7 + 3^9 + O(3^10))*z^4 + (3^2 + 3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 3^7 + 2*3^8 + 3^9 + O(3^10))*z^5 + (3^2 + 2*3^3 + 3^4 + 2*3^6 + O(3^10))*z^6 + (2*3^3 + 3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 3^8 + 3^9 + O(3^10))*z^7 + (3^2 + 3^3 + 2*3^6 + 3^7 + 3^8 + 3^9 + O(3^10))*z^8 + (2*3^2 + 2*3^3 + 2*3^5 + 2*3^7 + 3^8 + 2*3^9 + O(3^10))*z^9 1 | 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12) + (3^2 + O(3^12))*z + (2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12))*z^2 + (2*3^2 + 2*3^3 + 3^4 + 2*3^5 + 3^6 + 2*3^7 + 2*3^8 + O(3^10))*z^3 + (2*3^3 + 3^5 + 3^7 + 3^8 + O(3^10))*z^4 + (2*3^3 + 3^6 + 3^7 + 3^9 + O(3^10))*z^5 + (3^3 + 2*3^4 + 2*3^5 + 2*3^7 + 3^8 + 3^9 + O(3^10))*z^6 + (3^7 + 2*3^8 + 2*3^9 + O(3^10))*z^7 + (3^3 + 2*3^4 + 3^7 + O(3^10))*z^8 + (2*3^2 + 3^4 + 3^6 + 2*3^7 + 3^8 + 2*3^9 + O(3^10))*z^9 2 | 3^2 + 2*3^3 + 2*3^6 + 3^7 + 2*3^8 + O(3^12) + (3 + 2*3^2 + 2*3^3 + 3^5 + 2*3^6 + 3^7 + 3^10 + O(3^11))*z + (2*3 + 2*3^2 + 3^4 + 2*3^5 + 2*3^6 + 2*3^8 + 3^10 + O(3^11))*z^2 + (2*3 + 3^2 + 2*3^7 + 3^9 + O(3^10))*z^3 + (3 + 2*3^2 + 2*3^4 + 3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + O(3^10))*z^4 + (3 + 3^2 + 3^4 + 2*3^9 + O(3^10))*z^5 + (3^3 + 2*3^5 + 3^6 + 3^8 + 2*3^9 + O(3^10))*z^6 + (3^5 + 2*3^7 + 3^9 + O(3^10))*z^7 + (2*3 + 3^3 + 3^4 + 2*3^6 + O(3^10))*z^8 + (2*3 + 2*3^3 + 2*3^4 + 2*3^6 + O(3^10))*z^9 3 | 3^2 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12) + (3^3 + 2*3^4 + 2*3^8 + O(3^13))*z + (3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 3^7 + 2*3^8 + 2*3^9 + 2*3^10 + O(3^11))*z^2 + (3^2 + 2*3^3 + 3^4 + 3^7 + 3^8 + 2*3^9 + O(3^10))*z^3 + (3 + 2*3^2 + 2*3^3 + 3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 3^8 + O(3^10))*z^4 + (3 + 3^3 + 3^4 + 2*3^5 + 2*3^6 + 3^7 + 2*3^8 + 2*3^9 + O(3^10))*z^5 + (3 + 3^4 + 3^5 + 3^6 + 2*3^7 + O(3^10))*z^6 + (2*3 + 3^2 + 2*3^3 + 3^4 + 2*3^6 + 3^8 + 3^9 + O(3^10))*z^7 + (3 + 3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 3^7 + 2*3^9 + O(3^10))*z^8 + (2*3^2 + 3^4 + 3^5 + 3^8 + 3^9 + O(3^10))*z^9 """ HeckeData=self._X._get_Up_data() if scale == False: factor=(self._X._p)**(self._U.weight()/2) else: factor=1 Tf=[] for jj in range(2*len(self._E)): tmp=self._U(0) for d in HeckeData: gg=d[0] # acter u=d[1][jj] # edge_list[jj] r=self._X._p**(-(u.power))*(u.t()*gg) tmp+=f._F[u.label+u.parity*len(self._E)].r_act_by(r) tmp *= factor for ii in range(self._n+1): tmp[ii] = f._F[jj][ii] Tf.append(tmp) return pAutomorphicForm(self,Tf,quick=True)
def simplify(self, x, error=None, force=False, size_heuristic_bound=32): r""" Return a simplified version of ``x``. Produce an element which differs from ``x`` by an element of valuation strictly greater than the valuation of ``x`` (or strictly greater than ``error`` if set.) INPUT: - ``x`` -- an element in the domain of this valuation - ``error`` -- a rational, infinity, or ``None`` (default: ``None``), the error allowed to introduce through the simplification - ``force`` -- ignored - ``size_heuristic_bound` -- when ``force`` is not set, the expected factor by which the ``x`` need to shrink to perform an actual simplification (default: 32) EXAMPLES:: sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone sage: v = pAdicValuation(ZZ, 2) sage: v.simplify(6, force=True) 2 sage: v.simplify(6, error=0, force=True) 0 """ if not force and self._relative_size(x) <= size_heuristic_bound: return x x = self.domain().coerce(x) v = self(x) if error is None: error = v from sage.rings.all import infinity if error is infinity: return x if error < v: return self.domain().zero() from sage.rings.all import QQ error = QQ(error).ceil() from sage.rings.all import Qp precision_ring = Qp(self.p(), error + 1 - v) reduced = precision_ring(x) if error - v >= 5: # If there is not much relative precision left, it is better to # just go with the integer/rational lift. The rational # reconstruction is likely not smaller. try: reconstruction = reduced.rational_reconstruction() if reconstruction in self.domain(): return self.domain()(reconstruction) except ArithmeticError:pass return self.domain()(reduced.lift())
class pAutomorphicForms(Module): Element = pAutomorphicFormElement r""" The module of (quaternionic) `p`-adic automorphic forms. EXAMPLES:: AUTHORS: - Cameron Franc (2012-02-20) - Marc Masdeu (2012-02-20) """ def __init__(self,domain,U,prec = None,t = None,R = None,overconvergent = False): if(R is None): if not isinstance(U,Integer): self._R = U.base_ring() else: if prec is None: prec = 20 self._R = Qp(domain._p,prec) else: self._R = R #U is a CoefficientModuleSpace if isinstance(U,Integer): if t is None: if overconvergent: t = prec-U+1 else: t = 0 self._U = OCVn(U-2,self._R,U-1+t) else: self._U = U self._source = domain self._list = self._source.get_list() # Contains also the opposite edges self._prec = self._R.precision_cap() self._n = self._U.weight() self._p = self._source._p Module.__init__(self,base = self._R) self._populate_coercion_lists_() def prime(self): return self._p def _repr_(self): r""" This returns the representation of self as a string. EXAMPLES:: """ s = 'Space of automorphic forms on '+str(self._source)+' with values in '+str(self._U) return s def _coerce_map_from_(self, S): r""" Can coerce from other HarmonicCocycles or from pAutomorphicForms """ if isinstance(S,HarmonicCocycles): if S.weight()-2 != self._n: return False if S._source != self._source: return False return True if isinstance(S,pAutomorphicForms): if S._n != self._n: return False if S._source != self._source: return False return True return False def _element_constructor_(self,x): r""" """ #Code how to coherce x into the space #Admissible values of x? if isinstance(x,(HarmonicCocycleElement,pAutomorphicFormElement)): return pAutomorphicFormElement(self,x) def _an_element_(self): r""" Returns an element of the module. """ return pAutomorphicFormElement(self,1) def lift(self,f, verbose = True): r""" Lifts the harmonic cocycle ``f`` to an overconvegent automorphic form, thus computing all the moments. """ F = self.element_class(self,f) F.improve(verbose = verbose) return F def _make_invariant(self, F): r""" EXAMPLES:: """ S = self._source.get_stabilizers() M = [e.rep for e in self._list] coeff_module_class = self._U.element_class newF = [] for ii in range(len(S)): Si = S[ii] x = coeff_module_class(F[ii].parent(),F[ii]._val,quick = True) if(any([v[2] for v in Si])): newFi = coeff_module_class(F[ii].parent(),0) s = QQ(0) m = M[ii] for v in Si: s += 1 # self._source should has a embed method that, given stabilizers, # returns 2x2 matrices that can act on the distributions. newFi += x.r_act_by(m.adjoint()*self._source.embed(v[0],prec = self._prec)*m) newF.append((1/s)*newFi) else: newF.append(x) return newF def _apply_Up_operator(self,f,scale = False): r""" Apply the Up operator to ``f``. EXAMPLES:: sage: X = BTQuotient(3,11) sage: M = HarmonicCocycles(X,4,20) sage: A = pAutomorphicForms(X,4,10, overconvergent = True) sage: F = A.lift(M.basis()[0], verbose = False) sage: print F.values() [3^2 + O(3^12) + O(3^22)*z + O(3^16)*z^2 + (2*3^2 + O(3^10))*z^3 + (3^4 + O(3^10))*z^4 + (3^2 + 3^3 + O(3^10))*z^5 + (3^2 + 2*3^3 + 2*3^4 + O(3^10))*z^6 + (2*3^3 + O(3^10))*z^7 + (3^2 + 3^3 + 2*3^4 + 3^5 + O(3^10))*z^8 + (2*3^2 + 2*3^3 + O(3^10))*z^9, 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12) + (3^2 + O(3^12))*z + (2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12))*z^2 + (2*3^2 + 3^4 + 3^6 + 3^8 + O(3^10))*z^3 + (3^4 + 2*3^5 + 2*3^6 + 3^8 + 2*3^9 + O(3^10))*z^4 + (3^3 + 2*3^4 + 2*3^7 + 3^8 + O(3^10))*z^5 + (2*3^4 + 2*3^6 + 3^7 + 3^8 + 2*3^9 + O(3^10))*z^6 + (3^3 + 2*3^4 + 2*3^5 + 2*3^6 + 3^9 + O(3^10))*z^7 + (2*3^4 + 3^7 + O(3^10))*z^8 + (2*3^2 + 3^6 + 2*3^7 + 2*3^8 + O(3^10))*z^9, 3^2 + 2*3^3 + 2*3^6 + 3^7 + 2*3^8 + O(3^12) + (3 + 2*3^2 + 2*3^3 + 3^5 + 2*3^6 + 3^7 + 3^10 + O(3^11))*z + (2*3 + 2*3^2 + 3^4 + 2*3^5 + 2*3^6 + 2*3^8 + 3^10 + O(3^11))*z^2 + (2*3 + 3^2 + 3^4 + 3^5 + 2*3^7 + 2*3^8 + O(3^10))*z^3 + (3 + 2*3^2 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + O(3^10))*z^4 + (3 + 3^2 + 3^4 + 2*3^5 + 2*3^6 + 3^7 + 2*3^8 + 3^9 + O(3^10))*z^5 + (3^3 + 3^4 + 3^7 + O(3^10))*z^6 + (2*3^4 + 3^5 + 3^6 + 2*3^9 + O(3^10))*z^7 + (2*3 + 3^3 + 3^5 + 3^6 + 3^7 + 3^8 + 3^9 + O(3^10))*z^8 + (2*3 + 2*3^3 + 2*3^4 + 2*3^5 + 3^8 + 2*3^9 + O(3^10))*z^9, 3^2 + 2*3^4 + 2*3^5 + 2*3^6 + 2*3^7 + 2*3^8 + 2*3^9 + 2*3^10 + 2*3^11 + O(3^12) + (3^3 + 2*3^4 + 2*3^8 + O(3^12))*z + (3 + 3^2 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 3^7 + 2*3^8 + 2*3^9 + O(3^10))*z^2 + (3^2 + 2*3^3 + 3^4 + 3^5 + 2*3^8 + 3^9 + O(3^10))*z^3 + (3 + 2*3^2 + 2*3^3 + 3^4 + 2*3^5 + 2*3^9 + O(3^10))*z^4 + (3 + 3^3 + 2*3^4 + 2*3^5 + 2*3^7 + 3^8 + 3^9 + O(3^10))*z^5 + (3 + 3^4 + 3^5 + 2*3^6 + 3^7 + 2*3^8 + 3^9 + O(3^10))*z^6 + (2*3 + 3^2 + 2*3^3 + 2*3^5 + 3^7 + 3^8 + 3^9 + O(3^10))*z^7 + (3 + 3^3 + 2*3^4 + 2*3^5 + 3^6 + 3^7 + 3^9 + O(3^10))*z^8 + (2*3^2 + 3^4 + 2*3^5 + 2*3^6 + 3^7 + 2*3^8 + O(3^10))*z^9] """ HeckeData = self._source._get_Up_data() if scale == False: factor = (self._p)**(self._n/2) else: factor = 1 Tf = [] for jj in range(len(self._list)): tmp = self._U(0) for d in HeckeData: gg = d[0] # acter u = d[1][jj] # edge_list[jj] r = self._p**(-u.power) * (u.t(2*self._prec+1)*gg) tmp += f._value[u.label].r_act_by(r) tmp *= factor for ii in range(self._n+1): tmp[ii] = f._value[jj][ii] Tf.append(tmp) return pAutomorphicFormElement(self,Tf,quick = True)
def darmon_point(P, E, beta, prec, ramification_at_infinity=None, input_data=None, magma=None, working_prec=None, recognize_point=True, **kwargs): r''' EXAMPLES: We first need to import the module:: sage: from darmonpoints.darmonpoints import darmon_point A first example (Stark--Heegner point):: sage: from darmonpoints.darmonpoints import darmon_point sage: darmon_point(7,EllipticCurve('35a1'),41,20, cohomological=False, use_magma=False, use_ps_dists = True) Starting computation of the Darmon point ... (-70*alpha + 449 : 2100*alpha - 13444 : 1) A quaternionic (Greenberg) point:: sage: darmon_point(13,EllipticCurve('78a1'),5,20) # long time # optional - magma A Darmon point over a cubic (1,1) field:: sage: F.<r> = NumberField(x^3 - x^2 - x + 2) sage: E = EllipticCurve([-r -1, -r, -r - 1,-r - 1, 0]) sage: N = E.conductor() sage: P = F.ideal(r^2 - 2*r - 1) sage: beta = -3*r^2 + 9*r - 6 sage: darmon_point(P,E,beta,20) # long time # optional - magma ''' # global G, Coh, phiE, Phi, dK, J, J1, cycleGn, nn, Jlist config = ConfigParser.ConfigParser() config.read('config.ini') param_dict = config_section_map(config, 'General') param_dict.update(config_section_map(config, 'DarmonPoint')) param_dict.update(kwargs) param = Bunch(**param_dict) # Get general parameters outfile = param.get('outfile') use_ps_dists = param.get('use_ps_dists', False) use_shapiro = param.get('use_shapiro', False) use_sage_db = param.get('use_sage_db', False) magma_seed = param.get('magma_seed', 1515316) parallelize = param.get('parallelize', False) Up_method = param.get('up_method', 'naive') use_magma = param.get('use_magma', True) progress_bar = param.get('progress_bar', True) sign_at_infinity = param.get('sign_at_infinity', ZZ(1)) # Get darmon_point specific parameters idx_orientation = param.get('idx_orientation') idx_embedding = param.get('idx_embedding', 0) algorithm = param.get('algorithm') quaternionic = param.get('quaternionic') cohomological = param.get('cohomological', True) if Up_method == "bigmatrix" and use_shapiro == True: import warnings warnings.warn( 'Use of "bigmatrix" for Up iteration is incompatible with Shapiro Lemma trick. Using "naive" method for Up.' ) Up_method = 'naive' if working_prec is None: working_prec = max([2 * prec + 10, 30]) if use_magma: page_path = os.path.dirname(__file__) + '/KleinianGroups-1.0/klngpspec' if magma is None: from sage.interfaces.magma import Magma magma = Magma() quit_when_done = True else: quit_when_done = False magma.attach_spec(page_path) else: quit_when_done = False sys.setrecursionlimit(10**6) F = E.base_ring() beta = F(beta) DB, Np, Ncartan = get_heegner_params(P, E, beta) if quaternionic is None: quaternionic = (DB != 1) if cohomological is None: cohomological = quaternionic if quaternionic and not cohomological: raise ValueError( "Need cohomological algorithm when dealing with quaternions") if use_ps_dists is None: use_ps_dists = False if cohomological else True try: p = ZZ(P) except TypeError: p = ZZ(P.norm()) if not p.is_prime(): raise ValueError('P (= %s) should be a prime, of inertia degree 1' % P) if F == QQ: dK = ZZ(beta) extra_conductor_sq = dK / fundamental_discriminant(dK) assert ZZ(extra_conductor_sq).is_square() extra_conductor = extra_conductor_sq.sqrt() dK = dK / extra_conductor_sq assert dK == fundamental_discriminant(dK) if dK % 4 == 0: dK = ZZ(dK / 4) beta = dK else: dK = beta # Compute the completion of K at p x = QQ['x'].gen() K = F.extension(x * x - dK, names='alpha') if F == QQ: dK = K.discriminant() else: dK = K.relative_discriminant() hK = K.class_number() sgninfty = 'plus' if sign_at_infinity == 1 else 'minus' if hasattr(E, 'cremona_label'): Ename = E.cremona_label() elif hasattr(E, 'ainvs'): Ename = E.ainvs() else: Ename = 'unknown' fname = 'moments_%s_%s_%s_%s.sobj' % (P, Ename, sgninfty, prec) if use_sage_db: print("Moments will be stored in database as %s" % (fname)) if outfile == 'log': outfile = '%s_%s_%s_%s_%s_%s.log' % ( P, Ename, dK, sgninfty, prec, datetime.datetime.now().strftime("%Y%m%d-%H%M%S")) outfile = outfile.replace('/', 'div') outfile = '/tmp/darmonpoint_' + outfile fwrite("Starting computation of the Darmon point", outfile) fwrite('D_B = %s %s' % (DB, factor(DB)), outfile) fwrite('Np = %s' % Np, outfile) if Ncartan is not None: fwrite('Ncartan = %s' % Ncartan, outfile) fwrite('dK = %s (class number = %s)' % (dK, hK), outfile) fwrite('Calculation with p = %s and prec = %s' % (P, prec), outfile) fwrite('Elliptic curve %s: %s' % (Ename, E), outfile) if outfile is not None: print("Partial results will be saved in %s" % outfile) if input_data is None: if cohomological: # Define the S-arithmetic group if F != QQ and ramification_at_infinity is None: if F.signature()[0] > 1: if F.signature()[1] == 1: ramification_at_infinity = F.real_places( prec=Infinity) # Totally 'definite' else: raise ValueError( 'Please specify the ramification at infinity') elif F.signature()[0] == 1: if len(F.ideal(DB).factor()) % 2 == 0: ramification_at_infinity = [] # Split at infinity else: ramification_at_infinity = F.real_places( prec=Infinity) # Ramified at infinity else: ramification_at_infinity = None if F == QQ: abtuple = QuaternionAlgebra(DB).invariants() else: abtuple = quaternion_algebra_invariants_from_ramification( F, DB, ramification_at_infinity, magma=magma) G = BigArithGroup(P, abtuple, Np, base=F, outfile=outfile, seed=magma_seed, use_sage_db=use_sage_db, magma=magma, use_shapiro=use_shapiro, nscartan=Ncartan) # Define the cycle ( in H_1(G,Div^0 Hp) ) Coh = ArithCoh(G) while True: try: cycleGn, nn, ell = construct_homology_cycle( p, G.Gn, beta, working_prec, lambda q: Coh.hecke_matrix(q).minpoly(), outfile=outfile, elliptic_curve=E) break except PrecisionError: working_prec *= 2 verbose( 'Encountered precision error, trying with higher precision (= %s)' % working_prec) except ValueError: fwrite( 'ValueError occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) if quit_when_done: magma.quit() return G except AssertionError as e: fwrite( 'Assertion occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) fwrite('%s' % str(e), outfile) if quit_when_done: magma.quit() return G eisenstein_constant = -ZZ(E.reduction(ell).count_points()) fwrite( 'r = %s, so a_r(E) - r - 1 = %s' % (ell, eisenstein_constant), outfile) fwrite('exponent = %s' % nn, outfile) phiE = Coh.get_cocycle_from_elliptic_curve(E, sign=sign_at_infinity) if hasattr(E, 'ap'): sign_ap = E.ap(P) else: try: sign_ap = ZZ(P.norm() + 1 - E.reduction(P).count_points()) except ValueError: sign_ap = ZZ(P.norm() + 1 - Curve(E).change_ring( P.residue_field()).count_points(1)[0]) Phi = get_overconvergent_class_quaternionic( P, phiE, G, prec, sign_at_infinity, sign_ap, use_ps_dists=use_ps_dists, use_sage_db=use_sage_db, parallelize=parallelize, method=Up_method, progress_bar=progress_bar, Ename=Ename) # Integration with moments tot_time = walltime() J = integrate_H1(G, cycleGn, Phi, 1, method='moments', prec=working_prec, parallelize=parallelize, twist=True, progress_bar=progress_bar) verbose('integration tot_time = %s' % walltime(tot_time)) if use_sage_db: G.save_to_db() else: # not cohomological nn = 1 eisenstein_constant = 1 if algorithm is None: if Np == 1: algorithm = 'darmon_pollack' else: algorithm = 'guitart_masdeu' w = K.maximal_order().ring_generators()[0] r0, r1 = w.coordinates_in_terms_of_powers()(K.gen()) QQp = Qp(p, working_prec) Cp = QQp.extension(w.minpoly().change_ring(QQp), names='g') v0 = K.hom([r0 + r1 * Cp.gen()]) # Optimal embeddings of level one fwrite("Computing optimal embeddings of level one...", outfile) Wlist = find_optimal_embeddings(K, use_magma=use_magma, extra_conductor=extra_conductor) fwrite("Found %s such embeddings." % len(Wlist), outfile) if idx_embedding is not None: if idx_embedding >= len(Wlist): fwrite( 'There are not enough embeddings. Taking the index modulo %s' % len(Wlist), outfile) idx_embedding = idx_embedding % len(Wlist) fwrite('Taking only embedding number %s' % (idx_embedding), outfile) Wlist = [Wlist[idx_embedding]] # Find the orientations orients = K.maximal_order().ring_generators()[0].minpoly().roots( Zmod(Np), multiplicities=False) fwrite("Possible orientations: %s" % orients, outfile) if len(Wlist) == 1 or idx_orientation == -1: fwrite("Using all orientations, since hK = 1", outfile) chosen_orientation = None else: fwrite("Using orientation = %s" % orients[idx_orientation], outfile) chosen_orientation = orients[idx_orientation] emblist = [] for i, W in enumerate(Wlist): tau, gtau, sign, limits = find_tau0_and_gtau( v0, Np, W, algorithm=algorithm, orientation=chosen_orientation, extra_conductor=extra_conductor) fwrite( 'n_evals = %s' % sum( (num_evals(t1, t2) for t1, t2 in limits)), outfile) emblist.append((tau, gtau, sign, limits)) # Get the cohomology class from E Phi = get_overconvergent_class_matrices(P, E, prec, sign_at_infinity, use_ps_dists=use_ps_dists, use_sage_db=use_sage_db, parallelize=parallelize, progress_bar=progress_bar) J = 1 Jlist = [] for i, emb in enumerate(emblist): fwrite( "Computing %s-th period, attached to the embedding: %s" % (i, Wlist[i].list()), outfile) tau, gtau, sign, limits = emb n_evals = sum((num_evals(t1, t2) for t1, t2 in limits)) fwrite( "Computing one period...(total of %s evaluations)" % n_evals, outfile) newJ = prod((double_integral_zero_infty(Phi, t1, t2) for t1, t2 in limits))**ZZ(sign) Jlist.append(newJ) J *= newJ else: # input_data is not None Phi, J = input_data[1:3] fwrite('Integral done. Now trying to recognize the point', outfile) fwrite('J_psi = %s' % J, outfile) fwrite('g belongs to %s' % J.parent(), outfile) #Try to recognize a generator if quaternionic: local_embedding = G.base_ring_local_embedding(working_prec) twopowlist = [ 4, 3, 2, 1, QQ(1) / 2, QQ(3) / 2, QQ(1) / 3, QQ(2) / 3, QQ(1) / 4, QQ(3) / 4, QQ(5) / 2, QQ(4) / 3 ] else: local_embedding = Qp(p, working_prec) twopowlist = [ 4, 3, 2, 1, QQ(1) / 2, QQ(3) / 2, QQ(1) / 3, QQ(2) / 3, QQ(1) / 4, QQ(3) / 4, QQ(5) / 2, QQ(4) / 3 ] known_multiple = QQ( nn * eisenstein_constant ) # It seems that we are not getting it with present algorithm. while known_multiple % p == 0: known_multiple = ZZ(known_multiple / p) if not recognize_point: fwrite('known_multiple = %s' % known_multiple, outfile) if quit_when_done: magma.quit() return J, Jlist candidate, twopow, J1 = recognize_J(E, J, K, local_embedding=local_embedding, known_multiple=known_multiple, twopowlist=twopowlist, prec=prec, outfile=outfile) if candidate is not None: HCF = K.hilbert_class_field(names='r1') if hK > 1 else K if hK == 1: try: verbose('candidate = %s' % candidate) Ptsmall = E.change_ring(HCF)(candidate) fwrite('twopow = %s' % twopow, outfile) fwrite( 'Computed point: %s * %s * %s' % (twopow, known_multiple, Ptsmall), outfile) fwrite('(first factor is not understood, second factor is)', outfile) fwrite( '(r satisfies %s = 0)' % (Ptsmall[0].parent().gen().minpoly()), outfile) fwrite('================================================', outfile) if quit_when_done: magma.quit() return Ptsmall except (TypeError, ValueError): verbose("Could not recognize the point.") else: verbose('candidate = %s' % candidate) fwrite('twopow = %s' % twopow, outfile) fwrite( 'Computed point: %s * %s * (x,y)' % (twopow, known_multiple), outfile) fwrite('(first factor is not understood, second factor is)', outfile) try: pols = [HCF(c).relative_minpoly() for c in candidate[:2]] except AttributeError: pols = [HCF(c).minpoly() for c in candidate[:2]] fwrite('Where x satisfies %s' % pols[0], outfile) fwrite('and y satisfies %s' % pols[1], outfile) fwrite('================================================', outfile) if quit_when_done: magma.quit() return candidate else: fwrite('================================================', outfile) if quit_when_done: magma.quit() return []
def darmon_point(P, E, beta, prec, ramification_at_infinity = None, input_data = None, magma = None, working_prec = None, **kwargs): r''' EXAMPLES: We first need to import the module:: sage: from darmonpoints.darmonpoints import darmon_point A first example (Stark--Heegner point):: sage: from darmonpoints.darmonpoints import darmon_point sage: darmon_point(7,EllipticCurve('35a1'),41,20, cohomological=False, use_magma=False, use_ps_dists = True) Starting computation of the Darmon point ... (-70*alpha + 449 : 2100*alpha - 13444 : 1) A quaternionic (Greenberg) point:: sage: darmon_point(13,EllipticCurve('78a1'),5,20) # long time # optional - magma A Darmon point over a cubic (1,1) field:: sage: F.<r> = NumberField(x^3 - x^2 - x + 2) sage: E = EllipticCurve([-r -1, -r, -r - 1,-r - 1, 0]) sage: N = E.conductor() sage: P = F.ideal(r^2 - 2*r - 1) sage: beta = -3*r^2 + 9*r - 6 sage: darmon_point(P,E,beta,20) # long time # optional - magma ''' # global G, Coh, phiE, Phi, dK, J, J1, cycleGn, nn, Jlist config = ConfigParser.ConfigParser() config.read('config.ini') param_dict = config_section_map(config, 'General') param_dict.update(config_section_map(config, 'DarmonPoint')) param_dict.update(kwargs) param = Bunch(**param_dict) # Get general parameters outfile = param.get('outfile') use_ps_dists = param.get('use_ps_dists',False) use_shapiro = param.get('use_shapiro',True) use_sage_db = param.get('use_sage_db',False) magma_seed = param.get('magma_seed',1515316) parallelize = param.get('parallelize',False) Up_method = param.get('up_method','naive') use_magma = param.get('use_magma',True) progress_bar = param.get('progress_bar',True) sign_at_infinity = param.get('sign_at_infinity',ZZ(1)) # Get darmon_point specific parameters idx_orientation = param.get('idx_orientation') idx_embedding = param.get('idx_embedding',0) algorithm = param.get('algorithm') quaternionic = param.get('quaternionic') cohomological = param.get('cohomological',True) if Up_method == "bigmatrix" and use_shapiro == True: import warnings warnings.warn('Use of "bigmatrix" for Up iteration is incompatible with Shapiro Lemma trick. Using "naive" method for Up.') Up_method = 'naive' if working_prec is None: working_prec = max([2 * prec + 10, 30]) if use_magma: page_path = os.path.dirname(__file__) + '/KleinianGroups-1.0/klngpspec' if magma is None: from sage.interfaces.magma import Magma magma = Magma() quit_when_done = True else: quit_when_done = False magma.attach_spec(page_path) else: quit_when_done = False sys.setrecursionlimit(10**6) F = E.base_ring() beta = F(beta) DB,Np,Ncartan = get_heegner_params(P,E,beta) if quaternionic is None: quaternionic = ( DB != 1 ) if cohomological is None: cohomological = quaternionic if quaternionic and not cohomological: raise ValueError("Need cohomological algorithm when dealing with quaternions") if use_ps_dists is None: use_ps_dists = False if cohomological else True try: p = ZZ(P) except TypeError: p = ZZ(P.norm()) if not p.is_prime(): raise ValueError,'P (= %s) should be a prime, of inertia degree 1'%P if F == QQ: dK = ZZ(beta) extra_conductor_sq = dK/fundamental_discriminant(dK) assert ZZ(extra_conductor_sq).is_square() extra_conductor = extra_conductor_sq.sqrt() dK = dK / extra_conductor_sq assert dK == fundamental_discriminant(dK) if dK % 4 == 0: dK = ZZ(dK/4) beta = dK else: dK = beta # Compute the completion of K at p x = QQ['x'].gen() K = F.extension(x*x - dK,names = 'alpha') if F == QQ: dK = K.discriminant() else: dK = K.relative_discriminant() hK = K.class_number() sgninfty = 'plus' if sign_at_infinity == 1 else 'minus' if hasattr(E,'cremona_label'): Ename = E.cremona_label() elif hasattr(E,'ainvs'): Ename = E.ainvs() else: Ename = 'unknown' fname = 'moments_%s_%s_%s_%s.sobj'%(P,Ename,sgninfty,prec) if use_sage_db: print("Moments will be stored in database as %s"%(fname)) if outfile == 'log': outfile = '%s_%s_%s_%s_%s_%s.log'%(P,Ename,dK,sgninfty,prec,datetime.datetime.now().strftime("%Y%m%d-%H%M%S")) outfile = outfile.replace('/','div') outfile = '/tmp/darmonpoint_' + outfile fwrite("Starting computation of the Darmon point",outfile) fwrite('D_B = %s %s'%(DB,factor(DB)),outfile) fwrite('Np = %s'%Np,outfile) if Ncartan is not None: fwrite('Ncartan = %s'%Ncartan,outfile) fwrite('dK = %s (class number = %s)'%(dK,hK),outfile) fwrite('Calculation with p = %s and prec = %s'%(P,prec),outfile) fwrite('Elliptic curve %s: %s'%(Ename,E),outfile) if outfile is not None: print("Partial results will be saved in %s"%outfile) if input_data is None: if cohomological: # Define the S-arithmetic group if F != QQ and ramification_at_infinity is None: if F.signature()[0] > 1: if F.signature()[1] == 1: ramification_at_infinity = F.real_places(prec = Infinity) # Totally 'definite' else: raise ValueError,'Please specify the ramification at infinity' elif F.signature()[0] == 1: if len(F.ideal(DB).factor()) % 2 == 0: ramification_at_infinity = [] # Split at infinity else: ramification_at_infinity = F.real_places(prec = Infinity) # Ramified at infinity else: ramification_at_infinity = None if F == QQ: abtuple = QuaternionAlgebra(DB).invariants() else: abtuple = quaternion_algebra_invariants_from_ramification(F, DB, ramification_at_infinity) G = BigArithGroup(P,abtuple,Np,base = F,outfile = outfile,seed = magma_seed,use_sage_db = use_sage_db,magma = magma, use_shapiro = use_shapiro, nscartan=Ncartan) # Define the cycle ( in H_1(G,Div^0 Hp) ) Coh = ArithCoh(G) while True: try: cycleGn,nn,ell = construct_homology_cycle(G,beta,working_prec,lambda q: Coh.hecke_matrix(q).minpoly(), outfile = outfile, elliptic_curve = E) break except PrecisionError: working_prec *= 2 verbose('Encountered precision error, trying with higher precision (= %s)'%working_prec) except ValueError: fwrite('ValueError occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) if quit_when_done: magma.quit() return G except AssertionError as e: fwrite('Assertion occurred when constructing homology cycle. Returning the S-arithmetic group.', outfile) fwrite('%s'%str(e), outfile) if quit_when_done: magma.quit() return G eisenstein_constant = -ZZ(E.reduction(ell).count_points()) fwrite('r = %s, so a_r(E) - r - 1 = %s'%(ell,eisenstein_constant), outfile) fwrite('exponent = %s'%nn, outfile) phiE = Coh.get_cocycle_from_elliptic_curve(E, sign = sign_at_infinity) if hasattr(E,'ap'): sign_ap = E.ap(P) else: try: sign_ap = ZZ(P.norm() + 1 - E.reduction(P).count_points()) except ValueError: sign_ap = ZZ(P.norm() + 1 - Curve(E).change_ring(P.residue_field()).count_points(1)[0]) Phi = get_overconvergent_class_quaternionic(P,phiE,G,prec,sign_at_infinity,sign_ap,use_ps_dists = use_ps_dists,use_sage_db = use_sage_db,parallelize = parallelize,method = Up_method, progress_bar = progress_bar,Ename = Ename) # Integration with moments tot_time = walltime() J = integrate_H1(G,cycleGn,Phi,1,method = 'moments',prec = working_prec,parallelize = parallelize,twist = True,progress_bar = progress_bar) verbose('integration tot_time = %s'%walltime(tot_time)) if use_sage_db: G.save_to_db() else: # not cohomological nn = 1 eisenstein_constant = 1 if algorithm is None: if Np == 1: algorithm = 'darmon_pollack' else: algorithm = 'guitart_masdeu' w = K.maximal_order().ring_generators()[0] r0,r1 = w.coordinates_in_terms_of_powers()(K.gen()) QQp = Qp(p,working_prec) Cp = QQp.extension(w.minpoly().change_ring(QQp),names = 'g') v0 = K.hom([r0 + r1 * Cp.gen()]) # Optimal embeddings of level one fwrite("Computing optimal embeddings of level one...", outfile) Wlist = find_optimal_embeddings(K,use_magma = use_magma, extra_conductor = extra_conductor) fwrite("Found %s such embeddings."%len(Wlist), outfile) if idx_embedding is not None: if idx_embedding >= len(Wlist): fwrite('There are not enough embeddings. Taking the index modulo %s'%len(Wlist), outfile) idx_embedding = idx_embedding % len(Wlist) fwrite('Taking only embedding number %s'%(idx_embedding), outfile) Wlist = [Wlist[idx_embedding]] # Find the orientations orients = K.maximal_order().ring_generators()[0].minpoly().roots(Zmod(Np),multiplicities = False) fwrite("Possible orientations: %s"%orients, outfile) if len(Wlist) == 1 or idx_orientation == -1: fwrite("Using all orientations, since hK = 1", outfile) chosen_orientation = None else: fwrite("Using orientation = %s"%orients[idx_orientation], outfile) chosen_orientation = orients[idx_orientation] emblist = [] for i,W in enumerate(Wlist): tau, gtau,sign,limits = find_tau0_and_gtau(v0,Np,W,algorithm = algorithm,orientation = chosen_orientation,extra_conductor = extra_conductor) fwrite('n_evals = %s'%sum((num_evals(t1,t2) for t1,t2 in limits)), outfile) emblist.append((tau,gtau,sign,limits)) # Get the cohomology class from E Phi = get_overconvergent_class_matrices(P,E,prec,sign_at_infinity,use_ps_dists = use_ps_dists,use_sage_db = use_sage_db,parallelize = parallelize,progress_bar = progress_bar) J = 1 Jlist = [] for i,emb in enumerate(emblist): fwrite("Computing %s-th period, attached to the embedding: %s"%(i,Wlist[i].list()), outfile) tau, gtau,sign,limits = emb n_evals = sum((num_evals(t1,t2) for t1,t2 in limits)) fwrite("Computing one period...(total of %s evaluations)"%n_evals, outfile) newJ = prod((double_integral_zero_infty(Phi,t1,t2) for t1,t2 in limits))**ZZ(sign) Jlist.append(newJ) J *= newJ else: # input_data is not None Phi,J = input_data[1:3] fwrite('Integral done. Now trying to recognize the point', outfile) fwrite('J_psi = %s'%J,outfile) fwrite('g belongs to %s'%J.parent(),outfile) #Try to recognize a generator if quaternionic: local_embedding = G.base_ring_local_embedding(working_prec) twopowlist = [4, 3, 2, 1, QQ(1)/2, QQ(3)/2, QQ(1)/3, QQ(2)/3, QQ(1)/4, QQ(3)/4, QQ(5)/2, QQ(4)/3] else: local_embedding = Qp(p,working_prec) twopowlist = [4, 3, 2, 1, QQ(1)/2, QQ(3)/2, QQ(1)/3, QQ(2)/3, QQ(1)/4, QQ(3)/4, QQ(5)/2, QQ(4)/3] known_multiple = QQ(nn * eisenstein_constant) # It seems that we are not getting it with present algorithm. while known_multiple % p == 0: known_multiple = ZZ(known_multiple / p) candidate,twopow,J1 = recognize_J(E,J,K,local_embedding = local_embedding,known_multiple = known_multiple,twopowlist = twopowlist,prec = prec, outfile = outfile) if candidate is not None: HCF = K.hilbert_class_field(names = 'r1') if hK > 1 else K if hK == 1: try: verbose('candidate = %s'%candidate) Ptsmall = E.change_ring(HCF)(candidate) fwrite('twopow = %s'%twopow,outfile) fwrite('Computed point: %s * %s * %s'%(twopow,known_multiple,Ptsmall),outfile) fwrite('(first factor is not understood, second factor is)',outfile) fwrite('(r satisfies %s = 0)'%(Ptsmall[0].parent().gen().minpoly()),outfile) fwrite('================================================',outfile) if quit_when_done: magma.quit() return Ptsmall except (TypeError,ValueError): verbose("Could not recognize the point.") else: verbose('candidate = %s'%candidate) fwrite('twopow = %s'%twopow,outfile) fwrite('Computed point: %s * %s * (x,y)'%(twopow,known_multiple),outfile) fwrite('(first factor is not understood, second factor is)',outfile) try: pols = [HCF(c).relative_minpoly() for c in candidate[:2]] except AttributeError: pols = [HCF(c).minpoly() for c in candidate[:2]] fwrite('Where x satisfies %s'%pols[0],outfile) fwrite('and y satisfies %s'%pols[1],outfile) fwrite('================================================',outfile) if quit_when_done: magma.quit() return candidate else: fwrite('================================================',outfile) if quit_when_done: magma.quit() return []
def simplify(self, x, error=None, force=False, size_heuristic_bound=32): r""" Return a simplified version of ``x``. Produce an element which differs from ``x`` by an element of valuation strictly greater than the valuation of ``x`` (or strictly greater than ``error`` if set.) INPUT: - ``x`` -- an element in the domain of this valuation - ``error`` -- a rational, infinity, or ``None`` (default: ``None``), the error allowed to introduce through the simplification - ``force`` -- ignored - ``size_heuristic_bound`` -- when ``force`` is not set, the expected factor by which the ``x`` need to shrink to perform an actual simplification (default: 32) EXAMPLES:: sage: v = ZZ.valuation(2) sage: v.simplify(6, force=True) 2 sage: v.simplify(6, error=0, force=True) 0 In this example, the usual rational reconstruction misses a good answer for some moduli (because the absolute value of the numerator is not bounded by the square root of the modulus):: sage: v = QQ.valuation(2) sage: v.simplify(110406, error=16, force=True) 562/19 sage: Qp(2, 16)(110406).rational_reconstruction() Traceback (most recent call last): ... ArithmeticError: rational reconstruction of 55203 (mod 65536) does not exist """ if not force and self._relative_size(x) <= size_heuristic_bound: return x x = self.domain().coerce(x) v = self(x) if error is None: error = v from sage.rings.all import infinity if error is infinity: return x if error < v: return self.domain().zero() from sage.rings.all import QQ from sage.rings.all import Qp precision_ring = Qp(self.p(), QQ(error).floor() + 1 - v) reduced = precision_ring(x) lift = (reduced >> v).lift() best = self.domain()(lift) * self.p()**v if self._relative_size(x) < self._relative_size(best): best = x # We implement a modified version of the usual rational reconstruction # algorithm (based on the extended Euclidean algorithm) here. We do not # get the uniqueness properties but we do not need them actually. # This is certainly slower than the implementation in Cython. from sage.categories.all import Fields m = self.p()**(QQ(error).floor() + 1 - v) if self.domain() in Fields(): r = (m, lift) s = (0, 1) while r[1]: qq, rr = r[0].quo_rem(r[1]) r = r[1], rr s = s[1], s[0] - qq * s[1] from sage.arith.all import gcd if s[1] != 0 and gcd(s[1], r[1]) == 1: rational = self.domain()(r[1]) / self.domain()( s[1]) * self.p()**v if self._relative_size(rational) < self._relative_size( best): best = rational assert (self(x - best) > error) return best