コード例 #1
0
    def atkin_lehner_matrix(self, Q):
        r"""
        Return the matrix of the Atkin--Lehner--Li operator `W_Q` associated to
        an exact divisor `Q` of `N`, where `N` is the level of this group; that
        is, `gcd(Q, N/Q) = 1`.

        .. note::

            We follow the conventions of [AL1978]_ here, so `W_Q` is given by
            the action of any matrix of the form `\begin{pmatrix} Qx & y \\ Nz
            & Qw \end{pmatrix}` where `x,y,z,w` are integers such that `y = 1
            \bmod Q`, `x = 1 \bmod N/Q`, and `det(W_Q) = Q`. For convenience,
            we actually always choose `x = y = 1`.

        INPUT:

        - ``Q`` (integer): an integer dividing `N`, where `N` is the level of
          this group. If this divisor does not satisfy `gcd(Q, N/Q) = 1`, it
          will be replaced by the unique integer with this property having
          the same prime factors as `Q`.

        EXAMPLES::

            sage: Gamma1(994).atkin_lehner_matrix(71)
            [  71    1]
            [4970   71]
            sage: Gamma1(996).atkin_lehner_matrix(2)
            [   4    1]
            [-996 -248]
            sage: Gamma1(15).atkin_lehner_matrix(7)
            Traceback (most recent call last):
            ...
            ValueError: Q must divide the level
        """
        # normalise Q
        Q = ZZ(Q)
        N = self.level()
        if not Q.divides(N):
            raise ValueError("Q must divide the level")
        Q = N // N.prime_to_m_part(Q)

        _, z, w = xgcd(-N // Q, Q)
        # so w * Q - z*(N/Q) = 1
        return matrix(ZZ, 2, 2, [Q, 1, N * z, Q * w])
コード例 #2
0
    def zeta(self, n=2, all=False):
        """
        Return one, or a list of all, primitive n-th root of unity in this unit group.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: K.<z> = NumberField(x^2 + 3)
            sage: U = UnitGroup(K)
            sage: U.zeta(1)
            1
            sage: U.zeta(2)
            -1
            sage: U.zeta(2, all=True)
            [-1]
            sage: U.zeta(3)
            -1/2*z - 1/2
            sage: U.zeta(3, all=True)
            [-1/2*z - 1/2, 1/2*z - 1/2]
            sage: U.zeta(4)
            Traceback (most recent call last):
            ...
            ValueError: n (=4) does not divide order of generator

            sage: r.<x> = QQ[]
            sage: K.<b> = NumberField(x^2+1)
            sage: U = UnitGroup(K)
            sage: U.zeta(4)
            -b
            sage: U.zeta(4,all=True)
            [-b, b]
            sage: U.zeta(3)
            Traceback (most recent call last):
            ...
            ValueError: n (=3) does not divide order of generator
            sage: U.zeta(3,all=True)
            []

        """
        N = self.__ntu
        K = self.number_field()
        n = ZZ(n)
        if n <= 0:
            raise ValueError("n (=%s) must be positive" % n)
        if n == 1:
            if all:
                return [K(1)]
            else:
                return K(1)
        elif n == 2:
            if all:
                return [K(-1)]
            else:
                return K(-1)
        if n.divides(N):
            z = self.torsion_generator().value()**(N // n)
            if all:
                return [z**i for i in n.coprime_integers(n)]
            else:
                return z
        else:
            if all:
                return []
            else:
                raise ValueError("n (=%s) does not divide order of generator" %
                                 n)
コード例 #3
0
ファイル: unit_group.py プロジェクト: cswiercz/sage
    def zeta(self, n=2, all=False):
        """
        Return one, or a list of all, primitive n-th root of unity in this unit group.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: K.<z> = NumberField(x^2 + 3)
            sage: U = UnitGroup(K)
            sage: U.zeta(1)
            1
            sage: U.zeta(2)
            -1
            sage: U.zeta(2, all=True)
            [-1]
            sage: U.zeta(3)
            -1/2*z - 1/2
            sage: U.zeta(3, all=True)
            [-1/2*z - 1/2, 1/2*z - 1/2]
            sage: U.zeta(4)
            Traceback (most recent call last):
            ...
            ValueError: n (=4) does not divide order of generator

            sage: r.<x> = QQ[]
            sage: K.<b> = NumberField(x^2+1)
            sage: U = UnitGroup(K)
            sage: U.zeta(4)
            -b
            sage: U.zeta(4,all=True)
            [-b, b]
            sage: U.zeta(3)
            Traceback (most recent call last):
            ...
            ValueError: n (=3) does not divide order of generator
            sage: U.zeta(3,all=True)
            []

        """
        N = self.__ntu
        K = self.number_field()
        n = ZZ(n)
        if n <= 0:
            raise ValueError, "n (=%s) must be positive"%n
        if n == 1:
            if all:
                return [K(1)]
            else:
                return K(1)
        elif n == 2:
            if all:
                return [K(-1)]
            else:
                return K(-1)
        if n.divides(N):
            z = self.torsion_generator().value() ** (N//n)
            if all:
                return [z**i for i in n.coprime_integers(n)]
            else:
                return z
        else:
            if all:
                return []
            else:
                raise ValueError, "n (=%s) does not divide order of generator"%n
コード例 #4
0
def find_p_neighbor_from_vec(self, p, y):
    r"""
    Return the `p`-neighbor of ``self`` defined by ``y``.

    Let `(L,q)` be a lattice with `b(L,L) \subseteq \ZZ` which is maximal at `p`.
    Let `y \in L` with `b(y,y) \in p^2\ZZ` then the `p`-neighbor of
    `L` at `y` is given by
    `\ZZ y/p + L_y` where `L_y = \{x \in L | b(x,y) \in p \ZZ \}`
    and `b(x,y) = q(x+y)-q(x)-q(y)` is the bilinear form associated to `q`.

    INPUT:

    - ``p`` -- a prime number
    - ``y`` -- a vector with `q(y) \in p \ZZ`.
    - ``odd`` -- (default=``False``) if `p=2` return also odd neighbors

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1])
        sage: v = vector([0,2,1,1])
        sage: X = Q.find_p_neighbor_from_vec(3,v); X
        Quadratic form in 4 variables over Integer Ring with coefficients:
        [ 1 0 0 0 ]
        [ * 1 4 4 ]
        [ * * 5 12 ]
        [ * * * 9 ]

    Since the base ring and the domain are not yet separate,
    for rational, half integral forms we just pretend
    the base ring is `ZZ`::

        sage: Q = QuadraticForm(QQ,matrix.diagonal([1,1,1,1]))
        sage: v = vector([1,1,1,1])
        sage: Q.find_p_neighbor_from_vec(2,v)
        Quadratic form in 4 variables over Rational Field with coefficients:
        [ 1/2 1 1 1 ]
        [ * 1 1 2 ]
        [ * * 1 2 ]
        [ * * * 2 ]
    """
    p = ZZ(p)
    if not p.divides(self(y)):
        raise ValueError("y=%s must be of square divisible by p=%s" % (y, p))
    if self.base_ring() not in [ZZ, QQ]:
        raise NotImplementedError(
            "the base ring of this form must be the integers or the rationals")
    n = self.dim()
    G = self.Hessian_matrix()
    R = self.base_ring()
    odd = False
    if R is QQ:
        odd = True
        if G.denominator() != 1:
            raise ValueError(
                "the associated bilinear form q(x+y)-q(x)-q(y) must be integral."
            )
    b = y * G * y
    if not b % p == 0:
        raise ValueError("y^2 must be divisible by p=%s" % p)
    y_dual = y * G
    if p != 2 and b % p**2 != 0:
        for k in range(n):
            if y_dual[k] % p != 0:
                z = (ZZ**n).gen(k)
                break
        else:
            raise ValueError(
                "either y is not primitive or self is not maximal at %s" % p)
        z *= (2 * y * G * z).inverse_mod(p)
        y = y - b * z
        # assert y*G*y % p^2 == 0
    if p == 2:
        val = b.valuation(p)
        if val <= 1:
            raise ValueError("y=%s must be of square divisible by 2" % y)
        if val == 2 and not odd:
            # modify it to have square 4
            for k in range(n):
                if y_dual[k] % p != 0:
                    z = (ZZ**n).gen(k)
                    break
            else:
                raise ValueError(
                    "either y is not primitive or self is not even, maximal at 2"
                )
            y += 2 * z
            # assert y*G*y % 8 == 0

    y_dual = G * y
    Ly = y_dual.change_ring(GF(p)).column().kernel().matrix().lift()
    B = Ly.stack(p * matrix.identity(n))
    # the rows of B now generate L_y = { x in L | (x,y)=0 mod p}
    B = y.row().stack(p * B)
    B = B.hermite_form()[:n, :] / p
    # the rows of B generate ZZ * y/p + L_y
    # by definition this is the p-neighbor of L at y
    # assert B.det().abs() == 1

    QF = self.parent()
    Gnew = (B * G * B.T).change_ring(R)
    return QF(Gnew)
コード例 #5
0
def torsion_bound(E, number_of_places=20):
    r"""
    Return an upper bound on the order of the torsion subgroup.

    INPUT:

    - ``E`` -- an elliptic curve over `\QQ` or a number field

    - ``number_of_places`` (positive integer, default = 20) -- the
        number of places that will be used to find the bound

    OUTPUT:

    (integer) An upper bound on the torsion order.

    ALGORITHM:

    An upper bound on the order of the torsion group of the elliptic
    curve is obtained by counting points modulo several primes of good
    reduction. Note that the upper bound returned by this function is
    a multiple of the order of the torsion group, and in general will
    be greater than the order.

    To avoid nontrivial arithmetic in the base field (in particular,
    to avoid having to compute the maximal order) we only use prime
    `P` above rational primes `p` which do not divide the discriminant
    of the equation order.

    EXAMPLES::

        sage: CDB = CremonaDatabase()
        sage: from sage.schemes.elliptic_curves.ell_torsion import torsion_bound
        sage: [torsion_bound(E) for E in CDB.iter([14])]
        [6, 6, 6, 6, 6, 6]
        sage: [E.torsion_order() for E in CDB.iter([14])]
        [6, 6, 2, 6, 2, 6]

    An example over a relative number field (see :trac:`16011`)::

        sage: R.<x> = QQ[]
        sage: F.<a> = QuadraticField(5)
        sage: K.<b> = F.extension(x^2-3)
        sage: E = EllipticCurve(K,[0,0,0,b,1])
        sage: E.torsion_subgroup().order()
        1

    An example of a base-change curve from `\QQ` to a degree 16 field::

        sage: from sage.schemes.elliptic_curves.ell_torsion import torsion_bound
        sage: f = PolynomialRing(QQ,'x')([5643417737593488384,0,
        ....:     -11114515801179776,0,-455989850911004,0,379781901872,
        ....:     0,14339154953,0,-1564048,0,-194542,0,-32,0,1])
        sage: K = NumberField(f,'a')
        sage: E = EllipticCurve(K, [1, -1, 1, 824579, 245512517])
        sage: torsion_bound(E)
        16
        sage: E.torsion_subgroup().invariants()
        (4, 4)
    """
    from sage.rings.integer_ring import ZZ
    from sage.rings.finite_rings.finite_field_constructor import GF
    from sage.schemes.elliptic_curves.constructor import EllipticCurve

    K = E.base_field()

    # Special case K = QQ

    if K is RationalField():
        bound = ZZ.zero()
        k = 0
        p = ZZ(2)  # so we start with 3
        E = E.integral_model()
        disc_E = E.discriminant()

        while k < number_of_places:
            p = p.next_prime()
            if p.divides(disc_E):
                continue
            k += 1
            Fp = GF(p)
            new_bound = E.reduction(p).cardinality()
            bound = bound.gcd(new_bound)
            if bound == 1:
                return bound
        return bound

    # In case K is a relative extension we absolutize:

    absK = K.absolute_field('a_')
    f = absK.defining_polynomial()
    abs_map = absK.structure()[1]

    # Ensure f is monic and in ZZ[x]

    f = f.monic()
    den = f.denominator()
    if den != 1:
        x = f.parent().gen()
        n = f.degree()
        f = den**n * f(x / den)
    disc_f = f.discriminant()
    d = K.absolute_degree()

    # Now f is monic in ZZ[x] of degree d and defines the extension K = Q(a)

    # Make sure that we have a model for E with coefficients in ZZ[a]

    E = E.integral_model()
    disc_E = E.discriminant().norm()
    ainvs = [abs_map(c) for c in E.a_invariants()]

    bound = ZZ.zero()
    k = 0
    p = ZZ(2)  # so we start with 3

    try:  # special case, useful for base-changes from QQ
        ainvs = [ZZ(ai) for ai in ainvs]
        while k < number_of_places:
            p = p.next_prime()
            if p.divides(disc_E) or p.divides(disc_f):
                continue
            k += 1
            for fi, ei in f.factor_mod(p):
                di = fi.degree()
                Fp = GF(p)
                new_bound = EllipticCurve(
                    Fp, ainvs).cardinality(extension_degree=di)
                bound = bound.gcd(new_bound)
                if bound == 1:
                    return bound
        return bound
    except (ValueError, TypeError):
        pass

    # General case

    while k < number_of_places:
        p = p.next_prime()
        if p.divides(disc_E) or p.divides(disc_f):
            continue
        k += 1
        for fi, ei in f.factor_mod(p):
            di = fi.degree()
            Fq = GF((p, di))
            ai = fi.roots(Fq, multiplicities=False)[0]

            def red(c):
                return Fq.sum(Fq(c[j]) * ai**j for j in range(d))

            new_bound = EllipticCurve([red(c) for c in ainvs]).cardinality()
            bound = bound.gcd(new_bound)
            if bound == 1:
                return bound
    return bound