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 _test__jacobi_torsion_point(phi, weight, torsion_point): r""" Given a list of power series, which are the corrected Taylor coefficients of a Jacobi form, return the specialization to ``torsion_point``. INPUT: - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. - ``torsion_point`` -- A rational. OUPUT: - A power series. TESTS: See jacobi_form_by_taylor_expansion. sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: precision = 50 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fs = [JacobiFormD1NNFactory_class._test__jacobi_torsion_point(phi, weight, 2/3) for phi in phis] sage: fs_vec = [vector(f.padded_list(precision)) for f in fs] sage: mf_span = span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(GammaH(9, [4]), weight).basis()]) sage: all(f_vec in mf_span for f_vec in fs_vec) True FIXME: The case of torsion points of order 5, which should lead to forms for Gamma1(25) fails even in the simplest case. """ from sage.rings.all import CyclotomicField K = CyclotomicField(QQ(torsion_point).denominator()) zeta = K.gen() R = PowerSeriesRing(K, 'q') q = R.gen(0) ch = JacobiFormD1WeightCharacter(weight) coeffs = dict((n, QQ(0)) for n in range(phi.precision().index())) for (n, r) in phi.precision().monoid_filter(): coeffs[n] += zeta**r * phi[(ch, (n, r))] return PowerSeriesRing(K, 'q')(coeffs)
def __common_minimal_basering(chi, psi): """ Find the smallest basering over which chi and psi are valued, and return new chi and psi valued in that ring. EXAMPLES:: sage: sage.modular.modform.eis_series.__common_minimal_basering(DirichletGroup(1)[0], DirichletGroup(1)[0]) (Dirichlet character modulo 1 of conductor 1, Dirichlet character modulo 1 of conductor 1) sage: sage.modular.modform.eis_series.__common_minimal_basering(DirichletGroup(3).0, DirichletGroup(5).0) (Dirichlet character modulo 3 of conductor 3 mapping 2 |--> -1, Dirichlet character modulo 5 of conductor 5 mapping 2 |--> zeta4) sage: sage.modular.modform.eis_series.__common_minimal_basering(DirichletGroup(12).0, DirichletGroup(36).0) (Dirichlet character modulo 12 of conductor 4 mapping 7 |--> -1, 5 |--> 1, Dirichlet character modulo 36 of conductor 4 mapping 19 |--> -1, 29 |--> 1) """ chi = chi.minimize_base_ring() psi = psi.minimize_base_ring() n = lcm(chi.base_ring().zeta().multiplicative_order(), psi.base_ring().zeta().multiplicative_order()) if n <= 2: K = QQ else: K = CyclotomicField(n) chi = chi.change_ring(K) psi = psi.change_ring(K) return chi, psi
def _test__jacobi_torsion_point(phi, weight, torsion_point) : r""" Given a list of power series, which are the corrected Taylor coefficients of a Jacobi form, return the specialization to ``torsion_point``. INPUT: - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. - ``torsion_point`` -- A rational. OUPUT: - A power series. TESTS: See jacobi_form_by_taylor_expansion. sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: precision = 50 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fs = [JacobiFormD1NNFactory_class._test__jacobi_torsion_point(phi, weight, 2/3) for phi in phis] sage: fs_vec = [vector(f.padded_list(precision)) for f in fs] sage: mf_span = span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(GammaH(9, [4]), weight).basis()]) sage: all(f_vec in mf_span for f_vec in fs_vec) True FIXME: The case of torsion points of order 5, which should lead to forms for Gamma1(25) fails even in the simplest case. """ from sage.rings.all import CyclotomicField K = CyclotomicField(QQ(torsion_point).denominator()); zeta = K.gen() R = PowerSeriesRing(K, 'q'); q = R.gen(0) ch = JacobiFormD1WeightCharacter(weight) coeffs = dict( (n, QQ(0)) for n in range(phi.precision().index()) ) for (n, r) in phi.precision().monoid_filter() : coeffs[n] += zeta**r * phi[(ch, (n,r))] return PowerSeriesRing(K, 'q')(coeffs)
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 character_table(self): r""" Return the matrix of values of the irreducible characters of this group `G` at its conjugacy classes. The columns represent the conjugacy classes of `G` and the rows represent the different irreducible characters in the ordering given by GAP. OUTPUT: a matrix defined over a cyclotomic field EXAMPLES:: sage: MatrixGroup(SymmetricGroup(2)).character_table() [ 1 -1] [ 1 1] sage: MatrixGroup(SymmetricGroup(3)).character_table() [ 1 1 -1] [ 2 -1 0] [ 1 1 1] sage: MatrixGroup(SymmetricGroup(5)).character_table() [ 1 -1 -1 1 -1 1 1] [ 4 0 1 -1 -2 1 0] [ 5 1 -1 0 -1 -1 1] [ 6 0 0 1 0 0 -2] [ 5 -1 1 0 1 -1 1] [ 4 0 -1 -1 2 1 0] [ 1 1 1 1 1 1 1] """ #code from function in permgroup.py, but modified for #how gap handles these groups. G = self._gap_() cl = self.conjugacy_classes() from sage.rings.integer import Integer n = Integer(len(cl)) irrG = G.Irr() ct = [[irrG[i][j] for j in range(n)] for i in range(n)] from sage.rings.all import CyclotomicField e = irrG.Flat().Conductor() K = CyclotomicField(e) ct = [[K(x) for x in v] for v in ct] # Finally return the result as a matrix. from sage.matrix.all import MatrixSpace MS = MatrixSpace(K, n) return MS(ct)
def __init__(self, G, values): r""" Return the character of the group ``G`` with values given by the list values. The order of the values must correspond to the output of ``G.conjugacy_classes_representatives()``. EXAMPLES:: sage: G = CyclicPermutationGroup(4) sage: values = [1, -1, 1, -1] sage: chi = ClassFunction(G, values); chi Character of Cyclic group of order 4 as a permutation group """ self._group = G if isinstance(values, GapElement) and gap.IsClassFunction(values): self._gap_classfunction = values else: self._gap_classfunction = gap.ClassFunction(G, list(values)) e = self._gap_classfunction.Conductor() self._base_ring = CyclotomicField(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): r""" 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 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 hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False): r""" Given a basis `B` of `q`-expansions for a space of modular forms with character `\varepsilon` to precision at least `\#B\cdot n+1`, this function computes the matrix of `T_n` relative to `B`. .. note:: If the elements of B are not known to sufficient precision, this function will report that the vectors are linearly dependent (since they are to the specified precision). INPUT: - ``B`` - list of q-expansions - ``n`` - an integer >= 1 - ``k`` - an integer - ``eps`` - Dirichlet character - ``already_echelonized`` -- bool (default: False); if True, use that the basis is already in Echelon form, which saves a lot of time. EXAMPLES:: sage: sage.modular.modform.constructor.ModularForms_clear_cache() sage: ModularForms(1,12).q_expansion_basis() [ q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6), 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6) ] sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(), 3, 12) Traceback (most recent call last): ... ValueError: The given basis vectors must be linearly independent. sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(30), 3, 12) [ 252 0] [ 0 177148] TESTS: This shows that the problem with finite fields reported at trac #8281 is solved:: sage: bas_mod5 = [f.change_ring(GF(5)) for f in victor_miller_basis(12, 20)] sage: hecke_operator_on_basis(bas_mod5, 2, 12) [4 0] [0 1] This shows that empty input is handled sensibly (trac #12202):: sage: x = hecke_operator_on_basis([], 3, 12); x [] sage: x.parent() Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 1 and degree 1 sage: y = hecke_operator_on_basis([], 3, 12, eps=DirichletGroup(13).0^2); y [] sage: y.parent() Full MatrixSpace of 0 by 0 dense matrices over Cyclotomic Field of order 12 and degree 4 """ if not isinstance(B, (list, tuple)): raise TypeError, "B (=%s) must be a list or tuple" % B if len(B) == 0: if eps is None: R = CyclotomicField(1) else: R = eps.base_ring() return MatrixSpace(R, 0)(0) f = B[0] R = f.base_ring() if eps is None: eps = DirichletGroup(1, R).gen(0) all_powerseries = True for x in B: if not is_PowerSeries(x): all_powerseries = False if not all_powerseries: raise TypeError, "each element of B must be a power series" n = Integer(n) k = Integer(k) prec = (f.prec() - 1) // n A = R**prec V = A.span_of_basis([g.padded_list(prec) for g in B], already_echelonized=already_echelonized) return _hecke_operator_on_basis(B, V, n, k, eps)