def sample_apoly_points_via_giac_rur(manifold, n): import giac_rur I = extended_ptolemy_equations(manifold) R = I.ring() p = cyclotomic_polynomial(n, var=R('M')) I = I + [p] return giac_rur.rational_univariate_representation(I)
def is_semisimple_modular(M, m, nprimes=5): """M is a pari matrix over Q(zeta_m). Check if M mod p has squarefree char poly for nprimes primes p=1 (mod m). If True for any p, return True since then the char poly of M itself must be square-free. If False for all p, return False since the M probably has non-squarefree char poly. There may therefore be false negatives. """ pol = cyclotomic_polynomial(m) pt = pari("t") np = 0 for p in prime_range(1000000): if m > 1 and not p % m == 1: continue np += 1 #print("testing modulo p={}".format(p)) if np > nprimes: #print("op not semisimple modulo {} primes, so returning False".format(nprimes)) return False zmodp = pari(pol.roots(GF(p))[0][0]) #print("zmodp = {}".format(zmodp)) try: Mmodp = M.lift() * pari(mod(1, p)) #print("Lifted matrix = {}".format(Mmodp)) Mmodp = Mmodp.subst(pt, zmodp) #print("matrix (mod {}) = {}".format(p,Mmodp)) modpcharpoly = Mmodp.charpoly() #print("char poly (mod {}) = {}".format(p,modpcharpoly)) if modpcharpoly.issquarefree(): #print("op is semisimple mod {}".format(p)) return True else: #print("op is not semisimple mod {}".format(p)) pass except PariError: ## happens if M not integral mod p np -= 1
def Newforms_v2(N, k, chi_number, dmax=20, nan=100, Detail=0): t0 = time.time() G = pari(N).znstar(1) chi_dc = char_orbit_index_to_DC_number(N, chi_number) chi_gp = G.znconreylog(chi_dc) chi_order = ZZ(G.charorder(chi_gp)) if Detail: print("Decomposing space {}:{}:{}".format(N, k, chi_number)) NK = [N, k, [G, chi_gp]] pNK = pari(NK) if Detail > 1: print("NK = {} (gp character = {})".format(NK, chi_gp)) SturmBound = pNK.mfsturm() Snew = pNK.mfinit(0) total_dim = Snew.mfdim( ) # this is the relative dimension i.e. degree over Q(chi) # Get the character polynomial # Note that if the character order is 2*m with m odd then Pari uses the # m'th cyclotomic polynomial and not the 2m'th (e.g. for a # character of order 6 it uses t^2+t+1 and not t^2-t+1). chi_order_2 = chi_order // 2 if chi_order % 4 == 2 else chi_order chipoly = cyclotomic_polynomial(chi_order_2, 't') chi_degree = chipoly.degree() assert chi_degree == euler_phi(chi_order) == euler_phi(chi_order_2) t05 = time.time() if Detail: print( "Computed newspace {}:{}:{} in {:0.3f}, dimension={}*{}={}, now splitting into irreducible subspaces" .format(N, k, chi_number, t05 - t0, chi_degree, total_dim, chi_degree * total_dim)) if Detail > 1: print("Sturm bound = {}".format(SturmBound)) print("character order = {}".format(chi_order)) if total_dim == 0: if Detail: print("The space {}:{}:{} is empty".format(N, k, chi_number)) return [] # First just compute Hecke matrices one at a time, to find a splitting operator def Hecke_op_iter(): p = ZZ(1) while True: p = p.next_prime() # while p.divides(N): # p=p.next_prime() #print("Computing T_{}".format(p)) yield p, Snew.mfheckemat(p) Tp_iter = Hecke_op_iter() p, op = Tp_iter.next() s1 = time.time() if Detail: print("testing T_{}".format(p)) ok = is_semisimple_modular(op, chi_order_2) # f = op.charpoly() # ok = f.issquarefree() if ok: if Detail: print("Lucky first time: semisimple. Finding char poly") f = op.charpoly() ops = [(p, op)] while not ok: pi, opi = Tp_iter.next() if Detail: print("testing T_{}".format(pi)) ok = is_semisimple_modular(op, chi_order_2) # f = opi.charpoly() # ok = f.issquarefree() if ok: if Detail: print("success using T_{}. Finding char poly".format(pi)) op = opi f = op.charpoly() break else: #ops.append((pi,opi)) ops += [(pi, opi)] if Detail: print("T_{} not semisimple".format(pi)) print("testing combinations...") for j in range(5): co = [ZZ.random_element(-5, 5) for _ in ops] while not co: co = [ZZ.random_element(-5, 5) for _ in ops] if Detail: print("Testing lin comb of {} ops with coeffs {}".format( len(co), co)) op = sum([ci * opj[1] for ci, opj in zip(co, ops)]) ok = is_semisimple_modular(op, chi_order_2) # f=op.charpoly() # ok = f.issquarefree() if ok: if Detail: print( "success using {}-combo of T_p for p in {}. Finding char poly" .format(co, [opj[0] for opj in ops])) f = op.charpoly() break if not ok: raise RuntimeError( "failed to find a 0,1-combination of Tp which is semisimple") ffac = f.factor() nnf = ffac.matsize()[0] gp_pols = pari_col1(ffac) pols = [pol for pol in gp_pols] reldims = [pol.poldegree() for pol in pols] dims = [d * chi_degree for d in reldims] # We'll need the coefficients an, if any newforms have dimension >1 and <=dmax. an_needed = [ i for i, d in enumerate(dims) if d > 1 and (dmax == 0 or d <= dmax) ] if Detail: print("Need to compute a_n for {} newforms: {}".format( len(an_needed), an_needed)) s2 = time.time() if Detail: print("Computed splitting in {:0.3f}, # newforms = {}".format( s2 - s1, nnf)) print("relative dims = {}, absolute dims = {}".format(reldims, dims)) # Compute AL-matrices if character is trivial: if chi_order == 1: Qlist = [(pr, pr**e) for pr, e in ZZ(N).factor()] ALs = [Snew.mfatkininit(Q[1])[1] for Q in Qlist] if Detail: print("AL-matrices:") for Q, AL in zip(Qlist, ALs): print("W_{}={}".format(Q[1], AL)) if nnf == 1 and dims[0] > dmax and dmax > 0: if Detail: print( "Only one newform and dim={}, so use traceform to get traces". format(dims[0])) traces = pNK.mftraceform().mfcoefs(nan) if Detail > 1: print("raw traces: {}".format(traces)) if chi_degree > 1: # This is faster than the more simple # traces = [c.trace() for c in traces] gptrace = pari_trace(chi_degree) traces = pari.apply(gptrace, traces) if Detail > 1: print("traces to QQ: {}".format(traces)) traces = gen_to_sage(traces)[1:] traces[0] = dims[0] if Detail > 1: print("final traces: {}".format(traces)) traces = [traces] else: # >1 newform, or just one but its absolute dim is <=dmax hs = [f / fi for fi in pols] if Detail > 1: print("fs: {}".format(pols)) print("hs: {}".format(hs)) print(" with degrees {}".format([h.poldegree() for h in hs])) if Detail > 1: print("Starting to compute gcds") As = [(hi * (fi.gcdext(hi)[2])).subst(pari_x, op) for fi, hi in zip(pols, hs)] if Detail: print("Computed idempotent matrix decomposition") ims = [A.matimage() for A in As] U = pari.matconcat(ims) Uinv = U**(-1) if Detail: print("Computed U and U^-1") starts = [1 + sum(d for d in reldims[:i]) for i in range(len(reldims))] stops = [sum(d for d in reldims[:i + 1]) for i in range(len(reldims))] slicers = [pari_row_slice(r1, r2) for r1, r2 in zip(starts, stops)] ums = [slice(Uinv) for slice in slicers] imums = [imA * umA for imA, umA in zip(ims, ums)] s3 = time.time() if Detail: print("Computed projectors in {:0.3f}".format(s3 - s2)) print("Starting to compute {} Hecke matrices T_n".format(nan)) heckemats = Snew.mfheckemat(pari(range(1, nan + 1))) s4 = time.time() if Detail: print("Computed {} Hecke matrices in {:0.3f}s".format( nan, s4 - s3)) # If we are going to compute any a_n then we now compute # umA*T*imA for all Hecke matrices T, whose traces give the # traces and whose first columns (or any row or column) give # the coefficients of the a_n with respect to some # Q(chi)-basis for the Hecke field. # But if we only need the traces then it is faster to # precompute imA*umA=imAumA and then the traces are # trace(imAumA*T). NB trace(UMV)=trace(VUM)! if Detail: print("Computing traces") # Note that computing the trace of a matrix product is faster # than first computing the product and then the trace: gptrace = pari( 'c->if(type(c)=="t_POLMOD",trace(c),c*{})'.format(chi_degree)) traces = [[ gen_to_sage(gptrace(pari_trace_product(T, imum))) for T in heckemats ] for imum in imums] s4 = time.time() if Detail: print("Computed traces to Z in {:0.3f}".format(s4 - s3)) for tr in traces: print(tr[:20]) ans = [None for _ in range(nnf)] bases = [None for _ in range(nnf)] if an_needed: if Detail: print("...computing a_n...") for i in an_needed: dr = reldims[i] if Detail: print("newform #{}/{}, relative dimension {}".format( i, nnf, dr)) # method: for each irreducible component we have matrices # um and im (sizes dr x n and n x dr where n is the # relative dimension of the whole space) such that for # each Hecke matrix T, its restriction to the component is # um*T*im. To get the eigenvalue in a suitable basis all # we need do is take any one column (or row): we choose # the first column. So the computation can be done as # um*(T*im[,1]) (NB the placing of parentheses). imsicol1 = pari_col1(ims[i]) umsi = ums[i] ans[i] = [(umsi * (T * imsicol1)).Vec() for T in heckemats] if Detail: print("ans done") if Detail > 1: print("an: {}...".format(ans[i])) # Now compute the bases (of the relative Hecke field over # Q(chi) w.r.t which these coefficients are given. Here # we use e1 because we picked the first column just now. B = ums[i] * op * ims[i] e1 = pari_e1(dr) cols = [e1] while len(cols) < dr: cols.append(B * cols[-1]) W = pari.matconcat(cols) bases[i] = W.mattranspose()**(-1) if Detail > 1: print("basis = {}".format(bases[i].lift())) # Compute AL-eigenvalues if character is trivial: if chi_order == 1: ALeigs = [[[Q[0], gen_to_sage((umA * (AL * (pari_col1(imA))))[0])] for Q, AL in zip(Qlist, ALs)] for umA, imA in zip(ums, ims)] if Detail > 1: print("ALeigs: {}".format(ALeigs)) else: ALeigs = [[] for _ in range(nnf)] Nko = (N, k, chi_number) #print("len(traces) = {}".format(len(traces))) #print("len(newforms) = {}".format(len(newforms))) #print("len(pols) = {}".format(len(pols))) #print("len(ans) = {}".format(len(ans))) #print("len(ALeigs) = {}".format(len(ALeigs))) pari_nfs = [{ 'Nko': Nko, 'SB': SturmBound, 'chipoly': chipoly, 'poly': pols[i], 'ans': ans[i], 'basis': bases[i], 'ALeigs': ALeigs[i], 'traces': traces[i], } for i in range(nnf)] # We could return these as they are but the next processing step # will fail if the underlying gp process has quit, so we do the # processing here. # This processing returns full data but the polynomials have not # yet been polredbested and the an coefficients have not been # optimized (or even made integral): #return pari_nfs t1 = time.time() if Detail: print("{}: finished constructing pari newforms (time {:0.3f})".format( Nko, t1 - t0)) nfs = [process_pari_nf(nf, dmax, Detail) for nf in pari_nfs] if len(nfs) > 1: nfs.sort(key=lambda f: f['traces']) t2 = time.time() if Detail: print( "{}: finished first processing of newforms (time {:0.3f})".format( Nko, t2 - t1)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [bestify_newform(nf, dmax, Detail) for nf in nfs] t3 = time.time() if Detail: print("{}: finished bestifying newforms (time {:0.3f})".format( Nko, t3 - t2)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [integralify_newform(nf, dmax, Detail) for nf in nfs] t4 = time.time() if Detail: print("{}: finished integralifying newforms (time {:0.3f})".format( Nko, t4 - t3)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) print("Total time for space {}: {:0.3f}".format(Nko, t4 - t0)) return nfs
def Newforms_v1(N, k, chi_number, dmax=20, nan=100, Detail=0): t0 = time.time() G = pari(N).znstar(1) chi_dc = char_orbit_index_to_DC_number(N, chi_number) chi_gp = G.znconreylog(chi_dc) chi_order = ZZ(G.charorder(chi_gp)) if Detail: print("Decomposing space {}:{}:{}".format(N, k, chi_number)) NK = [N, k, [G, chi_gp]] pNK = pari(NK) if Detail > 1: print("NK = {} (gp character = {})".format(NK, chi_gp)) SturmBound = pNK.mfsturm() Snew = pNK.mfinit(0) total_dim = Snew.mfdim() # Get the character polynomial # Note that if the character order is 2*m with m odd then Pari uses the # m'th cyclotomic polynomial and not the 2m'th (e.g. for a # character of order 6 it uses t^2+t+1 and not t^2-t+1). chi_order_2 = chi_order // 2 if chi_order % 4 == 2 else chi_order chipoly = cyclotomic_polynomial(chi_order_2, 't') chi_degree = chipoly.degree() assert chi_degree == euler_phi(chi_order) == euler_phi(chi_order_2) if Detail: print( "Computed newspace {}:{}:{}, dimension={}*{}={}, now splitting into irreducible subspaces" .format(N, k, chi_number, chi_degree, total_dim, chi_degree * total_dim)) if Detail > 1: print("Sturm bound = {}".format(SturmBound)) print("character order = {}".format(chi_order)) # Get the relative polynomials: these are polynomials in y with coefficients either integers or polmods with modulus chipoly pols = Snew.mfsplit(0, 1)[1] if Detail > 2: print("pols[GP] = {}".format(pols)) nnf = len(pols) dims = [chi_degree * f.poldegree() for f in pols] if nnf == 0: if Detail: print("The space {}:{}:{} is empty".format(N, k, chi_number)) return [] if Detail: print("The space {}:{}:{} has {} newforms, dimensions {}".format( N, k, chi_number, nnf, dims)) # Get the traces. NB (1) mftraceform will only give the trace # form on the whole space so we only use this when nnf==1, # i.e. the space is irreducible. Otherwise we'll need to compute # traces from the ans. (2) these are only traces down to Q(chi) # so when that has degree>1 (and only then) we need to take an # additional trace. traces = [None for _ in range(nnf)] if nnf == 1: d = ZZ(chi_degree * (pols[0]).poldegree()) if Detail: print("Only one newform so use traceform to get traces") traces = pNK.mftraceform().mfcoefs(nan) if Detail > 1: print("raw traces: {}".format(traces)) if chi_degree > 1: # This is faster than the more simple # traces = [c.trace() for c in traces] gptrace = pari_trace(chi_degree) traces = pari.apply(gptrace, traces) if Detail > 1: print("traces to QQ: {}".format(traces)) traces = gen_to_sage(traces)[1:] traces[0] = d if Detail > 1: print("final traces: {}".format(traces)) traces = [traces] # Get the coefficients an. We'll need these for a newform f if # either (1) its dimension is >1 and <= dmax, when we want to # store them, or (2) there is more than one newform, so we can # later compute the traces from them. So we don't need them if # nnf==1 and the dimension>dmax. if dmax == 0 or nnf > 1 or ((chi_degree * (pols[0]).poldegree()) <= dmax): if Detail > 1: print("...computing mfeigenbasis...") newforms = Snew.mfeigenbasis() if Detail > 1: print("...computing {} mfcoefs...".format(nan)) coeffs = Snew.mfcoefs(nan) ans = [coeffs * Snew.mftobasis(nf) for nf in newforms] if Detail > 2: print("ans[GP] = {}".format(ans)) else: # there is only one newform (so we have the traces) and its # dimension is >dmax (so we will not need the a_n): ans = [None for _ in range(nnf)] newforms = [None for _ in range(nnf)] # Compute AL-eigenvalues if character is trivial: if chi_order == 1: Qlist = [(p, p**e) for p, e in ZZ(N).factor()] ALs = [gen_to_sage(Snew.mfatkineigenvalues(Q[1])) for Q in Qlist] if Detail: print("ALs: {}".format(ALs)) # "transpose" this list of lists: ALeigs = [[[Q[0], ALs[i][j][0]] for i, Q in enumerate(Qlist)] for j in range(nnf)] if Detail: print("ALeigs: {}".format(ALeigs)) else: ALeigs = [[] for _ in range(nnf)] Nko = (N, k, chi_number) # print("len(traces) = {}".format(len(traces))) # print("len(newforms) = {}".format(len(newforms))) # print("len(pols) = {}".format(len(pols))) # print("len(ans) = {}".format(len(ans))) # print("len(ALeigs) = {}".format(len(ALeigs))) pari_nfs = [{ 'Nko': Nko, 'SB': SturmBound, 'chipoly': chipoly, 'pari_newform': newforms[i], 'poly': pols[i], 'ans': ans[i], 'ALeigs': ALeigs[i], 'traces': traces[i], } for i in range(nnf)] # This processing returns full data but the polynomials have not # yet been polredbested and the an coefficients have not been # optimized (or even made integral): #return pari_nfs t1 = time.time() if Detail: print("{}: finished constructing GP newforms (time {:0.3f})".format( Nko, t1 - t0)) nfs = [process_pari_nf_v1(nf, dmax, Detail) for nf in pari_nfs] if len(nfs) > 1: nfs.sort(key=lambda f: f['traces']) t2 = time.time() if Detail: print( "{}: finished first processing of newforms (time {:0.3f})".format( Nko, t2 - t1)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [bestify_newform(nf, dmax, Detail) for nf in nfs] t3 = time.time() if Detail: print("{}: finished bestifying newforms (time {:0.3f})".format( Nko, t3 - t2)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [integralify_newform(nf, dmax, Detail) for nf in nfs] t4 = time.time() if Detail: print("{}: finished integralifying newforms (time {:0.3f})".format( Nko, t4 - t3)) if Detail > 2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) print("Total time for space {}: {:0.3f}".format(Nko, t4 - t0)) return nfs
def Newforms_v1(N, k, chi_number, dmax=20, nan=100, Detail=0, dims_only=False): t0=time.time() G = pari(N).znstar(1) Qx = PolynomialRing(QQ,'x') chi_dc = char_orbit_index_to_DC_number(N,chi_number) chi_gp = G.znconreylog(chi_dc) chi_order = ZZ(G.charorder(chi_gp)) if Detail: print("Decomposing space {}:{}:{}".format(N,k,chi_number)) NK = [N,k,[G,chi_gp]] pNK = pari(NK) if Detail>1: print("NK = {} (gp character = {})".format(NK,chi_gp)) SturmBound = pNK.mfsturm() Snew = pNK.mfinit(0) reldim = Snew.mfdim() if reldim==0: if Detail: print("The space {}:{}:{} is empty".format(N,k,chi_number)) return [] # Get the character polynomial # Note that if the character order is 2*m with m odd then Pari uses the # m'th cyclotomic polynomial and not the 2m'th (e.g. for a # character of order 6 it uses t^2+t+1 and not t^2-t+1). chi_order_2 = chi_order//2 if chi_order%4==2 else chi_order chipoly = cyclotomic_polynomial(chi_order_2,'t') chi_degree = chipoly.degree() totdim = reldim * chi_degree assert chi_degree==euler_phi(chi_order)==euler_phi(chi_order_2) if Detail: print("Computed newspace {}:{}:{}, dimension={}*{}={}, now splitting into irreducible subspaces".format(N,k,chi_number, chi_degree, reldim, totdim)) if Detail>1: print("Sturm bound = {}".format(SturmBound)) print("character order = {}".format(chi_order)) # Get the relative polynomials: these are polynomials in y with coefficients either integers or polmods with modulus chipoly # But we only need the poly for the largest space if its absolute dimension is less than 20 d = max(reldim // 2, dmax // chi_degree) if dmax else 0 if dims_only: if Detail: t1=time.time(); print("...calling mfsplit({},{})...".format(d,1)) forms, pols = Snew.mfsplit(d,1) if Detail: print("Call to mfsplit took {:.3f} secs".format(time.time()-t1)) if Detail>2: print("mfsplit({},1) returned pols[GP] = {}".format(d,pols)) dims = [chi_degree*f.poldegree() for f in pols] dims += [] if sum(dims+[0]) == totdim else [totdim-sum(dims+[0])] # add dimension of largest newform if needed nnf = len(dims) if Detail: print("The space {}:{}:{} has {} newforms, dimensions {}".format(N,k,chi_number,nnf,dims)) pari_nfs = [ { 'Nko': (N,k,chi_number), 'SB': SturmBound, 'chipoly': chipoly, 'dim': dims[i], 'traces': [], 'ALeigs': [], 'ans': [], 'poly': Qx.gen() if dims[i] == 1 else (pols[i] if dims[i] <= dmax else None), 'pari_newform':None, 'best_poly':None } for i in range(nnf)] return pari_nfs if Detail: t1=time.time(); print("...calling mfsplit({},{})...".format(d,d)) forms, pols = Snew.mfsplit(d,d) if Detail: print("Call to mfsplit took {:.3f} secs".format(time.time()-t1)) if Detail>2: print("mfsplit({},1) returned pols[GP] = {}".format(d,pols)) dims = [chi_degree*f.poldegree() for f in pols] dims += [] if sum(dims+[0]) == totdim else [totdim-sum(dims+[0])] # add dimension of largest newform if needed nnf = len(dims) if Detail: print("The space {}:{}:{} has {} newforms, dimensions {}".format(N,k,chi_number,nnf,dims)) # Compute trace forms using a combination of mftraceform and mfsplit (this avoids the need to compute a complete eigenbasis) # When the newspace contains a large irreducible subspace (and zero or more small ones) this saves a huge amount of time (e.g. 1000x faster) traces = [None for _ in range(nnf)] if Detail: t1=time.time(); print("...calling mftraceform...") straces = pNK.mftraceform().mfcoefs(nan) if Detail: print("Call to mftraceform took {:.3f} secs".format(time.time()-t1)) straces = gen_to_sage(pari.apply(pari_trace(chi_degree),straces)) if Detail>1: print("Newspace traceform: {}".format(straces)) # Compute coefficients here (but note that we don't need them if there is only one newform and its dimension is > dmax) if nnf>1 or dmax==0 or dims[0] <= dmax: if Detail: t1=time.time(); print("...computing {} mfcoefs...".format(nan)) coeffs = Snew.mfcoefs(nan) if Detail: print("Call to mfcoefs took {:.3f} secs".format(time.time()-t1)) if nnf==1: traces[0] = straces[1:] else: if Detail: s0=time.time() tforms = [pari.apply("trace",forms[i]) if pols[i].poldegree() > 1 else forms[i] for i in range(nnf-1)] ttraces = [pari.apply(pari_trace(chi_degree),coeffs*nf) for nf in tforms] ltraces = [straces[i] - sum([ttraces[j][i] for j in range(len(ttraces))]) for i in range(nan+1)] traces = [list(t)[1:] for t in ttraces] + [ltraces[1:]] if Detail>1: print("Traceforms: {}".format(traces)) if Detail: print("Spent {:.3f} secs computing traceforms".format(time.time()-s0)) # Get coefficients an for all newforms f of dim <= dmax (if dmax is set) # Note that even if there are only dimension 1 forms we want to compute an so that pari puts the AL-eigenvalues in the right order # m = max([d for d in dims if (dmax==0 or d<=dmax)] + [0]) d1 = len([d for d in dims if d == 1]) dm = len([i for i in range(nnf) if dmax==0 or dims[i] <= dmax]) ans = [traces[i] for i in range(d1)] + [coeffs*forms[i] for i in range(d1,dm)] + [None for i in range(dm,nnf)] if Detail>2: print("ans[GP] = {}".format(ans)) newforms = [None for i in range(d1)] + [forms[i] for i in range(d1,dm)] + [None for i in range(dm,nnf)] # Compute AL-eigenvalues if character is trivial: if chi_order==1: Qlist = [(p,p**e) for p,e in ZZ(N).factor()] ALs = [gen_to_sage(Snew.mfatkineigenvalues(Q[1])) for Q in Qlist] if Detail: print("ALs: {}".format(ALs)) # "transpose" this list of lists: ALeigs = [[[Q[0],ALs[i][j][0]] for i,Q in enumerate(Qlist)] for j in range(nnf)] if Detail: print("ALeigs: {}".format(ALeigs)) else: ALeigs = [[] for _ in range(nnf)] Nko = (N,k,chi_number) if Detail: print("traces set = {}".format([1 if t else 0 for t in traces])) if Detail: print("ans set = {}".format([1 if a else 0 for a in ans])) pari_nfs = [ { 'Nko': Nko, 'SB': SturmBound, 'chipoly': chipoly, 'dim': dims[i], 'pari_newform': newforms[i], 'poly': Qx.gen() if dims[i] == 1 else (pols[i] if dims[i] <= dmax else None), 'best_poly': Qx.gen() if dims[i] == 1 else None, 'ans': ans[i], 'ALeigs': ALeigs[i], 'traces': traces[i], } for i in range(nnf)] if len(pari_nfs)>1: pari_nfs.sort(key=lambda f: f['traces']) t1=time.time() if Detail: print("{}: finished constructing GP newforms (time {:0.3f})".format(Nko,t1-t0)) if d1 == dm: return pari_nfs # At this point we have everything we need, but the ans have not been optimized (or even made integral) nfs = [process_pari_nf_v1(pari_nfs[i], dmax, Detail) for i in range(d1,dm)] t2=time.time() if Detail: print("{}: finished first processing of newforms (time {:0.3f})".format(Nko,t2-t1)) if Detail>2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [bestify_newform(nf,dmax,Detail) for nf in nfs] t3=time.time() if Detail: print("{}: finished bestifying newforms (time {:0.3f})".format(Nko,t3-t2)) if Detail>2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) nfs = [integralify_newform(nf,dmax,Detail) for nf in nfs] t4=time.time() if Detail: print("{}: finished integralifying newforms (time {:0.3f})".format(Nko,t4-t3)) if Detail>2: for nf in nfs: if 'eigdata' in nf: print(nf['eigdata']['ancs']) print("Total time for space {}: {:0.3f}".format(Nko,t4-t0)) return [pari_nfs[i] for i in range(d1)] + nfs + [pari_nfs[i] for i in range(dm,nnf)]
def cyclotomic_polynomial_bound_4(): return [cyclotomic_polynomial(k) for k in [1, 2, 3, 4, 5, 6, 8, 10, 12] ]