def padic_H_values(self, t): res = self.amortized_padic_H_values(t) is_tame = self.is_tame_prime(t) for p in prime_range(self._pbound + 1): if not is_tame(p): res[p] = GF(p)(self.padic_H_value(p=p, f=1, t=t)) return res
def an_list(euler_factor_polynomial_fn, upperbound=100000, base_field=sage.rings.all.RationalField()): """ Takes a fn that gives for each prime the polynomial of the associated with the prime, given as a list, with independent coefficient first. This list is of length the degree+1. """ from sage.rings.fast_arith import prime_range from sage.rings.all import PowerSeriesRing from math import ceil, log PP = PowerSeriesRing(base_field, 'x', 1 + ceil(log(upperbound) / log(2.))) x = PP('x') prime_l = prime_range(upperbound + 1) result = [1 for i in range(upperbound)] for p in prime_l: euler_factor = (1 / (PP(euler_factor_polynomial_fn(p)))).padded_list() if len(euler_factor) == 1: for j in range(1, 1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p**k > upperbound: break for j in range(1, 1 + upperbound // (p**k)): if j % p == 0: continue result[j * p**k - 1] *= euler_factor[k] k += 1 return result
def an_list(euler_factor_polynomial_fn, upperbound=100000, base_field=sage.rings.all.RationalField()): """ Takes a fn that gives for each prime the polynomial of the associated with the prime, given as a list, with independent coefficient first. This list is of length the degree+1. """ from sage.rings.fast_arith import prime_range from sage.rings.all import PowerSeriesRing from math import ceil, log PP = PowerSeriesRing(base_field, 'x', 1 + ceil(log(upperbound) / log(2.))) prime_l = prime_range(upperbound + 1) result = [1 for i in range(upperbound)] for p in prime_l: euler_factor = (1 / (PP(euler_factor_polynomial_fn(p)))).padded_list() if len(euler_factor) == 1: for j in range(1, 1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p ** k > upperbound: break for j in range(1, 1 + upperbound // (p ** k)): if j % p == 0: continue result[j * p ** k - 1] *= euler_factor[k] k += 1 return result
def an_list(self, upperbound=100000): from sage.rings.fast_arith import prime_range PP = sage.rings.all.PowerSeriesRing(sage.rings.all.RationalField(), 'x', 30) x = PP('x') prime_l = prime_range(upperbound) result = upperbound * [1] for p in prime_l: euler_factor = (1 / (PP(self.eulerFactor(p)))).padded_list() if len(euler_factor) == 1: for j in range(1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p ** k > upperbound: break for j in range(1 + upperbound // (p ** k)): if j % p == 0: continue result[j * p ** k - 1] *= euler_factor[k] k += 1 return result
def an_list(self, upperbound=100000): from sage.rings.fast_arith import prime_range PP = sage.rings.all.PowerSeriesRing(sage.rings.all.RationalField(), 'x', 30) # FIXME THIS VARIABLE IS NEVER USED # x = PP('x') prime_l = prime_range(upperbound) result = upperbound * [1] for p in prime_l: euler_factor = (1 / (PP(self.eulerFactor(p)))).padded_list() if len(euler_factor) == 1: for j in range(1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p**k > upperbound: break for j in range(1 + upperbound // (p**k)): if j % p == 0: continue result[j * p**k - 1] *= euler_factor[k] k += 1 return result
def _primes(self): r""" Primes up to `N` satisfying the filter EXAMPLES:: sage: ARF = AccRemForest(20, {None: lambda x: x}, range, 1, lambda p: p > 3) sage: ARF._primes [5, 7, 11, 13, 17, 19] """ return [p for p in prime_range(self.N) if self.prime_filter(p)]
def tensor_get_an_no_deg1(L1, L2, d1, d2, BadPrimeInfo): """ Same as the above in the case no dimension is 1 """ if d1==1 or d2==1: raise ValueError('min(d1,d2) should not be 1, use direct method then') s1 = len(L1) s2 = len(L2) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S+1) Z = S * [1] S = RealField()(S) for p in P: f = S.log(base=p).floor() q = 1 E1 = [] E2 = [] if not p in BadPrimes: for i in range(f): q=q*p E1.append(L1[q-1]) E2.append(L2[q-1]) e1 = list_to_euler_factor(E1,f+1) e2 = list_to_euler_factor(E2,f+1) ld1 = d1 ld2 = d2 else: # either convolve, or have one input be the answer and other 1-t i = BadPrimes.index(p) e1 = BadPrimeInfo[i][1] e2 = BadPrimeInfo[i][2] ld1 = e1.degree() ld2 = e2.degree() F = e1.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f+1) e1 = R(e1) e2 = R(e2) E = tensor_local_factors(e1,e2,f) A = euler_factor_to_list(E,f) while len(A) < f: A.append(0) q = 1 for i in range(f): q = q*p Z[q-1]=A[i] all_an_from_prime_powers(Z) return Z
def tensor_get_an_no_deg1(L1, L2, d1, d2, BadPrimeInfo): """ Same as the above in the case no dimension is 1 """ if d1 == 1 or d2 == 1: raise ValueError('min(d1,d2) should not be 1, use direct method then') s1 = len(L1) s2 = len(L2) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S + 1) Z = S * [1] S = RealField()(S) for p in P: f = S.log(base=p).floor() q = 1 E1 = [] E2 = [] if not p in BadPrimes: for i in range(f): q = q * p E1.append(L1[q - 1]) E2.append(L2[q - 1]) e1 = list_to_euler_factor(E1, f + 1) e2 = list_to_euler_factor(E2, f + 1) ld1 = d1 ld2 = d2 else: # either convolve, or have one input be the answer and other 1-t i = BadPrimes.index(p) e1 = BadPrimeInfo[i][1] e2 = BadPrimeInfo[i][2] ld1 = e1.degree() ld2 = e2.degree() F = e1.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f + 1) e1 = R(e1) e2 = R(e2) E = tensor_local_factors(e1, e2, f) A = euler_factor_to_list(E, f) while len(A) < f: A.append(0) q = 1 for i in range(f): q = q * p Z[q - 1] = A[i] all_an_from_prime_powers(Z) return Z
def print_table_examples(Dbound): for D,h in [(D,h) for D,h in [(D,QuadraticField(D,'a').class_number()) for D in range(-1,-Dbound,-1)] if h % 2 == 1 and ZZ(-D).is_prime() and h > 2]: try: E = EllipticCurve(str(-D)) except ValueError: continue if E.rank() != 1: continue print D,h, E.conductor() print '----' for p in prime_range(5,50): print p,E.change_ring(GF(p)).count_points().factor() print ''
def _prime_range(self, t): prime_ranges = defaultdict(lambda: defaultdict(list)) ds = set([elt.denominator() for elt in self.starts]) ds.add(1) # is_tame = self.is_tame_prime(t) s = self.anomalous_primes() tame = self.tame_primes(t) s = s.union(tame) for p in prime_range(self._pbound + 1, self.N): if p not in s: # if not is_tame(p) and not (p in s): for d in ds: #assert p not in prime_ranges[d][p % d] prime_ranges[d][p % d].append(p) return prime_ranges
def all_an_from_prime_powers(L): """ L is a list of an such that the terms are correct for all n which are prime powers and all others are equal to 1; this function changes the list in place to make the correct ans for all n """ S = ZZ(len(L)) for p in prime_range(S+1): q = 1 Sr = RealField()(len(L)) f = Sr.log(base=p).floor() for k in range(f): q = q*p for m in range(2, 1+(S//q)): if (m%p) != 0: L[m*q-1] = L[m*q-1] * L[q-1]
def all_an_from_prime_powers(L): """ L is a list of an such that the terms are correct for all n which are prime powers and all others are equal to 1; this function changes the list in place to make the correct ans for all n """ S = ZZ(len(L)) for p in prime_range(S + 1): q = 1 Sr = RealField()(len(L)) f = Sr.log(base=p).floor() for k in range(f): q = q * p for m in range(2, 1 + (S // q)): if (m % p) != 0: L[m * q - 1] = L[m * q - 1] * L[q - 1]
def an_list(euler_factor_polynomial_fn, upperbound=100000, base_field=sage.rings.all.RationalField()): """ Takes a fn that gives for each prime the Euler polynomial of the associated with the prime, given as a list, with independent coefficient first. This list is of length the degree+1. Output the first `upperbound` coefficients built from the Euler polys. Example: The `euler_factor_polynomial_fn` should in practice come from an L-function or data. For a simple example, we construct just the 2 and 3 factors of the Riemann zeta function, which have Euler factors (1 - 1*2^(-s))^(-1) and (1 - 1*3^(-s))^(-1). >>> euler = lambda p: [1, -1] if p <= 3 else [1, 0] >>> an_list(euler)[:20] [1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0] """ from sage.rings.fast_arith import prime_range from sage.rings.all import PowerSeriesRing from math import ceil, log PP = PowerSeriesRing(base_field, 'x', 1 + ceil(log(upperbound) / log(2.))) prime_l = prime_range(upperbound + 1) result = [1 for i in range(upperbound)] for p in prime_l: euler_factor = (1 / (PP(euler_factor_polynomial_fn(p)))).padded_list() if len(euler_factor) == 1: for j in range(1, 1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p**k > upperbound: break for j in range(1, 1 + upperbound // (p**k)): if j % p == 0: continue result[j * p**k - 1] *= euler_factor[k] k += 1 return result
def an_list(euler_factor_polynomial_fn, upperbound=100000, base_field=sage.rings.all.RationalField()): """ Takes a fn that gives for each prime the Euler polynomial of the associated with the prime, given as a list, with independent coefficient first. This list is of length the degree+1. Output the first `upperbound` coefficients built from the Euler polys. Example: The `euler_factor_polynomial_fn` should in practice come from an L-function or data. For a simple example, we construct just the 2 and 3 factors of the Riemann zeta function, which have Euler factors (1 - 1*2^(-s))^(-1) and (1 - 1*3^(-s))^(-1). >>> euler = lambda p: [1, -1] if p <= 3 else [1, 0] >>> an_list(euler)[:20] [1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0] """ from sage.rings.fast_arith import prime_range from sage.rings.all import PowerSeriesRing from math import ceil, log PP = PowerSeriesRing(base_field, 'x', 1 + ceil(log(upperbound) / log(2.))) prime_l = prime_range(upperbound + 1) result = [1 for i in range(upperbound)] for p in prime_l: euler_factor = (1 / (PP(euler_factor_polynomial_fn(p)))).padded_list() if len(euler_factor) == 1: for j in range(1, 1 + upperbound // p): result[j * p - 1] = 0 continue k = 1 while True: if p ** k > upperbound: break for j in range(1, 1 + upperbound // (p ** k)): if j % p == 0: continue result[j * p ** k - 1] *= euler_factor[k] k += 1 return result
def tensor_get_an_deg1(L, D, BadPrimeInfo): """ Same as above, except that the BadPrimeInfo is now a list of lists of the form [p,f] where f is a polynomial. """ s1 = len(L) s2 = len(D) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S + 1) Z = S * [1] S = RealField()(S) # fix bug for p in P: f = S.log(base=p).floor() q = 1 u = 1 e = D[p - 1] if not p in BadPrimes: for i in range(f): q = q * p u = u * e Z[q - 1] = u * L[q - 1] else: i = BadPrimes.index(p) e = BadPrimeInfo[i][1] F = e.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f + 1) e = R(e) A = euler_factor_to_list(e, f) for i in range(f): q = q * p Z[q - 1] = A[i] all_an_from_prime_powers(Z) return Z
def tensor_get_an_deg1(L, D, BadPrimeInfo): """ Same as above, except that the BadPrimeInfo is now a list of lists of the form [p,f] where f is a polynomial. """ s1 = len(L) s2 = len(D) if s1 < s2: S = s1 if s2 <= s1: S = s2 BadPrimes = [] for bpi in BadPrimeInfo: BadPrimes.append(bpi[0]) P = prime_range(S+1) Z = S * [1] S = RealField()(S) # fix bug for p in P: f = S.log(base=p).floor() q = 1 u = 1 e = D[p-1] if not p in BadPrimes: for i in range(f): q = q*p u = u*e Z[q-1] = u*L[q-1] else: i = BadPrimes.index(p) e = BadPrimeInfo[i][1] F = e.list()[0].parent().fraction_field() R = PowerSeriesRing(F, "T", default_prec=f+1) e = R(e) A = euler_factor_to_list(e,f) for i in range(f): q = q*p Z[q-1] = A[i] all_an_from_prime_powers(Z) return Z
def dirichlet_coefficients(self, ncoeffs=20): from sage.rings.power_series_ring import PowerSeriesRing from sage.misc.misc import srange #from sage.misc.mrange import mrange ncoeffs = ZZ(ncoeffs) ps = prime_range(ncoeffs + 1) num_ps = len(ps) exps = [ncoeffs.exact_log(p) + 1 for p in ps] M = ncoeffs.exact_log(2) + 1 #print ps, exps, M PS = PowerSeriesRing(QQ, 'x', M) euler_factors = dict([[ps[i], ~PS(self.euler_factor(ps[i]), exps[i] + 1)] for i in range(num_ps)]) ans = [] for n in srange(1, ncoeffs + 1): ans.append(prod([euler_factors[p][e] for p, e in n.factor()])) #ans = [0] * ncoeffs #is_zeroes = True #for e in mrange(exps): # if is_zeroes: # is_zeroes = False # ans[0] = QQ.one() # continue # n = 1 # an = QQ.one() # breaker = False # for i in range(num_ps): # if exps[i] == 0: # continue # n *= ps[i] ** e[i] # if n > ncoeffs: # breaker = True # break # an *= euler_factors[i][e[i]] # #print n, an, e # if breaker: # continue # ans[n-1] = an return ans
def Lpvalue(f,g,h,p,prec,N = None,modformsring = False, weightbound = False, eps = None, orthogonal_form = None, data_idx=None, magma_args = None,force_computation=False, algorithm='threestage', derivative_order=1, lauders_advice = False, use_magma = True, magma = None, num_coeffs_qexpansion = 20000, max_primes=5, outfile = None): if magma_args is None: magma_args = {} if algorithm not in ['twostage','threestage']: raise ValueError('Algorithm should be one of "twostage" (default) or "threestage"') if magma is None: from sage.interfaces.magma import Magma magma = Magma(**magma_args) if hasattr(g,'j_invariant'): elliptic_curve = g g = g.modular_form() else: elliptic_curve = None data = None if h is None: if hasattr(f, 'modulus'): # Assume we need to create f and h from Dirichlet character kronecker_character = f f, _, h = define_qexpansions_from_dirichlet_character(p, prec, kronecker_character, num_coeffs_qexpansion, magma) else: kronecker_character = None # Assume that f contains a list of lines of text to initialize both f and h data = f f, h = get_magma_qexpansions(data, data_idx, max(prec,200), Qp(p,prec), magma=magma) eps = f.character_full() ll,mm = g.weight(),h.weight() t = 0 # Assume t = 0 here kk = ll + mm - 2 * (1 + t) # Is this correct? p = ZZ(p) if N is None: N = lcm([ZZ(f.level()),ZZ(g.level()),ZZ(h.level())]) nu = N.valuation(p) N = N.prime_to_m_part(p) else: N = ZZ(N) nu = N.valuation(p) if outfile is None: outfile = "output_iterated_integral_%s_%s_%s_%s.txt"%(p,g.level(), h.level(), prec) print("Writing output to file %s"%outfile) fwrite("######### STARTING COMPUTATION OF Lp ###########", outfile) if elliptic_curve is not None: fwrite("E = EllipticCurve(%s)"%list(elliptic_curve.ainvs()), outfile) fwrite(" cond(E) = %s"%elliptic_curve.conductor(), outfile) if kronecker_character is not None: fwrite("kronecker_character = %s"%kronecker_character, outfile) fwrite(" conductor = %s"%kronecker_character.conductor(), outfile) if data is not None: fwrite("Data for weight-1 forms:", outfile) for line in data: fwrite(line, outfile) fwrite("Tame level N = %s, prime p = %s, nu = %s"%(N,p,nu), outfile) fwrite("precision = %s"%prec, outfile) fwrite("------ parameters --------------------", outfile) fwrite("modformsring = %s"%modformsring, outfile) fwrite("weightbound = %s"%weightbound, outfile) fwrite("eps = %s"%eps, outfile) fwrite("orthogonal_form = %s"%orthogonal_form, outfile) fwrite("magma_args = %s"%magma_args, outfile) fwrite("force_computation = %s"%force_computation, outfile) fwrite("algorithm = %s"%algorithm, outfile) fwrite("derivative_order = %s"%derivative_order, outfile) fwrite("lauders_advice = %s"%lauders_advice, outfile) fwrite("use_magma = %s"%use_magma, outfile) fwrite("num_coeffs_qexpansion = %s"%num_coeffs_qexpansion, outfile) fwrite("##########################################", outfile) prec = ZZ(prec) fwrite("Step 1: Compute the Up matrix", outfile) if algorithm == "twostage": computation_name = '%s_%s_%s_%s_%s_%s_%s'%(p,N,nu,kk,prec,'triv' if eps is None else 'char',algorithm) else: computation_name = '%s_%s_%s_%s_%s_%s'%(p,N,nu,kk,prec,'triv' if eps is None else 'char') if use_magma: tmp_filename = '/tmp/magma_mtx_%s.tmp'%computation_name import os.path from sage.misc.persist import db, db_save try: if force_computation: raise IOError V = db('Lpvalue_Apow_ordbasis_eimat_%s'%computation_name) ord_basis, eimat, zetapm, elldash, mdash = V[:5] Apow_data = V[5:] except IOError: if force_computation or not os.path.exists(tmp_filename): if eps is not None: eps_magma = sage_character_to_magma(eps,N,magma=magma) magma.load("overconvergent_alan.m") # Am, zetapm, eimatm, elldash, mdash = magma.UpOperatorData(p, eps_magma, kk, prec,WeightBound=weightbound,nvals=5) Am, zetapm, eimatm, elldash, mdash = magma.HigherLevelUpGj(p, kk, prec, weightbound, eps_magma,'"B"',nvals=5) else: # Am, zetapm, eimatm, elldash, mdash = magma.UpOperatorData(p, N, kk, prec,WeightBound=weightbound,nvals=5) magma.load("overconvergent_alan.m") Am, zetapm, eimatm, elldash, mdash = magma.HigherLevelUpGj(p, kk, prec, weightbound, N,'"B"',nvals=5) fwrite(" ..Converting to Sage...", outfile) Amodulus = Am[1,1].Parent().Modulus().sage() Aprec = Amodulus.valuation(p) Arows = Am.NumberOfRows().sage() Acols = Am.NumberOfColumns().sage() Emodulus = eimatm[1,1].Parent().Modulus().sage() Eprec = Emodulus.valuation(p) Erows = eimatm.NumberOfRows().sage() Ecols = eimatm.NumberOfColumns().sage() magma.load("get_qexpansions.m") magma.eval('F := Open("%s", "w");'%tmp_filename) magma.eval('fprintf F, "%s, %s, %s, %s \\n"'%(p,Aprec,Arows,Acols)) # parameters magma.eval('save_matrix(%s, F)'%(Am.name())) # for i in range(1,Arows+1): # magma.eval('fprintf F, "%%o\\n", %s[%s]'%(Am.name(),i)) magma.eval('fprintf F, "%s, %s, %s, %s \\n"'%(p,Eprec,Erows,Ecols)) # parameters magma.eval('save_matrix(%s, F)'%(eimatm.name())) # for i in range(1,Erows+1): # magma.eval('fprintf F, "%%o\\n", %s[%s]'%(eimatm.name(),i)) magma.eval('fprintf F, "%s\\n"'%zetapm) magma.eval('fprintf F, "%s\\n"'%elldash) magma.eval('fprintf F, "%s\\n"'%mdash) magma.eval('delete F;') magma.quit() # Read A and eimat from file from sage.structure.sage_object import load from sage.misc.sage_eval import sage_eval with open(tmp_filename,'r') as fmagma: A = read_matrix_from_file(fmagma) eimat = read_matrix_from_file(fmagma) zetapm= sage_eval(fmagma.readline()) elldash = sage_eval(fmagma.readline()) mdash = sage_eval(fmagma.readline()) fwrite("Step 3b: Apply Up^(r-1) to H", outfile) if algorithm == 'twostage': V0 = list(find_Apow_and_ord_two_stage(A, eimat, p, prec)) else: V0 = list(find_Apow_and_ord_three_stage(A,eimat,p,prec)) ord_basis = V0[0] Apow_data = V0[1:] V = [ord_basis] V.extend([eimat, zetapm, elldash, mdash]) V.extend(Apow_data) db_save(V,'Lpvalue_Apow_ordbasis_eimat_%s'%computation_name) from posix import remove remove(tmp_filename) else: A, eimat, elldash, mdash = UpOperator(p,N,kk,prec, modformsring = False, weightbound = 6) fwrite("Step 2: p-depletion, Coleman primitive, and multiply", outfile) fwrite(".. Need %s coefficients of the q-expansion..."%(p**(nu+1) * elldash), outfile) if data is not None: f, h = get_magma_qexpansions(data, data_idx, (p**(nu+1) * elldash) + 200, Qp(p,prec), magma=magma) H = depletion_coleman_multiply(g, h, p, p**(nu+1) * elldash, t=0) fwrite("Step 3a: Compute ordinary projection", outfile) if len(Apow_data) == 1: Hord = compute_ordinary_projection_two_stage(H, Apow_data, eimat, elldash,p) else: Hord = compute_ordinary_projection_three_stage(H, [ord_basis] + Apow_data, eimat, elldash,p,nu) fwrite('Changing Hord to ring %s'%g[1].parent(), outfile) Hord = Hord.change_ring(h[1].parent()) print [Hord[i] for i in range(30)] fwrite("Step 4: Project onto f-component", outfile) while True: try: ell, piHord, epstwist = project_onto_eigenspace(f, ord_basis, Hord, kk, N * p, p = p, derivative_order=derivative_order, max_primes=max_primes) break except RuntimeError: derivative_order += 1 verbose("Increasing experimental derivative order to %s"%derivative_order) except ValueError: verbose("Experimental derivative order (%s) seems too high"%derivative_order) fwrite("Experimental derivative_order = %s"%derivative_order, outfile) fwrite("Seems too high...", outfile) fwrite("######################################", outfile) assert 0 n = 1 while f[n] == 0: n = next_prime(n) if lauders_advice == True or orthogonal_form is None: Lpa = piHord[n] / (f[n] * epstwist(n)) fwrite("Experimental derivative_order = %s"%derivative_order, outfile) fwrite("Checking Lauder's coincidence... (following should be a bunch of 'large' valuations)", outfile) fwrite(str([(i,(Lpa * f[i] * epstwist(i) - piHord[i]).valuation(p)) for i in prime_range(50)]), outfile) fwrite("Done", outfile) else: gplus, gminus = f, orthogonal_form l1 = 2 while N*p*ell % l1 == 0 or gplus[l1] == 0: l1 = next_prime(l1) proj_mat = matrix([[gplus[l1],gplus[p]],[gminus[l1],gminus[p]]]) Lpalist = (matrix([piHord[l1],piHord[p]]) * proj_mat**-1).list() Lpa = Lpalist[0] if Lpa.valuation() > prec / 2: # this is quite arbitrary! Lpa = Lpalist[1] Lpa = Lpa / f[n] fwrite("ell = %s"%ell, outfile) fwrite("######### FINISHED COMPUTATION ###########", outfile) fwrite("Lp = %s"%Lpa, outfile) fwrite("##########################################", outfile) return Lpa, ell
def get_is_geom_field(f, C, bad_primes, B=200): r""" Determine whether the geometric endomorphism algebra is a field. This is Algorithm 4.10 in [Lom2019]_. The computation done here may allow one to immediately conclude that the geometric endomorphism ring is trivial (i.e. the integer ring); this information is output in a second boolean to avoid unnecessary subsequent computation. An additional optimisation comes from Part (2) of Theorem 4.8 in [Lom2019]_, from which we can conclude that the endomorphism ring is geometrically trivial, and from Proposition 4.7 in loc. cit. from which we can rule out potential QM. INPUT: - ``f`` -- a polynomial defining the hyperelliptic curve. - ``C`` -- the hyperelliptic curve. - ``bad_primes`` -- the list of odd primes of bad reduction. - ``B`` -- (default: 200) the bound which appears in the statement of the algorithm from [Lom2019]_ OUTPUT: Pair of booleans (bool1, bool2). `bool1` indicates if the geometric endomorphism algebra is a field; `bool2` indicates if the geometric endomorphism algebra is the field of rational numbers. WARNING: There is a very small chance that this algorithm return ``False`` when in fact it is ``True``. In this case, as explained in the discussion immediately preceding Algorithm 4.15 of [Lom2019]_, this can be established by increasing the optional `B` parameter. Mathematically, this algorithm gives the correct answer only in the limit as `B \to \infty`, although in practice `B = 200` was sufficient to correctly verify every single entry in the LMFDB. However, strictly speaking, a ``False`` returned by this function is not provably ``False``. EXAMPLES: This is LMFDB curve 940693.a.960693.1:: sage: from sage.schemes.hyperelliptic_curves.jacobian_endomorphism_utils import get_is_geom_field sage: R.<x> = QQ[] sage: f = 4*x^6 - 12*x^5 + 20*x^3 - 8*x^2 - 4*x + 1 sage: C = HyperellipticCurve(f) sage: get_is_geom_field(f,C,[13,269]) (False, False) This is LMFDB curve 3125.a.3125.1:: sage: f = 4*x^5 + 1 sage: C = HyperellipticCurve(f) sage: get_is_geom_field(f,C,[5]) (True, False) This is LMFDB curve 277.a.277.2:: sage: f = 4*x^6 - 36*x^4 + 56*x^3 - 76*x^2 + 44*x - 23 sage: C = HyperellipticCurve(f) sage: get_is_geom_field(f,C,[277]) (True, True) """ if C.has_odd_degree_model(): C_odd = C.odd_degree_model() f_odd, h_odd = C_odd.hyperelliptic_polynomials() # if f was odd to begin with, then f_odd = f assert f_odd.degree() == 5 if (4*f_odd + h_odd**2).degree() == 5: f_new = 4*f_odd + h_odd**2 if f_new.is_irreducible(): # i.e. the Jacobian is geometrically simple f_disc_odd_prime_exponents = [v for _,v in f_new.discriminant().prime_to_S_part([ZZ(2)]).factor()] if 1 in f_disc_odd_prime_exponents: return (True, True) # Theorem 4.8 (2) # At this point we are in the situation of Algorithm 4.10 # Step 1, so either the geometric endomorphism algebra is a # field or it is a quaternion algebra. This latter case implies # that the Jacobian is the square of an elliptic curve modulo # a prime p where f is also irreducible (which exist by # Chebotarev density). This contradicts Prop 4.7, hence we can # conclude as follows. return (True, False) if f.is_irreducible(): assert f.degree() == 6 # else we should already have exited by now G = f.galois_group() if G.order() in [360, 720]: return (True, True) # Algorithm 4.10 Step 2 R = PolynomialRing(ZZ,2,"xv") x,v = R.gens() T = PolynomialRing(QQ,'v') g = v - x**12 for p in prime_range(3,B): if p not in bad_primes: fp = C.change_ring(FiniteField(p)).frobenius_polynomial() # This defines the polynomial f_v**[12] from the paper fp12 = T(R(fp).resultant(g)) if fp12.is_irreducible(): # i.e. the Jacobian is geometrically simple f_disc_odd_prime_exponents = [v for _,v in f.discriminant().prime_to_S_part([ZZ(2)]).factor()] if 1 in f_disc_odd_prime_exponents: return (True, True) # Theorem 4.8 (2) return (True, False) # Algorithm 4.10 Step 3 plus Prop 4.7 as above return (False, False)
def is_geom_trivial_when_field(C, bad_primes, B=200): r""" Determine if the geometric endomorphism ring is trivial assuming the geometric endomorphism algebra is a field. This is Algorithm 4.15 in [Lom2019]_. INPUT: - ``C`` -- the hyperelliptic curve. - ``bad_primes`` -- the list of odd primes of bad reduction. - ``B`` -- (default: 200) the bound which appears in the statement of the algorithm from [Lom2019]_ OUTPUT: Boolean indicating whether or not the geometric endomorphism algebra is the field of rational numbers. WARNING: There is a very small chance that this algorithm returns ``False`` when in fact it is ``True``. In this case, as explained in the discussion immediately preceding Algorithm 4.15 of [Lom2019]_, this can be established by increasing the optional `B` parameter. Mathematically, this algorithm gives the correct answer only in the limit as `B \to \infty`, although in practice `B = 200` was sufficient to correctly verify every single entry in the LMFDB. However, strictly speaking, a ``False`` returned by this function is not provably ``False``. EXAMPLES: This is LMFDB curve 461.a.461.2:: sage: from sage.schemes.hyperelliptic_curves.jacobian_endomorphism_utils import is_geom_trivial_when_field sage: R.<x> = QQ[] sage: f = 4*x^5 - 4*x^4 - 156*x^3 + 40*x^2 + 1088*x - 1223 sage: C = HyperellipticCurve(f) sage: is_geom_trivial_when_field(C,[461]) True This is LMFDB curve 4489.a.4489.1:: sage: f = x^6 + 4*x^5 + 2*x^4 + 2*x^3 + x^2 - 2*x + 1 sage: C = HyperellipticCurve(f) sage: is_geom_trivial_when_field(C,[67]) False """ running_gcd = 0 R = PolynomialRing(ZZ,2,"xv") x,v = R.gens() T = PolynomialRing(QQ,'v') g = v - x**4 for p in prime_range(3,B): if p not in bad_primes: Cp = C.change_ring(FiniteField(p)) fp = Cp.frobenius_polynomial() if satisfies_coefficient_condition(fp, p): # This defines the polynomial f_v**[4] from the paper fp4 = T(R(fp).resultant(g)) if fp4.is_irreducible(): running_gcd = gcd(running_gcd, NumberField(fp,'a').discriminant()) if running_gcd <= 24: return True return False
def find_in_space(f, A, base_extend=False): r""" Given a Newform object `f`, and a space `A` of modular symbols of the same weight and level, find the subspace of `A` which corresponds to the Hecke eigenvalues of `f`. If ``base_extend = True``, this will return a 2-dimensional space generated by the plus and minus eigensymbols of `f`. If ``base_extend = False`` it will return a larger space spanned by the eigensymbols of `f` and its Galois conjugates. (NB: "Galois conjugates" needs to be interpreted carefully -- see the last example below.) `A` should be an ambient space (because non-ambient spaces don't implement ``base_extend``). EXAMPLES:: sage: from sage.modular.local_comp.type_space import find_in_space Easy case (`f` has rational coefficients):: sage: f = Newform('99a'); f q - q^2 - q^4 - 4*q^5 + O(q^6) sage: A = ModularSymbols(GammaH(99, [13])) sage: find_in_space(f, A) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 25 for Congruence Subgroup Gamma_H(99) with H generated by [13] of weight 2 with sign 0 and over Rational Field Harder case:: sage: f = Newforms(23, names='a')[0] sage: A = ModularSymbols(Gamma1(23)) sage: find_in_space(f, A, base_extend=True) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 45 for Gamma_1(23) of weight 2 with sign 0 and over Number Field in a0 with defining polynomial x^2 + x - 1 sage: find_in_space(f, A, base_extend=False) Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 45 for Gamma_1(23) of weight 2 with sign 0 and over Rational Field An example with character, indicating the rather subtle behaviour of ``base_extend``:: sage: chi = DirichletGroup(5).0 sage: f = Newforms(chi, 7, names='c')[0]; f # long time (4s on sage.math, 2012) q + c0*q^2 + (zeta4*c0 - 5*zeta4 + 5)*q^3 + ((-5*zeta4 - 5)*c0 + 24*zeta4)*q^4 + ((10*zeta4 - 5)*c0 - 40*zeta4 - 55)*q^5 + O(q^6) sage: find_in_space(f, ModularSymbols(Gamma1(5), 7), base_extend=True) # long time Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 12 for Gamma_1(5) of weight 7 with sign 0 and over Number Field in c0 with defining polynomial x^2 + (5*zeta4 + 5)*x - 88*zeta4 over its base field sage: find_in_space(f, ModularSymbols(Gamma1(5), 7), base_extend=False) # long time (27s on sage.math, 2012) Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 12 for Gamma_1(5) of weight 7 with sign 0 and over Cyclotomic Field of order 4 and degree 2 Note that the base ring in the second example is `\QQ(\zeta_4)` (the base ring of the character of `f`), *not* `\QQ`. """ if not A.weight() == f.weight(): raise ValueError("Weight of space does not match weight of form") if not A.level() == f.level(): raise ValueError("Level of space does not match level of form") if base_extend: D = A.base_extend(f.hecke_eigenvalue_field()) else: M = f.modular_symbols(sign=1) D = A.base_extend(M.base_ring()) expected_dimension = 2 if base_extend else 2 * M.dimension() for p in prime_range(1 + A.sturm_bound()): h = D.hecke_operator(p) if base_extend: hh = h - f[p] else: f = M.hecke_polynomial(p) hh = f(h) DD = hh.kernel() if DD.dimension() < D.dimension(): D = DD if D.dimension() <= expected_dimension: break if D.dimension() != expected_dimension: raise ArithmeticError("Error in find_in_space: " + "got dimension %s (should be %s)" % (D.dimension(), expected_dimension)) return D
def find_in_space(f, A, base_extend=False): r""" Given a Newform object `f`, and a space `A` of modular symbols of the same weight and level, find the subspace of `A` which corresponds to the Hecke eigenvalues of `f`. If ``base_extend = True``, this will return a 2-dimensional space generated by the plus and minus eigensymbols of `f`. If ``base_extend = False`` it will return a larger space spanned by the eigensymbols of `f` and its Galois conjugates. (NB: "Galois conjugates" needs to be interpreted carefully -- see the last example below.) `A` should be an ambient space (because non-ambient spaces don't implement ``base_extend``). EXAMPLES:: sage: from sage.modular.local_comp.type_space import find_in_space Easy case (`f` has rational coefficients):: sage: f = Newform('99a'); f q - q^2 - q^4 - 4*q^5 + O(q^6) sage: A = ModularSymbols(GammaH(99, [13])) sage: find_in_space(f, A) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 25 for Congruence Subgroup Gamma_H(99) with H generated by [13] of weight 2 with sign 0 and over Rational Field Harder case:: sage: f = Newforms(23, names='a')[0] sage: A = ModularSymbols(Gamma1(23)) sage: find_in_space(f, A, base_extend=True) Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 45 for Gamma_1(23) of weight 2 with sign 0 and over Number Field in a0 with defining polynomial x^2 + x - 1 sage: find_in_space(f, A, base_extend=False) Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 45 for Gamma_1(23) of weight 2 with sign 0 and over Rational Field An example with character, indicating the rather subtle behaviour of ``base_extend``:: sage: chi = DirichletGroup(5).0 sage: f = Newforms(chi, 7, names='c')[0]; f # long time (4s on sage.math, 2012) q + c0*q^2 + (zeta4*c0 - 5*zeta4 + 5)*q^3 + ((-5*zeta4 - 5)*c0 + 24*zeta4)*q^4 + ((10*zeta4 - 5)*c0 - 40*zeta4 - 55)*q^5 + O(q^6) sage: find_in_space(f, ModularSymbols(Gamma1(5), 7), base_extend=True) # long time Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 12 for Gamma_1(5) of weight 7 with sign 0 and over Number Field in c0 with defining polynomial x^2 + (5*zeta4 + 5)*x - 88*zeta4 over its base field sage: find_in_space(f, ModularSymbols(Gamma1(5), 7), base_extend=False) # long time (27s on sage.math, 2012) Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 12 for Gamma_1(5) of weight 7 with sign 0 and over Cyclotomic Field of order 4 and degree 2 Note that the base ring in the second example is `\QQ(\zeta_4)` (the base ring of the character of `f`), *not* `\QQ`. """ if not A.weight() == f.weight(): raise ValueError( "Weight of space does not match weight of form" ) if not A.level() == f.level(): raise ValueError( "Level of space does not match level of form" ) if base_extend: D = A.base_extend(f.hecke_eigenvalue_field()) else: M = f.modular_symbols(sign=1) D = A.base_extend(M.base_ring()) expected_dimension = 2 if base_extend else 2*M.dimension() for p in prime_range(1 + A.sturm_bound()): h = D.hecke_operator(p) if base_extend: hh = h - f[p] else: f = M.hecke_polynomial(p) hh = f(h) DD = hh.kernel() if DD.dimension() < D.dimension(): D = DD if D.dimension() <= expected_dimension: break if D.dimension() != expected_dimension: raise ArithmeticError( "Error in find_in_space: " + "got dimension %s (should be %s)" % (D.dimension(), expected_dimension) ) return D