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)
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
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
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)))
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
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
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
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 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())
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
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())
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
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)