def _frobenius_matrix(self, N=None):
        """
        Compute p-adic frobenius matrix to precision p^N. If N not supplied,
        a default value is selected, which is the minimum needed to recover
        the charpoly unambiguously.

        Currently only implemented using hypellfrob, which means only works
        over GF(p^1), and must have p > (2g+1)(2N-1).

        TESTS::

            sage: R.<t> = PolynomialRing(GF(37))
            sage: H = HyperellipticCurve(t^5 + t + 2)
            sage: H._frobenius_matrix()
            [1258 + O(37^2)  925 + O(37^2)  132 + O(37^2)  587 + O(37^2)]
            [1147 + O(37^2)  814 + O(37^2)  241 + O(37^2) 1011 + O(37^2)]
            [1258 + O(37^2) 1184 + O(37^2) 1105 + O(37^2)  482 + O(37^2)]
            [1073 + O(37^2)  999 + O(37^2)  772 + O(37^2)  929 + O(37^2)]

        """
        p = self.base_ring().characteristic()
        f, h = self.hyperelliptic_polynomials()
        if h != 0:
            # need y^2 = f(x)
            raise NotImplementedError, "only implemented for curves y^2 = f(x)"

        sign = 1
        if not f.is_monic():
            # at this time we need a monic f
            c = f.leading_coefficient()
            f = f / c
            if c.is_square():
                # solutions of $y^2 = c * f(x)$ correspond naturally to
                # solutions of $(sqrt(c) y)^2 = f(x)$
                pass
            else:
                # we'll count points on a twist and then correct by untwisting...
                sign = -1
        assert f.is_monic()

        if N is None:
            N = self._frobenius_coefficient_bound()

        matrix_of_frobenius = hypellfrob(p, N, f)
        matrix_of_frobenius = sign * matrix_of_frobenius
        return matrix_of_frobenius
    def _frobenius_matrix(self, N=None):
        """
        Compute p-adic frobenius matrix to precision p^N. If N not supplied,
        a default value is selected, which is the minimum needed to recover
        the charpoly unambiguously.

        Currently only implemented using hypellfrob, which means only works
        over GF(p^1), and must have p > (2g+1)(2N-1).

        TESTS::

            sage: R.<t> = PolynomialRing(GF(37))
            sage: H = HyperellipticCurve(t^5 + t + 2)
            sage: H._frobenius_matrix()
            [1258 + O(37^2)  925 + O(37^2)  132 + O(37^2)  587 + O(37^2)]
            [1147 + O(37^2)  814 + O(37^2)  241 + O(37^2) 1011 + O(37^2)]
            [1258 + O(37^2) 1184 + O(37^2) 1105 + O(37^2)  482 + O(37^2)]
            [1073 + O(37^2)  999 + O(37^2)  772 + O(37^2)  929 + O(37^2)]

        """
        p = self.base_ring().characteristic()
        f, h = self.hyperelliptic_polynomials()
        if h != 0:
            # need y^2 = f(x)
            raise NotImplementedError, "only implemented for curves y^2 = f(x)"

        sign = 1
        if not f.is_monic():
            # at this time we need a monic f
            c = f.leading_coefficient()
            f = f / c
            if c.is_square():
                # solutions of $y^2 = c * f(x)$ correspond naturally to
                # solutions of $(sqrt(c) y)^2 = f(x)$
                pass
            else:
                # we'll count points on a twist and then correct by untwisting...
                sign = -1
        assert f.is_monic()

        if N is None:
            N = self._frobenius_coefficient_bound()

        matrix_of_frobenius = hypellfrob(p, N, f)
        matrix_of_frobenius = sign * matrix_of_frobenius
        return matrix_of_frobenius
def compute_frob_matrix_and_cp_H2(f, p, prec, **kwargs):
    """
    Return a p-adic matrix approximating the action of Frob on H^2 of a surface or abelian variety,
    and its characteristic polynomial over ZZ
    Input:
        - f defining the curve or surface
        - p, prime
        - prec, a lower bound for the desired precision to run the computations, this increases the time exponentially
        - kwargs, keyword arguments to be passed to controlledreduction

    Output:
        - `prec`, the minimum digits absolute precision for approximation of the Frobenius
        - a matrix representing an approximation of Frob matrix with at least `prec` digits of absolute precision
        - characteristic polynomial of Frob on H^2
        - the number of classes omitted by working with primitive cohomology

    Note: if given two or one univariate polynomial, we will try to change the model over Qpbar,
    in order to work with an odd and monic model
    """
    K = Qp(p, prec=prec + 10)
    OK = ZpCA(p, prec=prec)
    Rf = f.parent()
    R = f.base_ring()
    if len(Rf.gens()) == 2:
        if min(f.degrees()) != 2:
            raise NotImplementedError("Affine curves must be hyperelliptic")
        x, y = f.variables()
        if f.degree(x) == 2:
            f = f.substitute(x=y, y=x)
        # Get Weierstrass equation
        # y^2 + a*y  + b == 0
        b, a, _ = map(R['x'], R['x']['y'](f).monic())
        # y^2 + a*y  + b == 0 --> (2y + a)^2 = a^2 - 4 b
        f = a**2 - 4 * b
        f = find_monic_and_odd_model(f.change_ring(K), p)
        cp1 = HyperellipticCurve(f.change_ring(
            GF(p))).frobenius_polynomial().reverse()
        F1 = hypellfrob(p, max(3, prec), f.lift())
        F1 = F1.change_ring(OK)
        cp, frob_matrix = from_H1_to_H2(cp1,
                                        F1,
                                        tensor=kwargs.get('tensor', False))
        frob_matrix = frob_matrix.change_ring(K)
        shift = 0
    elif len(Rf.gens()) == 3 and f.total_degree() == 4 and f.is_homogeneous():
        # Quartic plane curve
        if p < 17:
            prec = max(4, prec)
        else:
            prec = max(3, prec)
        if 'find_better_model' in kwargs:
            model = kwargs['find_better_model']
        else:
            # there is a speed up, but we may also lose some nice numerical stability from the original sparseness
            model = binomial(2 + (prec - 1) * f.total_degree(),
                             2) < 2 * len(list(f**(prec - 1)))
        cp1, F1 = controlledreduction(
            f,
            p,
            min_abs_precision=prec,
            frob_matrix=True,
            threads=1,
            find_better_model=model,
        )
        # change ring to OK truncates precision accordingly
        F1 = F1.change_ring(OK)
        cp, frob_matrix = from_H1_to_H2(cp1,
                                        F1,
                                        tensor=kwargs.get('tensor', False))
        shift = 0
    elif len(Rf.gens()) == 4 and f.total_degree() in [4, 5
                                                      ] and f.is_homogeneous():
        shift = 1
        # we will not see the polarization
        # Quartic surface
        if f.total_degree() == 4:
            if p == 3:
                prec = max(5, prec)
            elif p == 5:
                prec = max(4, prec)
            elif p < 43:
                prec = max(3, prec)
            else:
                prec = max(2, prec)
        elif f.total_degree() == 5:
            if p in [3, 5]:
                prec = max(7, prec)
            elif p <= 23:
                prec = max(6, prec)
            else:
                prec = max(5, prec)
        OK = ZpCA(p, prec=prec)
        # a rough estimate if it is worth to find a non degenerate mode for f
        if 'find_better_model' in kwargs:
            model = kwargs['find_better_model']
        else:
            # there is a speed up, but we may also lose some nice numerical stability from the original sparseness
            model = binomial(3 + (prec - 1) * f.total_degree(),
                             3) < 4 * len(list(f**(prec - 1)))
        threads = kwargs.get('threads', ncpus)
        cp, frob_matrix = controlledreduction(f,
                                              p,
                                              min_abs_precision=prec,
                                              frob_matrix=True,
                                              find_better_model=model,
                                              threads=threads)
        frob_matrix = frob_matrix.change_ring(OK).change_ring(K)
    else:
        raise NotImplementedError("At the moment we only support:\n"
                                  " - Quartic or quintic surfaces\n"
                                  " - Jacobians of quartic curves\n"
                                  " - Jacobians of hyperelliptic curves\n")
    return prec, cp, frob_matrix, shift
Beispiel #4
0
def modular_symbols_from_curve(C, N, num_factors=3):
    """
    Find the modular symbols spaces that shoudl correspond to the
    Jacobian of the given hyperelliptic curve, up to the number of
    factors we consider.
    
    INPUT:
        - C -- a hyperelliptic curve over QQ
        - N -- a positive integer
        - num_factors -- number of Euler factors to verify match up; this is
          important, because if, e.g., there is only one factor of degree g(C), we
          don't want to just immediately conclude that Jac(C) = A_f. 
        
    OUTPUT:
        - list of all sign 1 simple modular symbols factor of level N
          that correspond to a simple modular abelian A_f
          that is isogenous to Jac(C).  

    EXAMPLES::

        sage: from psage.modform.rational.unfiled import modular_symbols_from_curve

        sage: R.<x> = ZZ[]
        sage: f = x^7+4*x^6+5*x^5+x^4-3*x^3-2*x^2+1
        sage: C1 = HyperellipticCurve(f)
        sage: modular_symbols_from_curve(C1, 284)
        [Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 39 for Gamma_0(284) of weight 2 with sign 1 over Rational Field]
        
        sage: f = x^7-7*x^5-11*x^4+5*x^3+18*x^2+4*x-11
        sage: C2 = HyperellipticCurve(f)
        sage: modular_symbols_from_curve(C2, 284)
        [Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 39 for Gamma_0(284) of weight 2 with sign 1 over Rational Field]
    """
    # We will use the Eichler-Shimura relation and David Harvey's
    # p-adic point counting hypellfrob.  Harvey's code has the
    # constraint:   p > (2*g + 1)*(2*prec - 1).
    # So, find the smallest p not dividing N that satisfies the
    # above constraint, for our given choice of prec.

    f, f2 = C.hyperelliptic_polynomials()
    if f2 != 0:
        raise NotImplementedError, "curve must be of the form y^2 = f(x)"
    if f.degree() % 2 == 0:
        raise NotImplementedError, "curve must be of the form y^2 = f(x) with f(x) odd"

    prec = 1

    g = C.genus()
    B = (2 * g + 1) * (2 * prec - 1)

    from sage.rings.all import next_prime
    p = B

    # We use that if F(X) is the characteristic polynomial of the
    # Hecke operator T_p, then X^g*F(X+p/X) is the characteristic
    # polynomial of Frob_p, because T_p = Frob_p + p/Frob_p, according
    # to Eichler-Shimura.  Use this to narrow down the factors.

    from sage.all import ModularSymbols, Integers, get_verbose
    D = ModularSymbols(
        N, sign=1).cuspidal_subspace().new_subspace().decomposition()
    D = [A for A in D if A.dimension() == g]

    from sage.schemes.hyperelliptic_curves.hypellfrob import hypellfrob

    while num_factors > 0:
        p = next_prime(p)
        while N % p == 0:
            p = next_prime(p)

        R = Integers(p**prec)['X']
        X = R.gen()
        D2 = []
        # Compute the charpoly of Frobenius using hypellfrob
        M = hypellfrob(p, 1, f)
        H = R(M.charpoly())

        for A in D:
            F = R(A.hecke_polynomial(p))
            # Compute charpoly of Frobenius from F(X)
            G = R(F.parent()(X**g * F(X + p / X)))
            if get_verbose(): print(p, G, H)
            if G == H:
                D2.append(A)
        D = D2
        num_factors -= 1

    return D
Beispiel #5
0
def modular_symbols_from_curve(C, N, num_factors=3):
    """
    Find the modular symbols spaces that shoudl correspond to the
    Jacobian of the given hyperelliptic curve, up to the number of
    factors we consider.
    
    INPUT:
        - C -- a hyperelliptic curve over QQ
        - N -- a positive integer
        - num_factors -- number of Euler factors to verify match up; this is
          important, because if, e.g., there is only one factor of degree g(C), we
          don't want to just immediately conclude that Jac(C) = A_f. 
        
    OUTPUT:
        - list of all sign 1 simple modular symbols factor of level N
          that correspond to a simple modular abelian A_f
          that is isogenous to Jac(C).  

    EXAMPLES::

        sage: from psage.modform.rational.unfiled import modular_symbols_from_curve

        sage: R.<x> = ZZ[]
        sage: f = x^7+4*x^6+5*x^5+x^4-3*x^3-2*x^2+1
        sage: C1 = HyperellipticCurve(f)
        sage: modular_symbols_from_curve(C1, 284)
        [Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 39 for Gamma_0(284) of weight 2 with sign 1 over Rational Field]
        
        sage: f = x^7-7*x^5-11*x^4+5*x^3+18*x^2+4*x-11
        sage: C2 = HyperellipticCurve(f)
        sage: modular_symbols_from_curve(C2, 284)
        [Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 39 for Gamma_0(284) of weight 2 with sign 1 over Rational Field]
    """
    # We will use the Eichler-Shimura relation and David Harvey's
    # p-adic point counting hypellfrob.  Harvey's code has the
    # constraint:   p > (2*g + 1)*(2*prec - 1).
    # So, find the smallest p not dividing N that satisfies the
    # above constraint, for our given choice of prec.

    f, f2 = C.hyperelliptic_polynomials()
    if f2 != 0:
        raise NotImplementedError, "curve must be of the form y^2 = f(x)"
    if f.degree() % 2 == 0:
        raise NotImplementedError, "curve must be of the form y^2 = f(x) with f(x) odd"

    prec = 1
    
    g = C.genus()
    B = (2*g + 1)*(2*prec - 1)

    from sage.rings.all import next_prime
    p = B

    # We use that if F(X) is the characteristic polynomial of the
    # Hecke operator T_p, then X^g*F(X+p/X) is the characteristic
    # polynomial of Frob_p, because T_p = Frob_p + p/Frob_p, according
    # to Eichler-Shimura.  Use this to narrow down the factors. 

    from sage.all import ModularSymbols, Integers, get_verbose
    D = ModularSymbols(N,sign=1).cuspidal_subspace().new_subspace().decomposition()
    D = [A for A in D if A.dimension() == g]

    from sage.schemes.hyperelliptic_curves.hypellfrob import hypellfrob

    while num_factors > 0:
        p = next_prime(p)
        while N % p == 0: p = next_prime(p)
        
        R = Integers(p**prec)['X']
        X = R.gen()
        D2 = []
        # Compute the charpoly of Frobenius using hypellfrob
        M = hypellfrob(p, 1, f)
        H = R(M.charpoly())
        
        for A in D:
            F = R(A.hecke_polynomial(p))
            # Compute charpoly of Frobenius from F(X)
            G = R(F.parent()(X**g * F(X + p/X)))
            if get_verbose(): print (p, G, H)
            if G == H:
                D2.append(A)
        D = D2
        num_factors -= 1

    return D