Beispiel #1
0
def wg_find_gamma(K):
    """
    Given a CM field K, returns gamma such that O_K = O_F[gamma].
    """
    assert K.is_CM()
    F, iota = K.maximal_totally_real_subfield()
    if F == QQ:
        R = ZZ['x']
        (x, ) = R._first_ngens(1)
        F = NumberField(x - _sage_const_1, "a0")
        iota = F.embeddings(K)[_sage_const_0]
    L = K.relativize(iota, names=('b', ))
    (b, ) = L._first_ngens(1)
    pari_to_F = lambda polmod: gen_to_sage(polmod, locals={"y": F.gen()})
    F_zk = [pari_to_F(b) for b in F.pari_zk()]
    B = pari.rnfbasis(F.pari_bnf(), L.defining_polynomial())
    B = [[
        pari_to_F(pari.centerlift(pari.nfbasistoalg(F.pari_nf(), b)))
        for b in Bi
    ] for Bi in B]
    B = [K(b[_sage_const_0] + b[_sage_const_1] * L.gen(0)) for b in B]
    assert B[_sage_const_0] == _sage_const_1
    gamma = B[_sage_const_1]
    # double check
    B = flatten([[iota(bi), gamma * iota(bi)]
                 for bi in F.ring_of_integers().basis()])
    assert all(bi in K.ring_of_integers() for bi in B)
    assert K.discriminant() == Matrix([[K(bi * bj).trace() for bi in B]
                                       for bj in B]).det()
    return gamma
Beispiel #2
0
def bestify_newform(nf, dmax=20, Detail=0):
    r"""
    Input is a dict with keys
     {
    'Nko',  'chipoly', 'SB', 'ALeigs', 'dim', 'traces', 'poly', 'eigdata'
    }
    (with ALeigs only when o=1 and eigdata only when 1<dim<=dmax)

    Here eigdata is a dict of the form

    'pol': list of d+1 coefficients of polynomial defining Hecke field F
    'bas': list of lists of rationals holding dxd matrix whose rows define a Q-basis for F in terms of the power basis
    'ancs': list of lists of d rationals giving coefficients of each a_n w.r.t. that basis
    'n': 0 (not yet set)
    'm': 0 (not yet set)

    Output adds 'best_poly' and applies a change of basis to eigdata
    changing 'pol' and 'bas' so the basis coefficients are w.r.t. the
    best_poly power basis and not the poly power basis.
    """
    Nko = nf['Nko']
    dim = nf['dim']
    if dim == 1:
        nf['best_poly'] = nf['poly']
        return nf
    if dim > dmax and dmax > 0:
        nf['best_poly'] = None
        return nf
    Qx = PolynomialRing(QQ, 'x')
    pari_Qx_poly_to_sage = lambda f: Qx(gen_to_sage(f.Vecrev()))
    poly = Qx(nf['poly'].list())
    if Detail:
        print("non-best poly for {} is {}".format(Nko, poly))
    nf['best_poly'] = best_poly = polredbest_stable(poly)
    if Detail:
        print("best_poly for {} is {}".format(Nko, best_poly))

    # Now the real work starts
    Fold = NumberField(poly, 'a')
    #print("Fold = {}".format(Fold))
    Fnew = NumberField(best_poly, 'b')
    #print("Fnew = {}".format(Fnew))
    iso = Fold.is_isomorphic(
        Fnew, isomorphism_maps=True)[1][0]  # we do not care which isomorphism
    #print("iso = {}".format(iso))
    iso = pari_Qx_poly_to_sage(iso)
    iso = Fold.hom([iso(Fnew.gen())])
    new_basis_matrix = [
        a.list()
        for a in [iso(b) for b in [Fold(co) for co in nf['eigdata']['bas']]]
    ]
    nf['eigdata']['bas'] = new_basis_matrix
    nf['eigdata']['pol'] = best_poly.list()
    return nf
Beispiel #3
0
def python(z, locals=None):
    """
    Return the closest Python/Sage equivalent of the given PARI object.

    This is deprecated, use the ``python`` method of :class:`gen`
    instead.

    TESTS::

        sage: from sage.libs.pari.gen_py import python
        sage: python(pari(3))
        doctest:...: DeprecationWarning: gen_py.python is deprecated, use sage.libs.pari.convert_sage.gen_to_sage or the .sage() method instead
        See http://trac.sagemath.org/19888 for details.
        3
    """
    from sage.misc.superseded import deprecation
    deprecation(19888, 'gen_py.python is deprecated, use sage.libs.pari.convert_sage.gen_to_sage or the .sage() method instead')
    from sage.libs.pari.convert_sage import gen_to_sage
    return gen_to_sage(z, locals)
Beispiel #4
0
 def enum_points(I):
     possibleValues = get_elements()
     R = I.ring()
     F = R.base()
     ch = F.characteristic()
     n = R.ngens()
     if n == 0:
         if I.is_zero():
             yield []
         return
     if I.is_one():
         return
     if all(map(lambda _: _.degree() == 1,
                I.gens())) and (ch > 0 or I.dimension() == 0):
         # solve using linear algebra
         f = R.hom(n * [0], F)
         A = matrix([f(g.coefficient(xi)) for xi in R.gens()]
                    for g in I.gens())
         b = vector(-g.constant_coefficient() for g in I.gens())
         v0 = A.solve_right(b)
         r = A.rank()
         if r == n:
             yield list(v0)
         else:
             K = A.right_kernel().matrix()
             for v in F**(n - r):
                 yield list(v * K + v0)
         return
     if ch > 0 and I.is_homogeneous():
         yield [F(0)] * n
         for pt in enum_proj_points(I):
             for sca in get_elements():
                 if sca != 0:
                     yield [x * sca for x in pt]
         return
     elim = I.elimination_ideal(I.ring().gens()[1:])
     g = elim.gens()[0]
     if g != 0:
         S = F['u']
         pr1 = R.hom([S.gen()] + [0] * (n - 1), S)
         possibleValues = (v[0] for v in pr1(g).roots() if bound == None or
                           global_height([v[0], F(1)]) <= bound + tolerance)
         if split:
             nonSplit = (f[0] for f in factor(pr1(g)) if f[0].degree() > 1)
             for f in nonSplit:
                 if ch == 0:
                     F_ = f.splitting_field('a')
                     # `polredbest` from PARI/GP, improves performance significantly
                     f = gen_to_sage(
                         pari(F_.gen().minpoly('x')).polredbest(),
                         {'x': S.gen()})
                 F_ = f.splitting_field('a')
                 R_ = PolynomialRing(F_, 'x', n)
                 I = R_.ideal(
                     [f.change_ring(base_change(F, F_)) for f in I.gens()])
                 for pt in enum_points(I):
                     yield pt
                 return
     R_ = PolynomialRing(F, 'x', n - 1)
     if n == 1:
         for v in possibleValues:
             yield [v]
     else:
         for v in possibleValues:
             pr2 = R.hom([v] + list(R_.gens()), R_)
             for rest in enum_points(pr2(I)):
                 yield [v] + rest
Beispiel #5
0
def process_pari_nf_v1(pari_nf, dmax=20, Detail=0):
    r"""
    Input is a dict with keys 'Nko' (N,k,chi_number), 'chipoly',  'SB' (Sturm bound), 'pari_newform',  'poly',  'ans',   'ALeigs', 'traces'

    Output adds 'traces' (unless already computed), and also 'eigdata' if 1<dimension<=dmax
    We do not yet use polredbest or optimize an coeffients
    """
    Nko = pari_nf['Nko']
    chipoly = pari_nf['chipoly']
    poly = pari_nf['poly']
    SB = pari_nf['SB']
    ALeigs = pari_nf['ALeigs']
    traces = pari_nf['traces']

    # initialize with data needing no more processing:

    newform = {
        'Nko': Nko,
        'chipoly': chipoly,
        'SB': SB,
        'ALeigs': ALeigs,
        'traces': traces
    }

    # Set the polynomial.  This is a polynomial in y, (just y if the
    # top degree is 1) with coefficients either integers (if the
    # bottom degree is 1) or polmods with modulus chipoly.  In all
    # cases rel_poly will be in Qchi[y].

    Qx = PolynomialRing(QQ, 'x')
    #pari_Qx_poly_to_sage = lambda f: Qx(gen_to_sage(f.Vecrev()))
    Qchi = NumberField(chipoly, 't')
    chi_degree = chipoly.degree()
    # NB the only reason for negating the chi_degree parameter here is to get around a bug in the Sage/pari interface
    pari_Qchi_to_sage = lambda elt: Qchi(
        gen_to_sage(elt.lift().Vecrev(-chi_degree)))
    Qchi_x = PolynomialRing(Qchi, 'x')
    pari_Qchix_poly_to_sage = lambda f: Qchi_x(
        [pari_Qchi_to_sage(co) for co in f.Vecrev()])

    rel_poly = pari_Qchix_poly_to_sage(poly)
    rel_degree = rel_poly.degree()

    newform['dim'] = dim = chi_degree * rel_degree
    small = (dmax == 0) or (dim <= dmax)

    # for 'small' spaces we compute more data, where 'small' means
    # dimension<=dmax (unless dmax==0 in which case all spaces are
    # deemed small).  However spaces of dimension 1 never need the
    # additional data.

    if Detail:
        print("{}: degree = {} = {}*{}".format(Nko, dim, chi_degree,
                                               rel_degree))
        if Detail > 1:
            print("rel_poly for {} is {}".format(Nko, rel_poly))

    # the newform will have its 'traces' field set already if it is
    # the only newform in its (N,k,chi)-newspace.  Otherwise we will
    # have set its 'ans' field and now compute the traces from that.
    # The 'ans' field will be None if we don't need the an, which is
    # if (1) the dimension is greater than dmax and (2) the
    # (N,k,chi)-newspace is irreducible.

    ans = pari_nf['ans']
    if Detail > 1: print("raw ans = {}".format(ans))

    # dimension 1 spaces: special case simpler traces, and no more to do:

    x = Qx.gen()
    if dim == 1:  # e.g. (11,2,1)[0]
        traces = gen_to_sage(ans)[1:]
        if newform['traces'] == None:
            newform['traces'] = traces
        newform['poly'] = x
        if Detail > 1: print("traces = {}".format(newform['traces']))
        return newform

    # All dimensions >1: traces

    if newform['traces'] == None:
        traces = [abstrace(an, dim) for an in ans][1:]
        # fix up trace(a_1)
        traces[0] = dim
        if Detail > 1: print("traces = {}".format(traces))
        newform['traces'] = traces

    # no more data required for non-small spaces:

    if not small:
        return newform

    if chi_degree == 1 or rel_degree == 1:  # e.g. (13,4,1)[1] or (25,2,4)[0] respectively

        # field is not relative, ans are t_POLMOD modulo pari_pol in y
        # or t, so if we lift them and take their coefficient vector
        # we'll get the coordinates w.r.t. a power basis for the field
        # defined by either rel_poly or chipoly.

        t0 = time.time()
        ancs = [gen_to_sage(an.lift().Vecrev(-dim)) for an in ans][1:]
        t1 = time.time()
        if Detail:
            print("time for converting an coeffs to QQ = {}".format(t1 - t0))
        basis = [[int(i == j) for j in range(dim)] for i in range(dim)]
        newform['poly'] = poly = Qx(rel_poly) if chi_degree == 1 else Qx(
            chipoly)

        if Detail > 1:
            print("Coefficient vectors of ans: {}".format(ancs))

        newform['eigdata'] = {
            'pol': poly.list(),
            'bas': basis,
            'n': 0,  # temporary
            'm': 0,  # temporary
            'ancs': ancs,
        }

        return newform

    # Now we are in the genuinely relative case where chi_degree>1 and rel_degree>1
    # e.g. (25,2,5)

    #Setting the Hecke field as a relative extension of Qchi and as an absolute field:

    t0 = time.time()
    Frel = Qchi.extension(rel_poly, 'b')
    abs_poly = Frel.absolute_polynomial()
    newform['poly'] = abs_poly(x)
    t1 = time.time()
    if Detail:
        print("absolute poly = {}".format(abs_poly))
        if Detail > 1:
            print("Time to construct Frel and find absolute poly = {}".format(
                t1 - t0))
    Fabs = Frel.absolute_field('a')
    rel2abs = Fabs.structure()[1]  # the isomorphism Frel --> Fabs
    z = rel2abs(Qchi.gen())
    y = rel2abs(Frel.gen())
    zpow = [z**i for i in range(chi_degree)]
    ypow = [y**j for j in range(rel_degree)]
    basis = sum([[(zpowi * ypowj).list() for zpowi in zpow] for ypowj in ypow],
                [])
    t2 = time.time()
    if Detail > 1:
        print("Time to construct Fabs and y,z in Fabs and basis matrix = {}".
              format(t2 - t1))

    #  Get coordinates of the an.  After lifting twice these are
    #  polynomials in Q[t][y] so simply extracting coefficient vectors
    #  gives their coordinates in terms of the basis z^i*y^j where
    #  Qchi=Q(z) and F=Qchi(y).  To relate these to the power basis of
    #  Fabs we only need the change of basis matrix whose rows give
    #  the power basis coefficients of each z^i*y^j (in the right
    #  order).

    ancs = [[
        gen_to_sage(c.lift().Vecrev(-chi_degree))
        for c in a.lift().Vecrev(-rel_degree)
    ] for a in ans][1:]
    t4 = time.time()
    if Detail > 1:
        print("Time to construct ancs) = {}".format(t4 - t2))
    ancs = [sum([anci for anci in anc], []) for anc in ancs]
    if Detail > 1:
        print("Coefficient vectors of ans: {}".format(ancs))

    newform['eigdata'] = {
        'pol': abs_poly.list(),
        'bas': basis,
        'n': 0,  # temporary
        'm': 0,  # temporary
        'ancs': ancs,
    }

    return newform
Beispiel #6
0
def process_pari_nf(pari_nf, dmax=20, Detail=0):
    r"""
    Input is a dict with keys 'Nko' (N,k,chi_number), 'chipoly',  'SB' (Sturm bound), 'pari_newform',  'poly',  'ans',   'ALeigs', 'traces'

    Output adds 'traces' (unless already computed), and also 'eigdata' if 1<dimension<=dmax
    We do not yet use polredbest or optimize an coeffients

    NB This must be called on  each newform *before* the GP process associated with the data has been terminated.

    """
    Nko = pari_nf['Nko']
    chipoly = pari_nf['chipoly']
    poly = pari_nf['poly']
    SB = pari_nf['SB']
    ALeigs = pari_nf['ALeigs']
    traces = pari_nf['traces']
    assert traces  # not None
    ans = pari_nf['ans']
    basis = pari_nf['basis']

    # initialize with data needing no more processing:

    newform = {
        'Nko': Nko,
        'chipoly': chipoly,
        'SB': SB,
        'ALeigs': ALeigs,
        'traces': traces
    }

    # Set the polynomial.  poly is the relative polynomial, in x (so
    # just x if the top degree is 1) with coefficients either integers
    # (if the bottom degree is 1) or polmods with modulus chipoly.
    #  rel_poly is in Qchi[x].

    Qx = PolynomialRing(QQ, 'x')
    #pari_Qx_poly_to_sage = lambda f: Qx(gen_to_sage(f.Vecrev()))
    Qchi = NumberField(chipoly, 't')
    chi_degree = chipoly.degree()
    # NB the only reason for negating the chi_degree parameter here is to get around a bug in the Sage/pari interface
    pari_Qchi_to_sage = lambda elt: Qchi(
        gen_to_sage(elt.lift().Vecrev(-chi_degree)))
    Qchi_x = PolynomialRing(Qchi, 'x')
    pari_Qchix_poly_to_sage = lambda f: Qchi_x(
        [pari_Qchi_to_sage(co) for co in f.Vecrev()])

    rel_poly = pari_Qchix_poly_to_sage(poly)
    rel_degree = rel_poly.degree()

    newform['dim'] = dim = chi_degree * rel_degree
    small = (dmax == 0) or (dim <= dmax)

    # for 'small' spaces we compute more data, where 'small' means
    # dimension<=dmax (unless dmax==0 in which case all spaces are
    # deemed small).  However spaces of dimension 1 never need the
    # additional data.

    if Detail:
        print("{}: degree = {} = {}*{}".format(Nko, dim, chi_degree,
                                               rel_degree))
        if Detail > 1:
            print("rel_poly for {} is {}".format(Nko, rel_poly))

    # The newform has its 'traces' field set already. We will have set
    # its 'ans' field where relevant (1<dim<=dmax) to a list of lists
    # of coefficients in Qchi.  In the genuinely relative case we'll
    # need to absolutise these.

    if Detail > 1: print("raw ans = {}".format(ans))

    # dimension 1 spaces: little to do

    if dim == 1:  # e.g. (11,2,1)[0]
        newform['poly'] = Qx.gen()
        return newform

    # no more data required for non-small spaces:

    if not small:
        return newform

    if chi_degree == 1:  # e.g. (13,4,1)[1]; now rel_degree>1
        # field is not relative, ans are lists of integers, coeffs w.r.t. basis
        t0 = time.time()
        ancs = [gen_to_sage(an) for an in ans]
        t1 = time.time()
        if Detail:
            print("time for converting an coeffs to QQ = {}".format(t1 - t0))
            if Detail > 1:
                print("Coefficient vectors of ans: {}".format(ancs))
        newform['poly'] = rel_poly
        # basis is a pari matrix over Q
        basis = gen_to_sage(basis)

        newform['eigdata'] = {
            'pol': rel_poly.list(),
            'bas': basis,
            'n': 0,  # temporary
            'm': 0,  # temporary
            'ancs': ancs,
        }

        return newform

    if rel_degree == 1:  # e.g. (25,2,4)[0]; now chi_degree>1

        # the field is not relative; ans is a lists of 1-lists of
        # t_POLMOD modulo a GP poly in t, so we lift them and take
        # their coefficient vector to get the coordinates w.r.t. a
        # power basis for the field defined by chipoly.

        t0 = time.time()
        ancs = [gen_to_sage(an[0].lift().Vecrev(-dim))
                for an in ans]  # list of lists of integers/rationals
        t1 = time.time()
        if Detail:
            print("time for converting an coeffs to QQ = {}".format(t1 - t0))
            if Detail > 1:
                print("Coefficient vectors of ans: {}".format(ancs))
        newform['poly'] = chipoly
        # basis is a 1x1 gp matrix over Qchi, so we want the power basis for Qchi: trivial
        basis = [[int(i == j) for j in range(dim)] for i in range(dim)]

        newform['eigdata'] = {
            'pol': chipoly.list(),
            'bas': basis,
            'n': 0,  # temporary
            'm': 0,  # temporary
            'ancs': ancs,
        }

        return newform

    # Now we are in the genuinely relative case where chi_degree>1 and rel_degree>1
    # e.g. (25,2,5)

    # Now ans is a (python) list of nan (GP) lists of d_rel elements
    # of Qchi, and basis is a GP d_rel x d_rel matrix over Qchi

    #Setting the Hecke field as a relative extension of Qchi and as an absolute field:

    t0 = time.time()
    Frel = Qchi.extension(rel_poly, 'b')
    newform['poly'] = abs_poly = Frel.absolute_polynomial()(Qx.gen())
    t1 = time.time()
    if Detail:
        print("absolute poly = {}".format(abs_poly))
        if Detail > 1:
            print("Frel = {}".format(Frel))
            print("Time to construct Frel and find absolute poly = {}".format(
                t1 - t0))
    Fabs = Frel.absolute_field('a')
    if Detail > 1:
        print("Fabs = {}".format(Fabs))
    rel2abs = Fabs.structure()[1]  # the isomorphism Frel --> Fabs
    z = rel2abs(Qchi.gen())
    zpow = [z**i for i in range(chi_degree)]
    # convert basis to a Sage list of lists of elements of Qchi:
    our_basis_coeffs = [[
        pari_Qchi_to_sage(basis[i, j]) for j in range(rel_degree)
    ] for i in range(rel_degree)]
    #print("our basis coeffs: {} (parent {})".format(our_basis_coeffs, our_basis_coeffs[0][0].parent()))
    our_basis_rel = [Frel(b) for b in our_basis_coeffs]
    #print("our basis (Sage, relative): {}".format(our_basis_rel))
    our_basis_abs = [rel2abs(b) for b in our_basis_rel]
    #print("our basis (Sage, absolute): {}".format(our_basis_abs))
    basis = sum([[(zpowi * yj).list() for zpowi in zpow]
                 for yj in our_basis_abs], [])
    #print("basis (Sage, matrix/Q): {}".format(basis))
    t2 = time.time()
    if Detail > 1:
        print("Time to construct Fabs and y,z in Fabs and basis matrix = {}".
              format(t2 - t1))

    #  Convert coordinates of the an.  After lifting these are lists
    #  of lists of polynomials in Q[t] so simply extracting
    #  coefficient vectors gives their coordinates in terms of the
    #  basis z^i*y_j where Qchi=Q(z) and [y_1,...,y_d_rel] is the
    #  Qchi-basis of Frel.  To relate these to the power basis of Fabs
    #  we only need the change of basis matrix whose rows give the
    #  power basis coefficients of each z^i*y_j (in the right order).

    ancs = [[gen_to_sage(c.lift().Vecrev(-chi_degree)) for c in an]
            for an in ans]
    t4 = time.time()
    if Detail > 1:
        print("Time to construct ancs) = {}".format(t4 - t2))
    ancs = [sum([anci for anci in anc], []) for anc in ancs]
    if Detail > 1:
        print("Coefficient vectors of ans: {}".format(ancs))

    newform['eigdata'] = {
        'pol': abs_poly.list(),
        'bas': basis,
        'n': 0,  # temporary
        'm': 0,  # temporary
        'ancs': ancs,
    }

    return newform
Beispiel #7
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 #8
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 #9
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)]