Esempio n. 1
0
    def weil_representation(self) :
        r"""
        OUTPUT:
        
        - A pair of matrices corresponding to T and S.
        """
        disc_bilinear = lambda a, b: (self._dual_basis * vector(QQ, a.lift())) * self._L * (self._dual_basis * vector(QQ, b.lift()))
        disc_quadratic = lambda a: disc_bilinear(a, a) / ZZ(2)
        
        zeta_order = ZZ(lcm([8, 12, prod(self.invariants())] + map(lambda ed: 2 * ed, self.invariants())))
        K = CyclotomicField(zeta_order); zeta = K.gen()

        R = PolynomialRing(K, 'x'); x = R.gen()
#        sqrt2s = (x**2 - 2).factor()
#        if sqrt2s[0][0][0].complex_embedding().real() > 0 :        
#            sqrt2  = sqrt2s[0][0][0]
#        else : 
#            sqrt2  = sqrt2s[0][1]
        Ldet_rts = (x**2 - prod(self.invariants())).factor()
        if Ldet_rts[0][0][0].complex_embedding().real() > 0 :
            Ldet_rt  = Ldet_rts[0][0][0] 
        else :
            Ldet_rt  = Ldet_rts[0][0][0]
                
        Tmat  = diagonal_matrix( K, [zeta**(zeta_order*disc_quadratic(a)) for a in self] )
        Smat = zeta**(zeta_order / 8 * self._L.nrows()) / Ldet_rt  \
               * matrix( K,  [ [ zeta**ZZ(-zeta_order * disc_bilinear(gamma,delta))
                                 for delta in self ]
                               for gamma in self ])
        
        return (Tmat, Smat)
    def primitive(self, signed=True):
        """
        Return hyperplane defined by primitive equation.

        INPUT:

        - ``signed`` -- boolean (optional, default: ``True``); whether
          to preserve the overall sign

        OUTPUT:

        Hyperplane whose linear expression has common factors and
        denominators cleared. That is, the same hyperplane (with the
        same sign) but defined by a rescaled equation. Note that
        different linear expressions must define different hyperplanes
        as comparison is used in caching.

        If ``signed``, the overall rescaling is by a positive constant
        only.

        EXAMPLES::

            sage: H.<x,y> = HyperplaneArrangements(QQ)
            sage: h = -1/3*x + 1/2*y - 1;  h
            Hyperplane -1/3*x + 1/2*y - 1
            sage: h.primitive()
            Hyperplane -2*x + 3*y - 6
            sage: h == h.primitive()
            False
            sage: (4*x + 8).primitive()
            Hyperplane x + 0*y + 2

            sage: (4*x - y - 8).primitive(signed=True)   # default
            Hyperplane 4*x - y - 8
            sage: (4*x - y - 8).primitive(signed=False)
            Hyperplane -4*x + y + 8
        """
        from sage.rings.all import lcm, gcd
        coeffs = self.coefficients()
        try:
            d = lcm([x.denom() for x in coeffs])
            n = gcd([x.numer() for x in coeffs])
        except AttributeError:
            return self
        if not signed:
            for x in coeffs:
                if x > 0:
                    break
                if x < 0:
                    d = -d
                    break
        parent = self.parent()
        d = parent.base_ring()(d)
        n = parent.base_ring()(n)
        if n == 0:
            n = parent.base_ring().one()
        return parent(self * d / n)
Esempio n. 3
0
    def primitive(self, signed=True):
        """
        Return hyperplane defined by primitive equation.

        INPUT:

        - ``signed`` -- boolean (optional, default: ``True``); whether
          to preserve the overall sign

        OUTPUT:

        Hyperplane whose linear expression has common factors and
        denominators cleared. That is, the same hyperplane (with the
        same sign) but defined by a rescaled equation. Note that
        different linear expressions must define different hyperplanes
        as comparison is used in caching.

        If ``signed``, the overall rescaling is by a positive constant
        only.

        EXAMPLES::

            sage: H.<x,y> = HyperplaneArrangements(QQ)
            sage: h = -1/3*x + 1/2*y - 1;  h
            Hyperplane -1/3*x + 1/2*y - 1
            sage: h.primitive()
            Hyperplane -2*x + 3*y - 6
            sage: h == h.primitive()
            False
            sage: (4*x + 8).primitive()
            Hyperplane x + 0*y + 2

            sage: (4*x - y - 8).primitive(signed=True)   # default
            Hyperplane 4*x - y - 8
            sage: (4*x - y - 8).primitive(signed=False)
            Hyperplane -4*x + y + 8
        """
        from sage.rings.all import lcm, gcd
        coeffs = self.coefficients()
        try:
            d = lcm([x.denom() for x in coeffs])
            n = gcd([x.numer() for x in coeffs])
        except AttributeError:
            return self
        if not signed:
            for x in coeffs:
                if x > 0:
                    break
                if x < 0: 
                    d = -d
                    break
        parent = self.parent()
        d = parent.base_ring()(d)
        n = parent.base_ring()(n)
        if n == 0:
            n = parent.base_ring().one()
        return parent(self * d / n)
Esempio n. 4
0
    def _normalize_coefficients(self, c):
        """
        If our coefficient ring is the field of fractions over a univariate
        polynomial ring over the rationals, then we should clear both the
        numerator and denominator of the denominators of their
        coefficients.
        
        EXAMPLES::
        
            sage: P = JackPolynomialsP(QQ)
            sage: t = P.base_ring().gen()
            sage: a = 2/(1/2*t+1/2)
            sage: P._normalize_coefficients(a)
            4/(t + 1)
            sage: a = 1/(1/3+1/6*t)
            sage: P._normalize_coefficients(a)
            6/(t + 2)
            sage: a = 24/(4*t^2 + 12*t + 8)
            sage: P._normalize_coefficients(a)
            6/(t^2 + 3*t + 2)
        """
        BR = self.base_ring()
        if is_FractionField(BR) and BR.base_ring() == QQ:
            denom = c.denominator()
            numer = c.numerator()

            #Clear the denominators
            a = lcm([i.denominator() for i in denom.coeffs()])
            b = lcm([i.denominator() for i in numer.coeffs()])
            l = Integer(a).lcm(Integer(b))
            denom *= l
            numer *= l

            #Divide through by the gcd of the numerators
            a = gcd([i.numerator() for i in denom.coeffs()])
            b = gcd([i.numerator() for i in numer.coeffs()])
            l = Integer(a).gcd(Integer(b))

            denom = denom / l
            numer = numer / l

            return c.parent()(numer, denom)
        else:
            return c
Esempio n. 5
0
    def _normalize_coefficients(self, c):
        """
        If our coefficient ring is the field of fractions over a univariate
        polynomial ring over the rationals, then we should clear both the
        numerator and denominator of the denominators of their
        coefficients.
        
        EXAMPLES::
        
            sage: P = JackPolynomialsP(QQ)
            sage: t = P.base_ring().gen()
            sage: a = 2/(1/2*t+1/2)
            sage: P._normalize_coefficients(a)
            4/(t + 1)
            sage: a = 1/(1/3+1/6*t)
            sage: P._normalize_coefficients(a)
            6/(t + 2)
            sage: a = 24/(4*t^2 + 12*t + 8)
            sage: P._normalize_coefficients(a)
            6/(t^2 + 3*t + 2)
        """
        BR = self.base_ring()
        if is_FractionField(BR) and BR.base_ring() == QQ:
            denom = c.denominator()
            numer = c.numerator()

            #Clear the denominators
            a = lcm([i.denominator() for i in denom.coeffs()])
            b = lcm([i.denominator() for i in numer.coeffs()])
            l = Integer(a).lcm(Integer(b))
            denom *= l
            numer *= l

            #Divide through by the gcd of the numerators
            a = gcd([i.numerator() for i in denom.coeffs()])
            b = gcd([i.numerator() for i in numer.coeffs()])
            l = Integer(a).gcd(Integer(b))

            denom = denom / l
            numer = numer / l
            
            return c.parent()(numer, denom)
        else:
            return c
Esempio n. 6
0
 def arith_prod_of_partitions(l1, l2):
     # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by
     # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes
     # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2`
     # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a
     # partition of `nm`.
     term_iterable = chain.from_iterable( repeat(lcm(pair), times=gcd(pair)) for pair in product(l1, l2) )
     term_list = sorted(term_iterable, reverse=True)
     res = Partition(term_list)
     return res
Esempio n. 7
0
 def arith_prod_of_partitions(l1, l2):
     # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by
     # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes
     # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2`
     # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a
     # partition of `nm`.
     term_iterable = chain.from_iterable( repeat(lcm(pair), times=gcd(pair)) for pair in product(l1, l2) )
     term_list = sorted(term_iterable, reverse=True)
     res = Partition(term_list)
     return res
Esempio n. 8
0
    def _upper_bound_for_longest_cycle(self, s):
        """
        EXAMPLES::

            sage: cis = species.PartitionSpecies().cycle_index_series()
            sage: cis._upper_bound_for_longest_cycle([4])
            4
            sage: cis._upper_bound_for_longest_cycle([3,1])
            3
            sage: cis._upper_bound_for_longest_cycle([2,2])
            2
            sage: cis._upper_bound_for_longest_cycle([2,1,1])
            2
            sage: cis._upper_bound_for_longest_cycle([1,1,1,1])
            1
        """
        if s == []:
            return 1
        return min(self._card(sum(s)), lcm(list(s)))
Esempio n. 9
0
    def _upper_bound_for_longest_cycle(self, s):
        """
        EXAMPLES::

            sage: cis = species.PartitionSpecies().cycle_index_series()
            sage: cis._upper_bound_for_longest_cycle([4])
            4
            sage: cis._upper_bound_for_longest_cycle([3,1])
            3
            sage: cis._upper_bound_for_longest_cycle([2,2])
            2
            sage: cis._upper_bound_for_longest_cycle([2,1,1])
            2
            sage: cis._upper_bound_for_longest_cycle([1,1,1,1])
            1
        """
        if s == []:
            return 1
        return min(self._card(sum(s)), lcm(list(s)))
Esempio n. 10
0
    def exponent(self):
        """
        Return the exponent of this finite abelian group.

        OUTPUT: Integer

        EXAMPLES::

            sage: t = J0(33).hecke_operator(7)
            sage: G = t.kernel()[0]; G
            Finite subgroup with invariants [2, 2, 2, 2, 4, 4] over QQ of Abelian variety J0(33) of dimension 3
            sage: G.exponent()
            4
        """
        try:
            return self.__exponent
        except AttributeError:
            e = lcm(self.invariants())
            self.__exponent = e
            return e
Esempio n. 11
0
 def exponent(self):
     """
     Return the exponent of this finite abelian group.
     
     OUTPUT: Integer
     
     EXAMPLES::
     
         sage: t = J0(33).hecke_operator(7)
         sage: G = t.kernel()[0]; G
         Finite subgroup with invariants [2, 2, 2, 2, 4, 4] over QQ of Abelian variety J0(33) of dimension 3
         sage: G.exponent()
         4
     """
     try:
         return self.__exponent
     except AttributeError:
         e = lcm(self.invariants())
         self.__exponent = e
         return e
Esempio n. 12
0
    def additive_order(self):
        """
        Return the additive order of this element.

        EXAMPLES::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (4, 12)
            sage: Q.0.additive_order()
            4
            sage: Q.1.additive_order()
            12
            sage: (Q.0+Q.1).additive_order()
            12
            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (12, 0)
            sage: Q.0.additive_order()
            12
            sage: type(Q.0.additive_order())
            <type 'sage.rings.integer.Integer'>
            sage: Q.1.additive_order()
            +Infinity
        """
        Q = self.parent()
        I = Q.invariants()
        v = self.vector()

        from sage.rings.all import infinity, lcm, Mod, Integer
        n = Integer(1)
        for i, a in enumerate(I):
            if a == 0:
                if v[i] != 0:
                    return infinity
            else:
                n = lcm(n, Mod(v[i],a).additive_order())
        return n
Esempio n. 13
0
    def additive_order(self):
        """
        Return the additive order of this element.

        EXAMPLES::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (4, 12)
            sage: Q.0.additive_order()
            4
            sage: Q.1.additive_order()
            12
            sage: (Q.0+Q.1).additive_order()
            12
            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (12, 0)
            sage: Q.0.additive_order()
            12
            sage: type(Q.0.additive_order())
            <type 'sage.rings.integer.Integer'>
            sage: Q.1.additive_order()
            +Infinity
        """
        Q = self.parent()
        I = Q.invariants()
        v = self.vector()

        from sage.rings.all import infinity, lcm, Mod, Integer
        n = Integer(1)
        for i, a in enumerate(I):
            if a == 0:
                if v[i] != 0:
                    return infinity
            else:
                n = lcm(n, Mod(v[i], a).additive_order())
        return n
Esempio n. 14
0
    def weil_representation(self):
        r"""
        OUTPUT:
        
        - A pair of matrices corresponding to T and S.
        """
        disc_bilinear = lambda a, b: (self._dual_basis * vector(QQ, a.lift(
        ))) * self._L * (self._dual_basis * vector(QQ, b.lift()))
        disc_quadratic = lambda a: disc_bilinear(a, a) / ZZ(2)

        zeta_order = ZZ(
            lcm([8, 12, prod(self.invariants())] +
                map(lambda ed: 2 * ed, self.invariants())))
        K = CyclotomicField(zeta_order)
        zeta = K.gen()

        R = PolynomialRing(K, 'x')
        x = R.gen()
        #        sqrt2s = (x**2 - 2).factor()
        #        if sqrt2s[0][0][0].complex_embedding().real() > 0 :
        #            sqrt2  = sqrt2s[0][0][0]
        #        else :
        #            sqrt2  = sqrt2s[0][1]
        Ldet_rts = (x**2 - prod(self.invariants())).factor()
        if Ldet_rts[0][0][0].complex_embedding().real() > 0:
            Ldet_rt = Ldet_rts[0][0][0]
        else:
            Ldet_rt = Ldet_rts[0][0][0]

        Tmat = diagonal_matrix(
            K, [zeta**(zeta_order * disc_quadratic(a)) for a in self])
        Smat = zeta**(zeta_order / 8 * self._L.nrows()) / Ldet_rt  \
               * matrix( K,  [ [ zeta**ZZ(-zeta_order * disc_bilinear(gamma,delta))
                                 for delta in self ]
                               for gamma in self ])

        return (Tmat, Smat)
Esempio n. 15
0
def cyclotomic_restriction(L,K):
    r"""
    Given two cyclotomic fields L and K, compute the compositum
    M of K and L, and return a function and the index [M:K]. The
    function is a map that acts as follows (here `M = Q(\zeta_m)`):

    INPUT:

    element alpha in L

    OUTPUT:

    a polynomial `f(x)` in `K[x]` such that `f(\zeta_m) = \alpha`,
    where we view alpha as living in `M`. (Note that `\zeta_m`
    generates `M`, not `L`.)

    EXAMPLES::
    
        sage: L = CyclotomicField(12) ; N = CyclotomicField(33) ; M = CyclotomicField(132)
        sage: z, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L,N)
        sage: n
        2
        
        sage: z(L.0)
        -zeta33^19*x
        sage: z(L.0)(M.0)
        zeta132^11

        sage: z(L.0^3-L.0+1)
        (zeta33^19 + zeta33^8)*x + 1
        sage: z(L.0^3-L.0+1)(M.0)
        zeta132^33 - zeta132^11 + 1
        sage: z(L.0^3-L.0+1)(M.0) - M(L.0^3-L.0+1)
        0
    """
    if not L.has_coerce_map_from(K):
        M = CyclotomicField(lcm(L.zeta_order(), K.zeta_order()))
        f = cyclotomic_restriction_tower(M,K)
        def g(x):
            """
            Function returned by cyclotomic restriction.

            INPUT:

            element alpha in L

            OUTPUT:
            
            a polynomial `f(x)` in `K[x]` such that `f(\zeta_m) = \alpha`,
            where we view alpha as living in `M`. (Note that `\zeta_m`
            generates `M`, not `L`.)            

            EXAMPLES::
            
                sage: L = CyclotomicField(12)
                sage: N = CyclotomicField(33)
                sage: g, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L,N)
                sage: g(L.0)
                -zeta33^19*x
            """
            return f(M(x))
        return g, euler_phi(M.zeta_order())//euler_phi(K.zeta_order())
    else:
        return cyclotomic_restriction_tower(L,K), \
               euler_phi(L.zeta_order())//euler_phi(K.zeta_order())
Esempio n. 16
0
def mod5family(a, b):
    """
    Formulas for computing the family of elliptic curves with
    congruent mod-5 representation.

    AUTHORS:
        -- Alice Silverberg and Karl Rubin (original PARI/GP version)
        -- William Stein -- Sage version.
    """
    J = 4 * a**3 / (4 * a**3 + 27 * b**2)

    alpha = [0 for _ in range(21)]
    alpha[0] = 1
    alpha[1] = 0
    alpha[2] = 190 * (J - 1)
    alpha[3] = -2280 * (J - 1)**2
    alpha[4] = 855 * (J - 1)**2 * (-17 + 16 * J)
    alpha[5] = 3648 * (J - 1)**3 * (17 - 9 * J)
    alpha[6] = 11400 * (J - 1)**3 * (17 - 8 * J)
    alpha[7] = -27360 * (J - 1)**4 * (17 + 26 * J)
    alpha[8] = 7410 * (J - 1)**4 * (-119 - 448 * J + 432 * J**2)
    alpha[9] = 79040 * (J - 1)**5 * (17 + 145 * J - 108 * J**2)
    alpha[10] = 8892 * (J - 1)**5 * (187 + 2640 * J - 5104 * J**2 +
                                     1152 * J**3)
    alpha[11] = 98800 * (J - 1)**6 * (-17 - 388 * J + 864 * J**2)
    alpha[12] = 7410 * (J - 1)**6 * (-187 - 6160 * J + 24464 * J**2 -
                                     24192 * J**3)
    alpha[13] = 54720 * (J - 1)**7 * (17 + 795 * J - 3944 * J**2 + 9072 * J**3)
    alpha[14] = 2280 * (J - 1)**7 * (221 + 13832 * J - 103792 * J**2 +
                                     554112 * J**3 - 373248 * J**4)
    alpha[15] = 1824 * (J - 1)**8 * (-119 - 9842 * J + 92608 * J**2 -
                                     911520 * J**3 + 373248 * J**4)
    alpha[16] = 4275 * (J - 1)**8 * (-17 - 1792 * J + 23264 * J**2 -
                                     378368 * J**3 + 338688 * J**4)
    alpha[17] = 18240 * (J - 1)**9 * (1 + 133 * J - 2132 * J**2 +
                                      54000 * J**3 - 15552 * J**4)
    alpha[18] = 190 * (J - 1)**9 * (17 + 2784 * J - 58080 * J**2 + 2116864 *
                                    J**3 - 946944 * J**4 + 2985984 * J**5)
    alpha[19] = 360 * (J - 1)**10 * (-1 + 28 * J - 1152 * J**2) * (
        1 + 228 * J + 176 * J**2 + 1728 * J**3)
    alpha[20] = (J - 1)**10 * (-19 - 4560 * J + 144096 * J**2 -
                               9859328 * J**3 - 8798976 * J**4 -
                               226934784 * J**5 + 429981696 * J**6)

    beta = [0 for _ in range(31)]
    beta[0] = 1
    beta[1] = 30
    beta[2] = -435 * (J - 1)
    beta[3] = 580 * (J - 1) * (-7 + 9 * J)
    beta[4] = 3915 * (J - 1)**2 * (7 - 8 * J)
    beta[5] = 1566 * (J - 1)**2 * (91 - 78 * J + 48 * J**2)
    beta[6] = -84825 * (J - 1)**3 * (7 + 16 * J)
    beta[7] = 156600 * (J - 1)**3 * (-13 - 91 * J + 92 * J**2)
    beta[8] = 450225 * (J - 1)**4 * (13 + 208 * J - 144 * J**2)
    beta[9] = 100050 * (J - 1)**4 * (143 + 4004 * J - 5632 * J**2 +
                                     1728 * J**3)
    beta[10] = 30015 * (J - 1)**5 * (-1001 - 45760 * J + 44880 * J**2 -
                                     6912 * J**3)
    beta[11] = 600300 * (J - 1)**5 * (-91 - 6175 * J + 9272 * J**2 -
                                      2736 * J**3)
    beta[12] = 950475 * (J - 1)**6 * (91 + 8840 * J - 7824 * J**2)
    beta[13] = 17108550 * (J - 1)**6 * (7 + 926 * J - 1072 * J**2 + 544 * J**3)
    beta[14] = 145422675 * (J - 1)**7 * (-1 - 176 * J + 48 * J**2 - 384 * J**3)
    beta[15] = 155117520 * (J - 1)**8 * (1 + 228 * J + 176 * J**2 +
                                         1728 * J**3)
    beta[16] = 145422675 * (J - 1)**8 * (1 + 288 * J + 288 * J**2 +
                                         5120 * J**3 - 6912 * J**4)
    beta[17] = 17108550 * (J - 1)**8 * (7 + 2504 * J + 3584 * J**2 + 93184 *
                                        J**3 - 283392 * J**4 + 165888 * J**5)
    beta[18] = 950475 * (J - 1)**9 * (-91 - 39936 * J - 122976 * J**2 -
                                      2960384 * J**3 + 11577600 * J**4 -
                                      5971968 * J**5)
    beta[19] = 600300 * (J - 1)**9 * (-91 - 48243 * J - 191568 * J**2 -
                                      6310304 * J**3 + 40515072 * J**4 -
                                      46455552 * J**5 + 11943936 * J**6)
    beta[20] = 30015 * (J - 1)**10 * (1001 + 634920 * J + 3880800 * J**2 +
                                      142879744 * J**3 - 1168475904 * J**4 +
                                      1188919296 * J**5 - 143327232 * J**6)
    beta[21] = 100050 * (J - 1)**10 * (143 + 107250 * J + 808368 * J**2 +
                                       38518336 * J**3 - 451953408 * J**4 +
                                       757651968 * J**5 - 367276032 * J**6)
    beta[22] = 450225 * (J - 1)**11 * (-13 - 11440 * J - 117216 * J**2 -
                                       6444800 * J**3 + 94192384 * J**4 -
                                       142000128 * J**5 + 95551488 * J**6)
    beta[23] = 156600 * (J - 1)**11 * (
        -13 - 13299 * J - 163284 * J**2 - 11171552 * J**3 + 217203840 * J**4 -
        474406656 * J**5 + 747740160 * J**6 - 429981696 * J**7)
    beta[24] = 6525*(J - 1)**12*(91 + 107536*J + 1680624*J**2 + 132912128*J**3 -\
          3147511552*J**4 + 6260502528*J**5 - 21054173184*J**6 + 10319560704*J**7)
    beta[25] = 1566*(J - 1)**12*(91 + 123292*J + 2261248*J**2 + 216211904*J**3 - \
          6487793920*J**4 + 17369596928*J**5 - 97854234624*J**6 + 96136740864*J**7 - 20639121408*J**8)
    beta[26] = 3915*(J - 1)**13*(-7 - 10816*J - 242352*J**2 - 26620160*J**3 + 953885440*J**4 - \
          2350596096*J**5 + 26796552192*J**6 - 13329432576*J**7)
    beta[27] = 580*(J - 1)**13*(-7 - 12259*J - 317176*J**2 - 41205008*J**3 + \
          1808220160*J**4 - 5714806016*J**5 + 93590857728*J**6 - 70131806208*J**7 - 36118462464*J**8)
    beta[28] = 435*(J - 1)**14*(1 + 1976*J + 60720*J**2 + 8987648*J**3 - 463120640*J**4 + 1359157248*J**5 - \
          40644882432*J**6 - 5016453120*J**7 + 61917364224*J**8)
    beta[29] = 30*(J - 1)**14*(1 + 2218*J + 77680*J**2 + 13365152*J**3 - \
          822366976*J**4 + 2990693888*J**5 - 118286217216*J**6 - 24514928640*J**7 + 509958291456*J**8 - 743008370688*J**9)
    beta[30] = (J - 1)**15*(-1 - 2480*J - 101040*J**2 - 19642496*J**3 + 1399023872*J**4 - \
          4759216128*J**5 + 315623485440*J**6 + 471904911360*J**7 - 2600529297408*J**8 + 8916100448256*J**9)

    R = PolynomialRing(QQ, 't')
    b4 = a * R(alpha)
    b6 = b * R(beta)

    c2 = b4
    c3 = b6
    d = lcm(c2.denominator(), c3.denominator())
    F = FractionField(R)

    E = EllipticCurve(F, [c2 * d**4, c3 * d**6])
    return E
Esempio n. 17
0
def cyclotomic_restriction(L, K):
    r"""
    Given two cyclotomic fields L and K, compute the compositum
    M of K and L, and return a function and the index [M:K]. The
    function is a map that acts as follows (here `M = Q(\zeta_m)`):

    INPUT:

    element alpha in L

    OUTPUT:

    a polynomial `f(x)` in `K[x]` such that `f(\zeta_m) = \alpha`,
    where we view alpha as living in `M`. (Note that `\zeta_m`
    generates `M`, not `L`.)

    EXAMPLES::
    
        sage: L = CyclotomicField(12) ; N = CyclotomicField(33) ; M = CyclotomicField(132)
        sage: z, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L,N)
        sage: n
        2
        
        sage: z(L.0)
        -zeta33^19*x
        sage: z(L.0)(M.0)
        zeta132^11

        sage: z(L.0^3-L.0+1)
        (zeta33^19 + zeta33^8)*x + 1
        sage: z(L.0^3-L.0+1)(M.0)
        zeta132^33 - zeta132^11 + 1
        sage: z(L.0^3-L.0+1)(M.0) - M(L.0^3-L.0+1)
        0
    """
    if not L.has_coerce_map_from(K):
        M = CyclotomicField(lcm(L.zeta_order(), K.zeta_order()))
        f = cyclotomic_restriction_tower(M, K)

        def g(x):
            """
            Function returned by cyclotomic restriction.

            INPUT:

            element alpha in L

            OUTPUT:
            
            a polynomial `f(x)` in `K[x]` such that `f(\zeta_m) = \alpha`,
            where we view alpha as living in `M`. (Note that `\zeta_m`
            generates `M`, not `L`.)            

            EXAMPLES::
            
                sage: L = CyclotomicField(12)
                sage: N = CyclotomicField(33)
                sage: g, n = sage.modular.modform.eisenstein_submodule.cyclotomic_restriction(L,N)
                sage: g(L.0)
                -zeta33^19*x
            """
            return f(M(x))

        return g, euler_phi(M.zeta_order()) // euler_phi(K.zeta_order())
    else:
        return cyclotomic_restriction_tower(L,K), \
               euler_phi(L.zeta_order())//euler_phi(K.zeta_order())
Esempio n. 18
0
def mod5family(a,b):
    """
    Formulas for computing the family of elliptic curves with
    congruent mod-5 representation.

    AUTHORS:
        -- Alice Silverberg and Karl Rubin (original PARI/GP version)
        -- William Stein -- Sage version.
    """
    J = 4*a**3 / (4*a**3+27*b**2)

    alpha = [0 for _ in range(21)]
    alpha[0] = 1
    alpha[1] = 0
    alpha[2] = 190*(J - 1)
    alpha[3] = -2280*(J - 1)**2
    alpha[4] = 855*(J - 1)**2*(-17 + 16*J)
    alpha[5] = 3648*(J - 1)**3*(17 - 9*J)
    alpha[6] = 11400*(J - 1)**3*(17 - 8*J)
    alpha[7] = -27360*(J - 1)**4*(17 + 26*J)
    alpha[8] = 7410*(J - 1)**4*(-119 - 448*J + 432*J**2)
    alpha[9] = 79040*(J - 1)**5*(17 + 145*J - 108*J**2)
    alpha[10] = 8892*(J - 1)**5*(187 + 2640*J - 5104*J**2 + 1152*J**3)
    alpha[11] = 98800*(J - 1)**6*(-17 - 388*J + 864*J**2)
    alpha[12] = 7410*(J - 1)**6*(-187 - 6160*J + 24464*J**2 - 24192*J**3)
    alpha[13] = 54720*(J - 1)**7*(17 + 795*J - 3944*J**2 + 9072*J**3)
    alpha[14] = 2280*(J - 1)**7*(221 + 13832*J - 103792*J**2 + 554112*J**3 - 373248*J**4)
    alpha[15] = 1824*(J - 1)**8*(-119 - 9842*J + 92608*J**2 - 911520*J**3 + 373248*J**4)
    alpha[16] = 4275*(J - 1)**8*(-17 - 1792*J + 23264*J**2 - 378368*J**3 + 338688*J**4)
    alpha[17] = 18240*(J - 1)**9*(1 + 133*J - 2132*J**2 + 54000*J**3 - 15552*J**4)
    alpha[18] = 190*(J - 1)**9*(17 + 2784*J - 58080*J**2 + 2116864*J**3 - 946944*J**4 + 2985984*J**5)
    alpha[19] = 360*(J - 1)**10*(-1 + 28*J - 1152*J**2)*(1 + 228*J + 176*J**2 + 1728*J**3)
    alpha[20] = (J - 1)**10*(-19 - 4560*J + 144096*J**2 - 9859328*J**3 - 8798976*J**4 - 226934784*J**5 + 429981696*J**6)

    beta = [0 for _ in range(31)]
    beta[0] = 1
    beta[1] = 30
    beta[2] = -435*(J - 1)
    beta[3] = 580*(J - 1)*(-7 + 9*J)
    beta[4] = 3915*(J - 1)**2*(7 - 8*J)
    beta[5] = 1566*(J - 1)**2*(91 - 78*J + 48*J**2)
    beta[6] = -84825*(J - 1)**3*(7 + 16*J)
    beta[7] = 156600*(J - 1)**3*(-13 - 91*J + 92*J**2)
    beta[8] = 450225*(J - 1)**4*(13 + 208*J - 144*J**2)
    beta[9] = 100050*(J - 1)**4*(143 + 4004*J - 5632*J**2 + 1728*J**3)
    beta[10] = 30015*(J - 1)**5*(-1001 - 45760*J + 44880*J**2 - 6912*J**3)
    beta[11] = 600300*(J - 1)**5*(-91 - 6175*J + 9272*J**2 - 2736*J**3)
    beta[12] = 950475*(J - 1)**6*(91 + 8840*J - 7824*J**2)
    beta[13] = 17108550*(J - 1)**6*(7 + 926*J - 1072*J**2 + 544*J**3)
    beta[14] = 145422675*(J - 1)**7*(-1 - 176*J + 48*J**2 - 384*J**3)
    beta[15] = 155117520*(J - 1)**8*(1 + 228*J + 176*J**2 + 1728*J**3)
    beta[16] = 145422675*(J - 1)**8*(1 + 288*J + 288*J**2 + 5120*J**3 - 6912*J**4)
    beta[17] = 17108550*(J - 1)**8*(7 + 2504*J + 3584*J**2 + 93184*J**3 - 283392*J**4 + 165888*J**5)
    beta[18] = 950475*(J - 1)**9*(-91 - 39936*J - 122976*J**2 - 2960384*J**3 + 11577600*J**4 - 5971968*J**5)
    beta[19] = 600300*(J - 1)**9*(-91 - 48243*J - 191568*J**2 - 6310304*J**3 + 40515072*J**4 - 46455552*J**5 + 11943936*J**6)
    beta[20] = 30015*(J - 1)**10*(1001 + 634920*J + 3880800*J**2 + 142879744*J**3 - 1168475904*J**4 + 1188919296*J**5 - 143327232*J**6)
    beta[21] = 100050*(J - 1)**10*(143 + 107250*J + 808368*J**2 + 38518336*J**3 - 451953408*J**4 + 757651968*J**5 - 367276032*J**6)
    beta[22] = 450225*(J - 1)**11*(-13 - 11440*J - 117216*J**2 - 6444800*J**3 + 94192384*J**4 - 142000128*J**5 + 95551488*J**6)
    beta[23] = 156600*(J - 1)**11*(-13 - 13299*J - 163284*J**2 - 11171552*J**3 +  217203840*J**4 - 474406656*J**5 + 747740160*J**6 - 429981696*J**7)
    beta[24] = 6525*(J - 1)**12*(91 + 107536*J + 1680624*J**2 + 132912128*J**3 -\
          3147511552*J**4 + 6260502528*J**5 - 21054173184*J**6 + 10319560704*J**7)
    beta[25] = 1566*(J - 1)**12*(91 + 123292*J + 2261248*J**2 + 216211904*J**3 - \
          6487793920*J**4 + 17369596928*J**5 - 97854234624*J**6 + 96136740864*J**7 - 20639121408*J**8)
    beta[26] = 3915*(J - 1)**13*(-7 - 10816*J - 242352*J**2 - 26620160*J**3 + 953885440*J**4 - \
          2350596096*J**5 + 26796552192*J**6 - 13329432576*J**7)
    beta[27] = 580*(J - 1)**13*(-7 - 12259*J - 317176*J**2 - 41205008*J**3 + \
          1808220160*J**4 - 5714806016*J**5 + 93590857728*J**6 - 70131806208*J**7 - 36118462464*J**8)
    beta[28] = 435*(J - 1)**14*(1 + 1976*J + 60720*J**2 + 8987648*J**3 - 463120640*J**4 + 1359157248*J**5 - \
          40644882432*J**6 - 5016453120*J**7 + 61917364224*J**8)
    beta[29] = 30*(J - 1)**14*(1 + 2218*J + 77680*J**2 + 13365152*J**3 - \
          822366976*J**4 + 2990693888*J**5 - 118286217216*J**6 - 24514928640*J**7 + 509958291456*J**8 - 743008370688*J**9)
    beta[30] = (J - 1)**15*(-1 - 2480*J - 101040*J**2 - 19642496*J**3 + 1399023872*J**4 - \
          4759216128*J**5 + 315623485440*J**6 + 471904911360*J**7 - 2600529297408*J**8 + 8916100448256*J**9)

    R = PolynomialRing(QQ, 't')
    b4 = a * R(alpha)
    b6 = b * R(beta)

    c2 = b4
    c3 = b6
    d = lcm(c2.denominator(), c3.denominator())
    F = FractionField(R)

    E = EllipticCurve(F, [c2*d**4, c3*d**6])
    return E
Esempio n. 19
0
def dimension__vector_valued(k, L, conjugate=False):
    r"""
    Compute the dimension of the space of weight `k` vector valued modular forms
    for the Weil representation (or its conjugate) attached to the lattice `L`.
    
    See [Borcherds, Borcherds - Reflection groups of Lorentzian lattices] for a proof
    of the formula that we use here.
    
    INPUT:
    
    - `k` -- A half-integer.
    
    - ``L`` -- An quadratic form.
    
    - ``conjugate`` -- A boolean; If ``True``, then compute the dimension for
                       the conjugated Weil representation.
    
    OUTPUT:
        An integer.

    TESTS::

        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 1, 1, 2])))
        1
        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 2])))
        1
        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 4])))
        1
    """
    if 2 * k not in ZZ:
        raise ValueError("Weight must be half-integral")
    if k <= 0:
        return 0
    if k < 2:
        raise NotImplementedError("Weight <2 is not implemented.")

    if L.matrix().rank() != L.matrix().nrows():
        raise ValueError(
            "The lattice (={0}) must be non-degenerate.".format(L))

    L_dimension = L.matrix().nrows()
    if L_dimension % 2 != ZZ(2 * k) % 2:
        return 0

    plus_basis = ZZ(L_dimension + 2 * k) % 4 == 0

    ## The bilinear and the quadratic form attached to L
    quadratic = lambda x: L(x) // 2
    bilinear = lambda x, y: L(x + y) - L(x) - L(y)

    ## A dual basis for L
    (elementary_divisors, dual_basis_pre, _) = L.matrix().smith_form()
    elementary_divisors = elementary_divisors.diagonal()
    dual_basis = map(operator.div, list(dual_basis_pre), elementary_divisors)

    L_level = ZZ(lcm([b.denominator() for b in dual_basis]))

    (elementary_divisors, _, discriminant_basis_pre) = (
        L_level * matrix(dual_basis)).change_ring(ZZ).smith_form()
    elementary_divisors = filter(lambda d: d not in ZZ,
                                 (elementary_divisors / L_level).diagonal())
    elementary_divisors_inv = map(ZZ, [ed**-1 for ed in elementary_divisors])
    discriminant_basis = matrix(
        map(operator.mul,
            discriminant_basis_pre.inverse().rows()[:len(elementary_divisors)],
            elementary_divisors)).transpose()
    ## This is a form over QQ, so that we cannot use an instance of QuadraticForm
    discriminant_form = discriminant_basis.transpose() * L.matrix(
    ) * discriminant_basis

    if conjugate:
        discriminant_form = -discriminant_form

    if prod(elementary_divisors_inv) > 100:
        disc_den = discriminant_form.denominator()
        disc_bilinear_pre = \
            cython_lambda( ', '.join(   ['int a{0}'.format(i) for i in range(discriminant_form.nrows())]
                                        + ['int b{0}'.format(i) for i in range(discriminant_form.nrows())] ),
                           ' + '.join('{0} * a{1} * b{2}'.format(disc_den * discriminant_form[i,j], i, j)
                                      for i in range(discriminant_form.nrows())
                                      for j in range(discriminant_form.nrows())) )
        disc_bilinear = lambda *a: disc_bilinear_pre(*a) / disc_den
    else:
        disc_bilinear = lambda *xy: vector(ZZ, xy[:discriminant_form.nrows(
        )]) * discriminant_form * vector(ZZ, xy[discriminant_form.nrows():])

    disc_quadratic = lambda *a: disc_bilinear(*(2 * a)) / 2

    ## red gives a normal form for elements in the discriminant group
    red = lambda x: map(operator.mod, x, elementary_divisors_inv)

    def is_singl(x):
        y = red(map(operator.neg, x))
        for (e, f) in zip(x, y):
            if e < f:
                return -1
            elif e > f:
                return 1
        return 0

    ## singls and pairs are elements of the discriminant group that are, respectively,
    ## fixed and not fixed by negation.
    singls = list()
    pairs = list()
    for x in mrange(elementary_divisors_inv):
        si = is_singl(x)
        if si == 0:
            singls.append(x)
        elif si == 1:
            pairs.append(x)

    if plus_basis:
        subspace_dimension = len(singls + pairs)
    else:
        subspace_dimension = len(pairs)

    ## 200 bits are, by far, sufficient to distinguish 12-th roots of unity
    ## by increasing the precision by 4 for each additional dimension, we
    ## compensate, by far, the errors introduced by the QR decomposition,
    ## which are of the size of (absolute error) * dimension
    CC = ComplexIntervalField(200 + subspace_dimension * 4)

    zeta_order = ZZ(
        lcm([8, 12] + map(lambda ed: 2 * ed, elementary_divisors_inv)))

    zeta = CC(exp(2 * pi * I / zeta_order))
    sqrt2 = CC(sqrt(2))
    drt = CC(sqrt(L.det()))

    Tmat = diagonal_matrix(CC, [
        zeta**(zeta_order * disc_quadratic(*a))
        for a in (singls + pairs if plus_basis else pairs)
    ])
    if plus_basis:
        Smat = zeta**(zeta_order / 8 * L_dimension) / drt  \
               * matrix( CC, [  [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls]
                              + [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in pairs]
                              for gamma in singls] \
                           + [  [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls]
                              + [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) + zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg, delta)))) for delta in pairs]
                              for gamma in pairs] )
    else:
        Smat = zeta**(zeta_order / 8 * L_dimension) / drt  \
               * matrix( CC, [  [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) - zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg,delta))))  for delta in pairs]
                               for gamma in pairs ] )
    STmat = Smat * Tmat

    ## This function overestimates the number of eigenvalues, if it is not correct
    def eigenvalue_multiplicity(mat, ev):
        mat = matrix(CC, mat - ev * identity_matrix(subspace_dimension))
        return len(
            filter(lambda row: all(e.contains_zero() for e in row),
                   _qr(mat).rows()))

    rti = CC(exp(2 * pi * I / 8))
    S_ev_multiplicity = [
        eigenvalue_multiplicity(Smat, rti**n) for n in range(8)
    ]
    ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities
    ## this asserts that the computed multiplicities are correct
    assert sum(S_ev_multiplicity) == subspace_dimension

    rho = CC(exp(2 * pi * I / 12))
    ST_ev_multiplicity = [
        eigenvalue_multiplicity(STmat, rho**n) for n in range(12)
    ]
    ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities
    ## this asserts that the computed multiplicities are correct
    assert sum(ST_ev_multiplicity) == subspace_dimension

    T_evs = [
        ZZ((zeta_order * disc_quadratic(*a)) % zeta_order) / zeta_order
        for a in (singls + pairs if plus_basis else pairs)
    ]

    return subspace_dimension * (1 + QQ(k) / 12) \
           - ZZ(sum( (ST_ev_multiplicity[n] * ((-2 * k - n) % 12)) for n in range(12) )) / 12 \
           - ZZ(sum( (S_ev_multiplicity[n] * ((2 * k + n) % 8)) for n in range(8) )) / 8 \
           - sum(T_evs)
def dimension__vector_valued(k, L, conjugate = False) :
    r"""
    Compute the dimension of the space of weight `k` vector valued modular forms
    for the Weil representation (or its conjugate) attached to the lattice `L`.
    
    See [Borcherds, Borcherds - Reflection groups of Lorentzian lattices] for a proof
    of the formula that we use here.
    
    INPUT:
    
    - `k` -- A half-integer.
    
    - ``L`` -- An quadratic form.
    
    - ``conjugate`` -- A boolean; If ``True``, then compute the dimension for
                       the conjugated Weil representation.
    
    OUTPUT:
        An integer.

    TESTS::

        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 1, 1, 2])))
        1
        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 2])))
        1
        sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 4])))
        1
    """
    if 2 * k not in ZZ :
        raise ValueError( "Weight must be half-integral" ) 
    if k <= 0 :
        return 0
    if k < 2 :
        raise NotImplementedError( "Weight <2 is not implemented." )

    if L.matrix().rank() != L.matrix().nrows() :
        raise ValueError( "The lattice (={0}) must be non-degenerate.".format(L) )

    L_dimension = L.matrix().nrows()
    if L_dimension % 2 != ZZ(2 * k) % 2 :
        return 0
    
    plus_basis = ZZ(L_dimension + 2 * k) % 4 == 0 

    ## The bilinear and the quadratic form attached to L
    quadratic = lambda x: L(x) // 2
    bilinear = lambda x,y: L(x + y) - L(x) - L(y)

    ## A dual basis for L
    (elementary_divisors, dual_basis_pre, _) = L.matrix().smith_form()
    elementary_divisors = elementary_divisors.diagonal()
    dual_basis = map(operator.div, list(dual_basis_pre), elementary_divisors)
    
    L_level = ZZ(lcm([ b.denominator() for b in dual_basis ]))
    
    (elementary_divisors, _, discriminant_basis_pre) = (L_level * matrix(dual_basis)).change_ring(ZZ).smith_form()
    elementary_divisors = filter( lambda d: d not in ZZ, (elementary_divisors / L_level).diagonal() )
    elementary_divisors_inv = map(ZZ, [ed**-1 for ed in elementary_divisors])
    discriminant_basis = matrix(map( operator.mul,
                                     discriminant_basis_pre.inverse().rows()[:len(elementary_divisors)],
                                     elementary_divisors )).transpose()
    ## This is a form over QQ, so that we cannot use an instance of QuadraticForm
    discriminant_form = discriminant_basis.transpose() * L.matrix() * discriminant_basis

    if conjugate :
        discriminant_form = - discriminant_form

    if prod(elementary_divisors_inv) > 100 :
        disc_den = discriminant_form.denominator()
        disc_bilinear_pre = \
            cython_lambda( ', '.join(   ['int a{0}'.format(i) for i in range(discriminant_form.nrows())]
                                        + ['int b{0}'.format(i) for i in range(discriminant_form.nrows())] ),
                           ' + '.join('{0} * a{1} * b{2}'.format(disc_den * discriminant_form[i,j], i, j)
                                      for i in range(discriminant_form.nrows())
                                      for j in range(discriminant_form.nrows())) )
        disc_bilinear = lambda *a: disc_bilinear_pre(*a) / disc_den
    else :
        disc_bilinear = lambda *xy: vector(ZZ, xy[:discriminant_form.nrows()]) * discriminant_form * vector(ZZ, xy[discriminant_form.nrows():])

    disc_quadratic = lambda *a: disc_bilinear(*(2 * a)) / 2

    ## red gives a normal form for elements in the discriminant group
    red = lambda x : map(operator.mod, x, elementary_divisors_inv)
    def is_singl(x) :
        y = red(map(operator.neg, x))
        for (e, f) in zip(x, y) :
            if e < f :
                return -1
            elif e > f :
                return 1
        return 0
    ## singls and pairs are elements of the discriminant group that are, respectively,
    ## fixed and not fixed by negation.
    singls = list()
    pairs = list()
    for x in mrange(elementary_divisors_inv) :
        si = is_singl(x)
        if si == 0 :
            singls.append(x)
        elif si == 1 :
            pairs.append(x)

    if plus_basis :
        subspace_dimension = len(singls + pairs)
    else :
        subspace_dimension = len(pairs)

    ## 200 bits are, by far, sufficient to distinguish 12-th roots of unity
    ## by increasing the precision by 4 for each additional dimension, we
    ## compensate, by far, the errors introduced by the QR decomposition,
    ## which are of the size of (absolute error) * dimension
    CC = ComplexIntervalField(200 + subspace_dimension * 4)

    zeta_order = ZZ(lcm([8, 12] + map(lambda ed: 2 * ed, elementary_divisors_inv)))

    zeta = CC(exp(2 * pi * I / zeta_order))
    sqrt2  = CC(sqrt(2))
    drt  = CC(sqrt(L.det()))

    Tmat  = diagonal_matrix(CC, [zeta**(zeta_order*disc_quadratic(*a)) for a in (singls + pairs if plus_basis else pairs)])
    if plus_basis :        
        Smat = zeta**(zeta_order / 8 * L_dimension) / drt  \
               * matrix( CC, [  [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls]
                              + [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in pairs]
                              for gamma in singls] \
                           + [  [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls]
                              + [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) + zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg, delta)))) for delta in pairs]
                              for gamma in pairs] )
    else :
        Smat = zeta**(zeta_order / 8 * L_dimension) / drt  \
               * matrix( CC, [  [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) - zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg,delta))))  for delta in pairs]
                               for gamma in pairs ] )
    STmat = Smat * Tmat
    
    ## This function overestimates the number of eigenvalues, if it is not correct
    def eigenvalue_multiplicity(mat, ev) :
        mat = matrix(CC, mat - ev * identity_matrix(subspace_dimension))
        return len(filter( lambda row: all( e.contains_zero() for e in row), _qr(mat).rows() ))
    
    rti = CC(exp(2 * pi * I / 8))
    S_ev_multiplicity = [eigenvalue_multiplicity(Smat, rti**n) for n in range(8)]
    ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities
    ## this asserts that the computed multiplicities are correct
    assert sum(S_ev_multiplicity) == subspace_dimension

    rho = CC(exp(2 * pi * I / 12))
    ST_ev_multiplicity = [eigenvalue_multiplicity(STmat, rho**n) for n in range(12)]
    ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities
    ## this asserts that the computed multiplicities are correct
    assert sum(ST_ev_multiplicity) == subspace_dimension

    T_evs = [ ZZ((zeta_order * disc_quadratic(*a)) % zeta_order) / zeta_order
              for a in (singls + pairs if plus_basis else pairs) ]

    return subspace_dimension * (1 + QQ(k) / 12) \
           - ZZ(sum( (ST_ev_multiplicity[n] * ((-2 * k - n) % 12)) for n in range(12) )) / 12 \
           - ZZ(sum( (S_ev_multiplicity[n] * ((2 * k + n) % 8)) for n in range(8) )) / 8 \
           - sum(T_evs)