Example #1
0
File: cusps.py Project: CETHop/sage
    def galois_action(self, t, N):
        r"""
        Suppose this cusp is `\alpha`, `G` a congruence subgroup of level `N`
        and `\sigma` is the automorphism in the Galois group of
        `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this
        function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`,
        where `[\alpha]` is the equivalence class of `\alpha` modulo `G`.

        This code only needs as input the level and not the group since the
        action of galois for a congruence group `G` of level `N` is compatible
        with the action of the full congruence group `\Gamma(N)`.


        INPUT:

           - `t` -- integer that is coprime to N

           - `N` -- positive integer (level)

        OUTPUT:

           - a cusp


        .. WARNING::

            In some cases `N` must fit in a long long, i.e., there
            are cases where this algorithm isn't fully implemented.

        .. NOTE::

            Modular curves can have multiple non-isomorphic models over `\QQ`.
            The action of galois depends on such a model. The model over `\QQ`
            of `X(G)` used here is the model where the function field
            `\QQ(X(G))` is given by the functions whose fourier expansion at
            `\infty` have their coefficients in `\QQ`. For `X(N):=X(\Gamma(N))`
            the corresponding moduli interpretation over `\ZZ[1/N]` is that
            `X(N)` parametrizes pairs `(E,a)` where `E` is a (generalized)
            elliptic curve and `a: \ZZ / N\ZZ \times \mu_N \to E` is a closed
            immersion such that the weil pairing of `a(1,1)` and `a(0,\zeta_N)`
            is `\zeta_N`. In this parameterisation the point `z \in H`
            corresponds to the pair `(E_z,a_z)` with `E_z=\CC/(z \ZZ+\ZZ)` and
            `a_z: \ZZ / N\ZZ \times \mu_N \to E` given by `a_z(1,1) = z/N` and
            `a_z(0,\zeta_N) = 1/N`.
            Similarly `X_1(N):=X(\Gamma_1(N))` parametrizes pairs `(E,a)` where
            `a: \mu_N \to E` is a closed immersion.

        EXAMPLES::

            sage: Cusp(1/10).galois_action(3, 50)
            1/170
            sage: Cusp(oo).galois_action(3, 50)
            Infinity
            sage: c=Cusp(0).galois_action(3, 50); c
            50/67
            sage: Gamma0(50).reduce_cusp(c)
            0

        Here we compute the permutations of the action for t=3 on cusps for
        Gamma0(50). ::

            sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
            sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
            sage: for i in range(5): print i, t^i, [cl(alpha.galois_action(t^i,N)) for alpha in C]
            0 1 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
            1 3 [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
            2 9 [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
            3 27 [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
            4 81 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]

        TESTS:

        Here we check that the galois action is indeed a permutation on the
        cusps of Gamma1(48) and check that :trac:`13253` is fixed. ::

            sage: G=Gamma1(48)
            sage: C=G.cusps()
            sage: for i in Integers(48).unit_gens():
            ...     C_permuted = [G.reduce_cusp(c.galois_action(i,48)) for c in C]
            ...     assert len(set(C_permuted))==len(C)

        We test that Gamma1(19) has 9 rational cusps and check that :trac:`8998`
        is fixed. ::

            sage: G = Gamma1(19)
            sage: [c for c in G.cusps() if c.galois_action(2,19).is_gamma1_equiv(c,19)[0]]
            [2/19, 3/19, 4/19, 5/19, 6/19, 7/19, 8/19, 9/19, Infinity]


        REFERENCES:

            - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"

            - There is a long comment about our algorithm in the source code for this function.

        AUTHORS:

            - William Stein, 2009-04-18

        """
        if self.is_infinity(): return self
        if not isinstance(t, Integer): t = Integer(t)

        # Our algorithm for computing the Galois action works as
        # follows (see Section 1.3 of Glenn Stevens "Arithmetic on
        # Modular Curves" for a proof that the action given below is
        # correct).  We alternatively view the set of cusps as the
        # Gamma-equivalence classes of column vectors [a;b] with
        # gcd(a,b,N)=1, and the left action of Gamma by matrix
        # multiplication.  The action of t is induced by [a;b] |-->
        # [a;t'*b], where t' is an inverse mod N of t.  For [a;t'*b]
        # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
        # just the rational number a/(t'*b).  Thus in this case, to
        # compute the action of t we just do a/b <--> [a;b] |--->
        # [a;t'*b] <--> a/(t'*b).  IN the other case when we get
        # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
        # we have to work a bit harder.  We need to find [c;d] such
        # that [c;d] is congruent to [a;t'*b] modulo N, and
        # gcd(c,d)=1.  There is a standard lifting algorithm that is
        # implemented for working with P^1(Z/NZ) [it is needed for
        # modular symbols algorithms], so we just apply it to lift
        # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
        # entries congruent to [a,t'*b] modulo N.  This exactly solves
        # our problem, since gcd(c,d)=1.

        a = self.__a
        b = self.__b * t.inverse_mod(N)
        if b.gcd(a) != 1:
            _,_,a,b = lift_to_sl2z_llong(a,b,N)
            a = Integer(a); b = Integer(b)

        # Now that we've computed the Galois action, we efficiently
        # construct the corresponding cusp as a Cusp object.
        return Cusp(a,b,check=False)
Example #2
0
File: cusps.py Project: yjjcc/sage
    def galois_action(self, t, N):
        r"""
        Suppose this cusp is `\alpha`, `G` a congruence subgroup of level `N`
        and `\sigma` is the automorphism in the Galois group of
        `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this
        function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`,
        where `[\alpha]` is the equivalence class of `\alpha` modulo `G`.

        This code only needs as input the level and not the group since the
        action of Galois for a congruence group `G` of level `N` is compatible
        with the action of the full congruence group `\Gamma(N)`.

        INPUT:

        - `t` -- integer that is coprime to N

        - `N` -- positive integer (level)

        OUTPUT:

        - a cusp

        .. WARNING::

            In some cases `N` must fit in a long long, i.e., there
            are cases where this algorithm isn't fully implemented.

        .. NOTE::

            Modular curves can have multiple non-isomorphic models over `\QQ`.
            The action of Galois depends on such a model. The model over `\QQ`
            of `X(G)` used here is the model where the function field
            `\QQ(X(G))` is given by the functions whose Fourier expansion at
            `\infty` have their coefficients in `\QQ`. For `X(N):=X(\Gamma(N))`
            the corresponding moduli interpretation over `\ZZ[1/N]` is that
            `X(N)` parametrizes pairs `(E,a)` where `E` is a (generalized)
            elliptic curve and `a: \ZZ / N\ZZ \times \mu_N \to E` is a closed
            immersion such that the Weil pairing of `a(1,1)` and `a(0,\zeta_N)`
            is `\zeta_N`. In this parameterisation the point `z \in H`
            corresponds to the pair `(E_z,a_z)` with `E_z=\CC/(z \ZZ+\ZZ)` and
            `a_z: \ZZ / N\ZZ \times \mu_N \to E` given by `a_z(1,1) = z/N` and
            `a_z(0,\zeta_N) = 1/N`.
            Similarly `X_1(N):=X(\Gamma_1(N))` parametrizes pairs `(E,a)` where
            `a: \mu_N \to E` is a closed immersion.

        EXAMPLES::

            sage: Cusp(1/10).galois_action(3, 50)
            1/170
            sage: Cusp(oo).galois_action(3, 50)
            Infinity
            sage: c=Cusp(0).galois_action(3, 50); c
            50/67
            sage: Gamma0(50).reduce_cusp(c)
            0

        Here we compute the permutations of the action for t=3 on cusps for
        Gamma0(50). ::

            sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
            sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
            sage: for i in range(5):
            ....:     print((i, t^i))
            ....:     print([cl(alpha.galois_action(t^i,N)) for alpha in C])
            (0, 1)
            [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
            (1, 3)
            [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
            (2, 9)
            [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
            (3, 27)
            [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
            (4, 81)
            [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]

        TESTS:

        Here we check that the Galois action is indeed a permutation on the
        cusps of Gamma1(48) and check that :trac:`13253` is fixed. ::

            sage: G = Gamma1(48)
            sage: C = G.cusps()
            sage: for i in Integers(48).unit_gens():
            ....:   C_permuted = [G.reduce_cusp(c.galois_action(i,48)) for c in C]
            ....:   assert len(set(C_permuted))==len(C)

        We test that Gamma1(19) has 9 rational cusps and check that :trac:`8998`
        is fixed. ::

            sage: G = Gamma1(19)
            sage: [c for c in G.cusps() if c.galois_action(2,19).is_gamma1_equiv(c,19)[0]]
            [2/19, 3/19, 4/19, 5/19, 6/19, 7/19, 8/19, 9/19, Infinity]


        REFERENCES:

        - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"

        - There is a long comment about our algorithm in the source code for this function.

        AUTHORS:

        - William Stein, 2009-04-18

        """
        if self.is_infinity():
            return self
        if not isinstance(t, Integer):
            t = Integer(t)

        # Our algorithm for computing the Galois action works as
        # follows (see Section 1.3 of Glenn Stevens "Arithmetic on
        # Modular Curves" for a proof that the action given below is
        # correct).  We alternatively view the set of cusps as the
        # Gamma-equivalence classes of column vectors [a;b] with
        # gcd(a,b,N)=1, and the left action of Gamma by matrix
        # multiplication.  The action of t is induced by [a;b] |-->
        # [a;t'*b], where t' is an inverse mod N of t.  For [a;t'*b]
        # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
        # just the rational number a/(t'*b).  Thus in this case, to
        # compute the action of t we just do a/b <--> [a;b] |--->
        # [a;t'*b] <--> a/(t'*b).  IN the other case when we get
        # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
        # we have to work a bit harder.  We need to find [c;d] such
        # that [c;d] is congruent to [a;t'*b] modulo N, and
        # gcd(c,d)=1.  There is a standard lifting algorithm that is
        # implemented for working with P^1(Z/NZ) [it is needed for
        # modular symbols algorithms], so we just apply it to lift
        # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
        # entries congruent to [a,t'*b] modulo N.  This exactly solves
        # our problem, since gcd(c,d)=1.

        a = self.__a
        b = self.__b * t.inverse_mod(N)
        if b.gcd(a) != 1:
            _, _, a, b = lift_to_sl2z_llong(a, b, N)
            a = Integer(a)
            b = Integer(b)

        # Now that we've computed the Galois action, we efficiently
        # construct the corresponding cusp as a Cusp object.
        return Cusp(a, b, check=False)
Example #3
0
    def galois_action(self, t, N):
        r"""
        Suppose this cusp is `\alpha`, `G` is the congruence subgroup
        `\Gamma_0(N)` of level `N`, and `\sigma` is the automorphism in
        the Galois group of `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to
        `\zeta_N^t`.  Then this function computes a cusp `\beta` such
        that `\sigma([\alpha]) = [\beta]`, where `[\alpha]` is the
        equivalence class of `\alpha` modulo `G`.

        BIG WARNING: Despite its general name, this function only
        computes something that defines an action on `\Gamma_0(N)`
        equivalence classes; it does not compute the action on
        `\Gamma_1(N)` classes (see trac 8998).

        INPUT:

           - `t` -- integer that is coprime to N

           - `N` -- positive integer (level)

        OUTPUT:

           - a cusp

        EXAMPLES::
        
            sage: Cusp(1/10).galois_action(3, 50)
            1/170
            sage: Cusp(oo).galois_action(3, 50)
            Infinity
            sage: Cusp(0).galois_action(3, 50)
            0
            
        Here we compute explicitly the permutations of the action for
        t=3 on cusps for Gamma0(50)::
        
            sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
            sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
            sage: for i in range(5): print i, t^i, [cl(alpha.galois_action(t^i,N)) for alpha in C]
            0 1 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
            1 3 [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
            2 9 [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
            3 27 [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
            4 81 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]

        REFERENCES:

            - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"
            
            - There is a long comment about our algorithm in the source code for this function.

        WARNING: In some cases `N` must fit in a long long, i.e., there
                 are cases where this algorithm isn't fully implemented.

        AUTHORS:
        
            - William Stein, 2009-04-18

        """
        if self.is_infinity() or not self.__a: return self
        if not isinstance(t, Integer): t = Integer(t)

        # Our algorithm for computing the Galois action works as
        # follows (see Section 1.3 of Glenn Stevens "Arithmetic on
        # Modular Curves" for a proof that the action given below is
        # correct).  We alternatively view the set of cusps as the
        # Gamma-equivalence classes of column vectors [a;b] with
        # gcd(a,b,N)=1, and the left action of Gamma by matrix
        # multiplication.  The action of t is induced by [a;b] |-->
        # [a;t'*b], where t' is an inverse mod N of t.  For [a;t'*b]
        # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
        # just the rational number a/(t'*b).  Thus in this case, to
        # compute the action of t we just do a/b <--> [a;b] |--->
        # [a;t'*b] <--> a/(t'*b).  IN the other case when we get
        # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
        # we have to work a bit harder.  We need to find [c;d] such
        # that [c;d] is congruent to [a;t'*b] modulo N, and
        # gcd(c,d)=1.  There is a standard lifting algorithm that is
        # implemented for working with P^1(Z/NZ) [it is needed for
        # modular symbols algorithms], so we just apply it to lift
        # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
        # entries congruent to [a,t'*b] modulo N.  This exactly solves
        # our problem, since gcd(c,d)=1.

        a = self.__a
        b = self.__b * t.inverse_mod(N)
        if b.gcd(a) != 1:
            _,_,a,b = lift_to_sl2z_llong(a,b,N)
            a = Integer(a); b = Integer(b)

        # Now that we've computed the Galois action, we efficiently
        # construct the corresponding cusp as a Cusp object.
        return Cusp(a,b,check=False)