예제 #1
0
    def _compute_echelon(self):
        A = Matrix(self.parent(),
                   self.A.rows())  # we create a copy of the matrix
        U = identity_matrix(self.parent(), A.nrows())

        if (self.have_ideal):  # we do simplifications
            A = self.simplify(A)

        ## Step 1: initialize
        r = 0
        c = 0  # we look from the position (r,c)
        while (r < A.nrows() and c < A.ncols()):
            ir = self.__find_pivot(A, r, c)
            A = self.simplify(A)
            U = self.simplify(U)  # we simplify in case relations pop up

            if (ir != None):  # we found a pivot
                # We do the swapping (if needed)
                if (ir != r):
                    A.swap_rows(r, ir)
                    U.swap_rows(r, ir)

                # We do the bareiss step
                Arc = A[r][c]
                Arows = A.rows()
                Urows = U.rows()
                for i in range(r):  # we create zeros on top of the pivot
                    Aic = A[i][c]
                    A.set_row(i, Arc * Arows[i] - Aic * Arows[r])
                    U.set_row(i, Arc * Urows[i] - Aic * Urows[r])

                # We then leave the row r without change
                for i in range(r + 1,
                               A.nrows()):  # we create zeros below the pivot
                    Aic = A[i][c]
                    A.set_row(i, Aic * Arows[r] - Arc * Arows[i])
                    U.set_row(i, Aic * Urows[r] - Arc * Urows[i])

                r += 1
                c += 1

            else:  # no pivot then only advance in column
                c += 1

        # We finish simplifying the gcds in each row
        gcds = [gcd(row) for row in A]
        T = diagonal_matrix([1 / el if el != 0 else 1 for el in gcds])
        A = (T * A).change_ring(self.parent())
        U = T * U
        return A, U
예제 #2
0
def solve_vectors(n,d, verbose=False):
   def w(i,j):
      return 0 if i==j else (d[Set([i,j])] + d[Set([i])] + d[Set([j])])
   W = Matrix(GF(2),[[w(i,j) for j in range(n)] for i in range(n)])
   v = vector(GF(2),[d[Set([i])] for i in range(n)])
   if verbose:
      print("W = {}".format(W))
      print("v = {}".format(v))
   if W==0:
      if v==0:
         return 0
      else:
         return v, v

   Wrows = [wr for wr in W.rows() if wr]
   if v==0:
      x = Wrows[0]
      y = next(wr for wr in Wrows[1:] if wr!=x)
      return x, y

   z = W.row(v.support()[0])
   y = next(wr for wr in Wrows if wr!=z)
   return y+z, y
예제 #3
0
def add_trace_and_norm_ladic(g, D, alpha_geo, verbose=True):
    if verbose:
        print "add_trace_and_norm_ladic()"
    #load Fields
    L = D['L']
    if L is QQ:
        QQx = PolynomialRing(QQ, "x")
        L = NumberField(QQx.gen(), "b")

    prec = D['prec']
    CCap = ComplexField(prec)

    # load endo
    alpha = D['alpha']
    rosati = bound_rosati(alpha_geo)

    if alpha.base_ring() is not L:
        alpha_K = copy(alpha)
        alpha = Matrix(L, 2, 2)
        #shift alpha field from K to L
        for i, row in enumerate(alpha_K.rows()):
            for j, elt in enumerate(row):
                if elt not in L:
                    assert elt.base_ring().absolute_polynomial(
                    ) == L.absolute_polynomial()
                    alpha[i, j] = L(elt.list())
                else:
                    alpha[i, j] = L(elt)

    # load algx_poly
    algx_poly_coeff = D['algx_poly']

    #sometimes, by mistake the algx_poly is defined over K where K == L, but with a different name
    for i, elt in enumerate(algx_poly_coeff):
        if elt not in L:
            assert elt.base_ring().absolute_polynomial(
            ) == L.absolute_polynomial()
            algx_poly_coeff[i] = L(elt.list())
        else:
            algx_poly_coeff[i] = L(elt)

    x_poly = vector(CCap, D['x_poly'])
    for i in [0, 1]:
        assert almost_equal(
            x_poly[i],
            algx_poly_coeff[i]), "%s != %s" % (algx_poly_coeff[i], x_poly[i])

    # load P
    P0 = vector(L, [D['P'][0], D['P'][1]])
    for i, elt in enumerate(P0):
        if elt not in L:
            assert elt.base_ring().absolute_polynomial(
            ) == L.absolute_polynomial()
            P0[i] = L(elt.list())
        else:
            P0[i] = L(elt)
    if verbose:
        print "P0 = %s" % (P0, )

    # load image points, P1 and P2

    L_poly = PolynomialRing(L, "xL")
    xL = L_poly.gen()

    Xpoly = L_poly(algx_poly_coeff)
    if Xpoly.is_irreducible():
        M = Xpoly.root_field("c")
    else:
        # this avoids bifurcation later on in the code, we don't want to be always checking if M is L
        M = NumberField(xL, "c")

    # trying to be sure that we keep the same complex_embedding...
    M_complex_embedding = 0
    if L.gen() not in QQ:
        M_complex_embedding = None
        Lgen_CC = toCCap(L.gen(), prec=prec)
        for i, _ in enumerate(M.complex_embeddings()):
            if norm(Lgen_CC - M(L.gen()).complex_embedding(prec=prec, i=i)
                    ) < CCap(2)**(-0.7 * Lgen_CC.prec()) * Lgen_CC.abs():
                M_complex_embedding = i

        assert M_complex_embedding is not None, "\nL = %s\n%s = %s\n%s" % (
            L, L.gen(), Lgen_CC, M.complex_embeddings())

    M_poly = PolynomialRing(M, "xM")
    xM = M_poly.gen()

    # convert everything to M
    P0_M = vector(M, [elt for elt in P0])
    alpha_M = Matrix(M, [[elt for elt in row] for row in alpha.rows()])
    Xpoly_M = M_poly(Xpoly)

    for i in [0, 1]:
        assert almost_equal(x_poly[i],
                            Xpoly_M.list()[i],
                            ithcomplex_embedding=M_complex_embedding
                            ), "%s != %s" % (Xpoly_M.list()[i], x_poly[i])

    P1 = vector(M, 2)
    P1_ap = vector(CCap, D['R'][0])
    P2 = vector(M, 2)
    P2_ap = vector(CCap, D['R'][1])

    M_Xpoly_roots = Xpoly_M.roots()
    assert len(M_Xpoly_roots) > 0

    Ypoly_M = prod([xM**2 - g(root)
                    for root, _ in M_Xpoly_roots])  # also \in L_poly

    assert sum(m for _, m in Ypoly_M.roots(M)) == Ypoly_M.degree(
    ), "%s != %s\n%s\n%s" % (sum(m for _, m in Ypoly_M.roots(M)),
                             Ypoly_M.degree(), Ypoly_M, Ypoly_M.roots(M))

    if len(M_Xpoly_roots) == 1:
        # we have a double root
        P1[0] = M_Xpoly_roots[0][0]
        P2[0] = M_Xpoly_roots[0][0]
        ae_prec = prec * 0.4
    else:
        assert len(M_Xpoly_roots) == 2
        ae_prec = prec
        # we have two distinct roots
        P1[0] = M_Xpoly_roots[0][0]
        P2[0] = M_Xpoly_roots[1][0]
        if not_equal(P1_ap[0], P1[0],
                     ithcomplex_embedding=M_complex_embedding):
            P1[0] = M_Xpoly_roots[1][0]
            P2[0] = M_Xpoly_roots[0][0]

    assert almost_equal(
        P1_ap[0],
        P1[0],
        ithcomplex_embedding=M_complex_embedding,
        prec=ae_prec), "\n%s = %s \n != %s" % (
            P1[0], toCCap(
                P1[0], ithcomplex_embedding=M_complex_embedding), CC(P1_ap[0]))
    assert almost_equal(
        P2_ap[0],
        P2[0],
        ithcomplex_embedding=M_complex_embedding,
        prec=ae_prec), "\n%s = %s \n != %s" % (
            P2[0], toCCap(
                P2[0], ithcomplex_embedding=M_complex_embedding), CC(P2_ap[0]))

    # figure out the right square root

    # pick the default branch
    P1[1] = sqrt(g(P1[0]))
    P2[1] = sqrt(g(P2[0]))

    if 0 in [P1[1], P2[1]]:
        print "one of image points is a Weirstrass point"
        print P1
        print P2
        raise ZeroDivisionError

    #switch if necessary
    if not_equal(P1_ap[1],
                 P1[1],
                 ithcomplex_embedding=M_complex_embedding,
                 prec=ae_prec):
        P1[1] *= -1

    if not_equal(P2_ap[1],
                 P2[1],
                 ithcomplex_embedding=M_complex_embedding,
                 prec=ae_prec):
        P2[1] *= -1

    # double check
    for i in [0, 1]:
        assert almost_equal(P1_ap[i],
                            P1[i],
                            ithcomplex_embedding=M_complex_embedding,
                            prec=ae_prec), "%s != %s" % (P1_ap[i], P1[i])
        assert almost_equal(P2_ap[i],
                            P2[i],
                            ithcomplex_embedding=M_complex_embedding,
                            prec=ae_prec), "%s != %s" % (P2_ap[i], P2[i])

    # now alpha, P0 \in L
    # P1, P2 \in L

    if verbose:
        print "P1 = %s\nP2 = %s" % (P1, P2)
        print "Computing the trace and the norm ladically\n"
        trace_and_norm = trace_and_norm_ladic(L,
                                              M,
                                              P0_M,
                                              P1,
                                              P2,
                                              g,
                                              2 * alpha_M,
                                              16 * rosati,
                                              primes=ceil(prec * L.degree() /
                                                          61))
    else:
        trace_and_norm = trace_and_norm_ladic(L,
                                              M,
                                              P0_M,
                                              P1,
                                              P2,
                                              g,
                                              2 * alpha_M,
                                              16 * rosati,
                                              primes=ceil(prec * L.degree() /
                                                          61))

    # Convert the coefficients to polynomials
    trace_numerator, trace_denominator, norm_numerator, norm_denominator = [
        L_poly(coeff) for coeff in trace_and_norm
    ]

    assert trace_numerator(P0[0]) == trace_denominator(
        P0[0]) * -algx_poly_coeff[1], "%s/%s (%s) != %s" % (
            trace_numerator, trace_denominator, P0[0], -algx_poly_coeff[1])
    assert norm_numerator(P0[0]) == norm_denominator(
        P0[0]) * algx_poly_coeff[0], "%s/%s (%s) != %s" % (
            norm_numerator, norm_denominator, P0[0], algx_poly_coeff[0])
    buffer = "# x1 + x2 = degree %d/ degree %d\n" % (
        trace_numerator.degree(), trace_denominator.degree())
    buffer += "# = (%s) / (%s) \n" % (trace_numerator, trace_denominator)
    buffer += "# max(%d, %d) <= %d\n\n" % (
        trace_numerator.degree(), trace_denominator.degree(), 16 * rosati)

    buffer += "# x1 * x2 = degree %d/ degree %d\n" % (
        norm_numerator.degree(), norm_denominator.degree())
    buffer += "# = (%s) / (%s) \n" % (norm_numerator, norm_denominator)
    buffer += "# max(%d, %d) <= %d\n" % (
        norm_numerator.degree(), norm_denominator.degree(), 16 * rosati)

    if verbose:
        print buffer
        print "\n"
    assert max(trace_numerator.degree(),
               trace_denominator.degree()) <= 16 * rosati
    assert max(norm_numerator.degree(),
               norm_denominator.degree()) <= 16 * rosati

    if verbose:
        print "Veritfying if x1*x2 and x1 + x2 are correct..."

    verified = verify_algebraically(g,
                                    P0,
                                    alpha,
                                    trace_and_norm,
                                    verbose=verbose)
    if verbose:
        print "\nDoes it act on the tangent space as expected? %s\n" % verified
        print "Done add_trace_and_norm_ladic()"

    return verified, [
        trace_numerator.list(),
        trace_denominator.list(),
        norm_numerator.list(),
        norm_denominator.list()
    ]
예제 #4
0
def algo64(K, S, BB, T2=None, unit_first = True, verbose=False):
   r = 1+len(S)
   if T2 is None:
      T2 = get_T2(QQ,S, unit_first)
      if verbose:
         print("T2 = {}".format(T2))
   assert len(T2)==r*(r+1)//2

   from KSp import IdealGenerator
   Sx = [IdealGenerator(P) for P in S]
   u = -1 if K==QQ else  K(K.unit_group().torsion_generator())
   Sx = [u] + Sx if unit_first else Sx+[u]
   if verbose:
      print("Basis for K(S,2): {}".format(Sx))

   #BBdict = dict((k,BB(T2[k])) for k in T2)
   ap = BB_trace(BB)
   apdict = dict((k,ap(T2[k])) for k in T2)
   t4 = BB_t4(BB)
   t4dict = dict((k,t4(T2[k])) for k in T2)
   if verbose:
      print("apdict = {}".format(apdict))
      print("t4dict = {}".format(t4dict))

   v = vector(GF(2),[t4dict[Set([i])] for i in range(r)])
   if verbose:
      print("v = {}".format(v))

   def w(i,j):
      if i==j:
         return 0
      else:
         return (t4dict[Set([i,j])] + t4dict[Set([i])] + t4dict[Set([j])])

   # Note that W ignores the first coordinate
   Wd = Matrix(GF(2),[[w(i,j) for j in range(1,r)] for i in range(1,r)])
   vd = vector(v.list()[1:])
   rkWd = Wd.rank()
   if verbose:
      print("W' = \n{} with rank {}".format(Wd,rkWd))
   # Case 1: rank(W)=2
   if rkWd==2:
      # x' and y' are any two distinct nonzero rows of W
      Wrows = [wr for wr in Wd.rows() if wr]
      xd = Wrows[0]
      yd = next(wr for wr in Wrows if wr!=xd)
      zd = xd+yd
      ud = vd - vector(xi*yi for xi,yi in zip(list(xd),list(yd)))
      if verbose:
         print("x' = {}".format(xd))
         print("y' = {}".format(yd))
         print("z' = {}".format(zd))
         print("u' = {}".format(ud))
         print("v' = {}".format(vd))

      u = vector([1]+ud.list())
      v = vector([0]+vd.list())

      if t4dict[Set([0])]==1:
         x = vector([1]+xd.list())
         y = vector([1]+yd.list())
         z = vector([1]+zd.list())
         if verbose:
            print("x = {}".format(x))
            print("y = {}".format(y))
            print("z = {}".format(z))
            print("u = {}".format(u))
            print("v = {}".format(v))
      else:
         raise NotImplementedError("t_4(p_1) case not yet implemented in algo64")

      return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]]

   # W==0
   raise NotImplementedError("rank(W)=0 case not yet implemented in algo64")
예제 #5
0
def algo63(K, S, BB, T2=None, unit_first = True, verbose=False):
   r = 1+len(S)
   if T2 is None:
      T2 = get_T2(QQ,S, unit_first)
      if verbose:
         print("T2 = {}".format(T2))
   assert len(T2)==r*(r+1)//2

   from KSp import IdealGenerator
   Sx = [IdealGenerator(P) for P in S]
   u = -1 if K==QQ else  K(K.unit_group().torsion_generator())
   Sx = [u] + Sx if unit_first else Sx+[u]
   if verbose:
      print("Basis for K(S,2): {}".format(Sx))

   BBdict = dict((k,BB(T2[k])) for k in T2)
   ap = BB_trace(BB)
   apdict = dict((k,ap(T2[k])) for k in T2)
   t2 = BB_t2(BB)
   t2dict = dict((k,t2(T2[k])) for k in T2)
   if verbose:
      print("apdict = {}".format(apdict))
      print("t2dict = {}".format(t2dict))

   v = vector(GF(2),[t2dict[Set([i])] for i in range(r)])
   if verbose:
      print("v = {}".format(v))

   def w(i,j):
      if i==j:
         return 0
      else:
         return (t2dict[Set([i,j])] + t2dict[Set([i])] + t2dict[Set([j])])

   W = Matrix(GF(2),[[w(i,j) for j in range(r)] for i in range(r)])
   rkW = W.rank()
   if verbose:
      print("W = \n{} with rank {}".format(W,rkW))
   # Case 1: rank(W)=2
   if rkW==2:
      # x and y are any two distinct nonzero rows of W
      Wrows = [wr for wr in W.rows() if wr]
      x = Wrows[0]
      y = next(wr for wr in Wrows if wr!=x)
      z = x+y
      u = v - vector(xi*yi for xi,yi in zip(list(x),list(y)))
      if verbose:
         print("x = {}".format(x))
         print("y = {}".format(y))
         print("z = {}".format(z))
         print("u = {}".format(u))
   else: # W==0
      # y=0, x=z
      u = v
      y = u-u # zero vector
      if verbose:
         print("u = {}".format(u))
         print("y = {}".format(y))
      t3dict = {}
      for k in T2:
         t = 1 if t2dict[k]==0 else -1
         t3dict[k] = (BBdict[k](t)//8)%2
      s = solve_vectors(r,t3dict)
      if not s:
         z = x = y # = 0
         if verbose:
            print("x and  y are both zero, so class has >4 vertices")
      else:
         x, _ = s
         z = x
         if verbose:
            print("x = {}".format(x))
            print("y = {}".format(y))
            print("z = {}".format(z))

   return [vec_to_disc(Sx,vec) for vec in [u,x,y,z]]
예제 #6
0
def compute_alpha_point(g,
                        iaj,
                        alpha,
                        P0,
                        digits,
                        power,
                        verbose,
                        aggressive=True,
                        append=""):
    # input:
    # * g, defining polynomial of the hyperelliptic curve
    # * iaj = InvertAJglobal class
    # * alpha = analytic representation of the endomorphism acting on the tangent space
    # * digits = how many digits to work with
    # * power, we will divide by 2**power before inverting the abel jacobi map
    # * P0, a point in the curve for which we will compute alpha*2(P - \infty) = P1 + P2 - \infty
    # * verbose
    # * agressive, raise ZeroDivisionError  if we get a P1[0] = P2[0] or one of the points is infty
    # * append, a string to append to the numberfield generators
    #
    # output: a dictionary with the following keys
    # TODO add the keys

    output = {}
    K = alpha.base_ring()
    CCap = iaj.C
    prec = CCap.precision()
    output['prec'] = prec
    x0, y0 = P0
    Kz = PolynomialRing(K, "z")
    z = Kz.gen()
    if verbose:
        print "compute_alpha_point()"
        print "P0 = %s" % (P0, )
    #deal with the field of definition
    if y0 in K:
        if K is QQ:
            L = K
            from_K_to_L = QQ.hom(1, QQ)
        else:
            L = K.change_names("b" + append)
            from_K_to_L = L.structure()[1]
    else:
        L, from_K_to_L = (z**2 - g(x0)).splitting_field("b" + append,
                                                        simplify_all=True,
                                                        map=True)

    output['L'] = L
    #    output['L_str'] = sage_str_numberfield(L, 'x','b'+append);
    output['from_K_to_L'] = from_K_to_L
    #    output['L_gen'] =  toCCap(L.gen(), 53);

    # figure out y0 in L
    y0_ap = toCCap(y0, prec)
    y0s = [elt for elt, _ in (z**2 - g(x0)).roots(L)]
    assert len(y0s) == 2
    y0s_ap = [toCCap(elt, prec) for elt in y0s]
    if norm(y0_ap - y0s_ap[0]) < norm(y0_ap - y0s_ap[1]):
        y0 = y0s[0]
    else:
        y0 = y0s[1]

    P0 = vector(L, [x0, y0])

    alpha_L = Matrix(L, [[from_K_to_L(elt) for elt in row]
                         for row in alpha.rows()])
    alpha_ap = Matrix(CCap, [toCCap_list(row, prec) for row in alpha_L.rows()])

    output['P'] = P0
    output['alpha'] = alpha_L

    if verbose:
        print "L = %s" % L
        print "%s = %s" % (L.gen(), toCCap(L.gen(), 53))
        print "P0 = %s" % (P0, )
        print "alpha = %s" % ([[elt for elt in row]
                               for row in alpha_L.rows()], )

    P0_ap = vector(CCap, toCCap_list(P0, prec + 192))

    if verbose:
        print "P0_ap = %s" % (vector(CC, P0_ap), )

    if verbose:
        print "Computing AJ of P0..."
        c, w = cputime(), walltime()
        ajP0 = vector(CCap, AJ1_digits(g, P0_ap, digits))
        print "Time: CPU %.2f s, Wall: %.2f s" % (
            cputime(c),
            walltime(w),
        )
        print
    else:
        ajP0 = vector(CCap, AJ1_digits(g, P0_ap, digits))

    output['ajP'] = ajP0

    aj2P0 = 2 * ajP0
    alpha2P0_an = alpha_ap * aj2P0
    if verbose:
        print "Working over %s" % CCap

    invertAJ_tries = 3
    for i in range(invertAJ_tries):
        #try invertAJ_tries times to invertAJ
        try:
            if verbose:
                print "\n\ninverting AJ..."
                c, w = cputime(), walltime()
                alpha2P0_div = iaj.invertAJ(alpha2P0_an, power)
                print "Time: CPU %.2f s, Wall: %.2f s" % (
                    cputime(c),
                    walltime(w),
                )
                print "\n\n"
            else:
                alpha2P0_div = iaj.invertAJ(alpha2P0_an, power)
            break
        except AssertionError as error:
            print error
            if verbose:
                print "an assertion failed while inverting AJ.."
            if i == invertAJ_tries - 1:
                if verbose:
                    print "retrying with a new P0"
                    print
                raise ZeroDivisionError
            else:
                iaj.iajlocal.set_basepoints()
                if verbose:
                    print "retrying again with a new set of base points"

    if verbose:
        print "Computing the Mumford coordinates of alpha(2*P0 - 2*W)"
        c, w = cputime(), walltime()
        R0, R1 = alpha2P0_div.coordinates()
        print "Time: CPU %.2f s, Wall: %.2f s" % (
            cputime(c),
            walltime(w),
        )
    else:
        R0, R1 = alpha2P0_div.coordinates()

    points = [R0, R1]
    x_poly = alpha2P0_div.x_coordinates()
    output['R'] = points
    output['x_poly'] = x_poly

    if (R0 in [+Infinity, -Infinity]) or (R1 in [+Infinity, -Infinity]):
        if aggressive:
            # we want to avoid these situations
            if verbose:
                print "One of the coordinates is at infinity"
                if R0 in [+Infinity, -Infinity]:
                    print "R0 = %s" % (R0, )
                else:
                    print "R1 = %s" % (R1, )
                print "retrying with a new P0"
                print
            raise ZeroDivisionError
        else:
            return output

    buffer = "# R0 = %s\n" % (vector(CC, R0), )
    buffer += "# R1 = %s\n" % (vector(CC, R1), )
    buffer += "# and \n# x_poly = %s\n" % (vector(CC, x_poly), )

    if verbose:
        print buffer
    assert len(x_poly) == 3

    algx_poly = [NF_embedding(coeff, L) for coeff in x_poly]
    buffer = "algx_poly = %s;\n" % (algx_poly, )
    if L != QQ:
        buffer += "#where %s ~ %s\n" % (L.gen(), L.gen().complex_embedding())
    buffer += "\n"
    if verbose:
        print buffer
        sys.stdout.flush()
        sys.stderr.flush()

    output['algx_poly'] = algx_poly

    if None in algx_poly:
        if aggressive:
            if verbose:
                print "No algebraic expression  for the polynomial"
                print "retrying with a new P0"
                sys.stdout.flush()
                sys.stderr.flush()
            raise ZeroDivisionError
        else:
            return output
    #c, b, a = algx_poly
    #if aggressive and b**2 - 4*a*c == 0:
    #    raise ZeroDivisionError
    if verbose:
        print "Done compute_alpha_point()"
    return output
예제 #7
0
def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a = 1):
    """
    INPUT:
        - ``frob_matrix`` -- a matrix representing the p-power Frobenius lift to Z_q up to some precision
        - ``charpoly_prec`` -- a vector ai, such that, frob_matrix.change_ring(ZZ).charpoly()[i] will be correct mod p^ai, this can be easily deduced from the hodge numbers and knowing the q-adic precision of frob_matrix
        - ``p`` -- prime p
        - ``weight`` -- weight of the motive
        - ``a`` -- q = q^a

    OUTPUT:
        a list of integers corresponding to the characteristic polynomial of the Frobenius action

    Examples:
    sage: M = Matrix([[O(17), 8 + O(17)], [O(17), 15 + O(17)]])
    sage: charpoly_frobenius(M, [2, 1, 1], 17, 1, 1)
        [17, 2, 1]

    sage: R = Zq(17 ** 2 , names=('a',));
    sage: M = Matrix(R, [[8*17 + 16*17**2 + O(17**3), 8 + 11*17 + O(17**2)], [7*17**2 + O(17**3), 15 + 8*17 + O(17**2)]])
    sage: charpoly_frobenius(M, [3, 2, 2], 17, 1, 2)
        [289, 30, 1]

    sage: M = Matrix([[8*31 + 8*31**2 + O(31**3), O(31**3), O(31**3), O(31**3)], [O(31**3), 23*31 + 22*31**2 + O(31**3), O(31**3), O(31**3)], [O(31**3), O(31**3), 27 + 7*31 + O(31**3), O(31**3)], [O(31**3), O(31**3), O(31**3), 4 + 23*31 + O(31**3)]])
    sage: charpoly_frobenius(M, [4, 3, 2, 2, 2], 31, 1, 1)
        [961, 0, 46, 0, 1]

    sage: M = Matrix([[4*43**2 + O(43**3), 17*43 + 11*43**2 + O(43**3), O(43**3), O(43**3), 17 + 37*43 + O(43**3), O(43**3)], [30*43 + 23*43**2 + O(43**3), 5*43 + O(43**3), O(43**3), O(43**3), 3 + 38*43 + O(43**3), O(43**3)], [O(43**3), O(43**3), 9*43 + 32*43**2 + O(43**3), 13 + 25*43 + O(43**3), O(43**3), 17 + 18*43 + O(43**3)], [O(43**3), O(43**3), 22*43 + 25*43**2 + O(43**3), 11 + 24*43 + O(43**3), O(43**3), 36 + 5*43 + O(43**3)], [42*43 + 15*43**2 + O(43**3), 22*43 + 8*43**2 + O(43**3), O(43**3), O(43**3), 29 + 4*43 + O(43**3), O(43**3)], [O(43**3), O(43**3), 6*43 + 19*43**2 + O(43**3), 8 + 24*43 + O(43**3), O(43**3), 31 + 42*43 + O(43**3)]])
    sage: charpoly_frobenius(M, [5, 4, 3, 2, 2, 2, 2], 43, 1, 1)
        [79507, 27735, 6579, 1258, 153, 15, 1]

    """
    if a > 1:
        F = frob_matrix
        sigmaF = F;
        for _ in range(a - 1):
            sigmaF = Matrix(F.base_ring(), [[elt.frobenius() for elt in row] for row in sigmaF.rows()])
            F = F * sigmaF
        F = F.change_ring(ZZ)
    else:
        F = frob_matrix.change_ring(ZZ)
    cp = F.charpoly().list();
    
    assert len(charpoly_prec) == len(cp)
    assert cp[-1] == 1;
    
    # reduce cp mod prec
    degree = F.nrows()
    mod = [0] * (degree + 1)
    for i in range(degree):
        mod[i] = p**charpoly_prec[i]
        cp[i] = cp[i] % mod[i]
    
    
    # figure out the sign
    
    if weight % 2 == 1:
        # for odd weight the sign is always 1
        # it's the charpoly of a USp matrix
        # and charpoly of a symplectic matrix is reciprocal
        sign = 1
    else:
        for i in range(degree/2):
            p_power = p ** min( charpoly_prec[i], charpoly_prec[degree - i] + (a*(degree - 2*i)*weight/2)); 
            # Note: degree*weight = 0 mod 2
            if cp[i] % p_power != 0 and cp[degree-i] % p_power != 0:
                if 0 == (cp[i] + cp[degree - i] * p**(a*(degree-2*i)*weight/2)) %  p_power:
                    sign = -1;
                else:
                    sign = 1;
                assert 0 == (-sign*cp[i] + cp[degree - i] * p**(a*(degree-2*i)*weight/2)) %  p_power;
                break;
    cp[0] = sign * p**(a*degree*weight/2)
    
    #calculate the i-th power sum of the roots and correct cp allong the way
    halfdegree = ceil(degree/2) + 1;
    e = [None]*(halfdegree)
    for k in range(halfdegree):
        e[k] = cp[degree - k] if (k%2 ==0) else -cp[degree - k]
        if k > 0:
            # verify if p^charpoly_prec[degree - k] > 2*degree/k * q^(w*k/2)
            assert log(k)/log(p) + charpoly_prec[degree - k] > log(2*degree)/log(p) + a*0.5*weight*k, "log(k)/log(p) + charpoly_prec[degree - k] <= log(2*degree)/log(p) + a*0.5*weight*k, k = %d" % k
    #e[k] = \sum x_{i_1} x_{i_2} ... x_{i_k} # where x_* are eigenvalues
    # and i_1 < i_2 ... < i_k
    
    #s[k] = \sum x_i ^k for i>0
    s = [None]*(halfdegree)
    for k in range(1, halfdegree):
        # assume that s[i] and e[i] are correct for i < k
        # e[k] correct modulo mod[degree - k]
        # S = sum (-1)^i e[k-i] * s[i]
        # s[k] = (-1)^(k-1) (k*e[k] + S) ==> (-1)^(k-1) s[k] - S = k*e[k] 
        S = sum( (-1)**i * e[k-i] * s[i] for i in range(1,k))
        s[k] = (-1)**(k - 1) * (S + k*e[k])
        #hence s[k] is correct modulo k*mod[degree - k] 
        localmod = k*mod[degree - k]
        s[k] = s[k] % localmod
        
        # |x_i| = p^(w*0.5)
        # => s[k] <= degree*p^(a*w*k*0.5)
        # recall, 2*degree*p^(a*w*k*0.5) /k < mod[degree - k] 
        if s[k] > degree*p**(a*weight*k*0.5) :
            s[k] = -(-s[k] % localmod);
        
        #now correct e[k] with:
        # (-1)^(k-1) s[k] - S = k*e[k] 
        e[k] = (-S + (-1)**(k - 1) * s[k])//k;
        assert (-S + (-1)**(k - 1) * s[k])%k == 0
        cp[degree - k] = e[k] if k % 2 == 0 else -e[k]
        cp[k] = sign*cp[degree - k]*p**(a*(degree-2*k)*weight/2)
    return cp