Beispiel #1
0
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)
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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
Beispiel #5
0
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)]
Beispiel #6
0
def cyclotomic_polynomial_bound_4():
    return [cyclotomic_polynomial(k) for k in [1, 2, 3, 4, 5, 6, 8, 10, 12] ]