def symmetrise_siegel_modular_form(f, level, weight) : """ ALGORITHM: We use the Hecke operators \delta_p and [1,level,1,1/level], where the last one can be chosen, since we assume that f is invariant with respect to the full Siegel modular group. """ if not Integer(level).is_prime() : raise NotImplementedError( "Symmetrisation is only implemented for prime levels" ) fr = ParamodularFormD2FourierExpansionRing(f.parent().coefficient_domain(), level) precision = ParamodularFormD2Filter_discriminant(f.precision().discriminant() // level**2, level) coeffs = dict() for (k,l) in precision : kp = apply_GL_to_form(precision._p1list()[l], k) coeffs[(k,l)] = f[kp] g1 = fr( {fr.characters().one_element() : coeffs} ) g1._set_precision(precision) g1._cleanup_coefficients() coeffs = dict() for (k,l) in precision : kp = apply_GL_to_form(precision._p1list()[l], k) if kp[1] % level == 0 and kp[2] % level**2 == 0 : coeffs[(k,l)] = f[(kp[0], kp[1] // level, kp[2] // level**2)] g2 = fr( {fr.characters().one_element() : coeffs} ) g2._set_precision(precision) g2._cleanup_coefficients() return g1 + level**(weight-1) * g2
def symmetrise_siegel_modular_form(f, level, weight) : """ ALGORITHM: We use the Hecke operators \delta_p and [1,level,1,1/level], where the last one can be chosen, since we assume that f is invariant with respect to the full Siegel modular group. """ if not Integer(level).is_prime() : raise NotImplementedError( "Symmetrisation is only implemented for prime levels" ) fr = ParamodularFormD2FourierExpansionRing(f.parent().coefficient_domain(), level) precision = ParamodularFormD2Filter_discriminant(f.precision().discriminant() // level**2, level) coeffs = dict() for (k,l) in precision : kp = apply_GL_to_form(precision._p1list()[l], k) coeffs[(k,l)] = f[kp] g1 = fr( {fr.characters().one_element() : coeffs} ) g1._set_precision(precision) g1._cleanup_coefficients() coeffs = dict() for (k,l) in precision : kp = apply_GL_to_form(precision._p1list()[l], k) if kp[1] % level == 0 and kp[2] % level**2 == 0 : coeffs[(k,l)] = f[(kp[0], kp[1] // level, kp[2] // level**2)] g2 = fr( {fr.characters().one_element() : coeffs} ) g2._set_precision(precision) g2._cleanup_coefficients() return g1 + level**(weight-1) * g2
def schmidt_t5_eigenvalue_numerical(self, t): (tau1, z, tau2) = t from sage.libs.mpmath import mp from sage.libs.mpmath.mp import exp, pi from sage.libs.mpmath.mp import j as i if not Integer(self.__level()).is_prime(): raise ValueError("T_5 is only unique if the level is a prime") precision = ParamodularFormD2Filter_trace(self.precision()) s = Sequence([tau1, z, tau2]) if not is_ComplexField(s): mp_precision = 30 else: mp_precision = ceil(3.33 * s.universe().precision()) mp.dps = mp_precision p1list = P1List(self.level()) ## Prepare the operation for d_1(N) ## We have to invert the lifts since we will later use apply_GL_to_form d1_matrices = [p1list.lift_to_sl2z(i) for i in range(len(p1list))] d1_matrices = [(a_b_c_d[3], -a_b_c_d[1], -a_b_c_d[2], a_b_c_d[0]) for a_b_c_d in d1_matrices] ## Prepare the evaluation points corresponding to d_02(N) d2_points = list() for i in range(len(p1list())): (a, b, c, d) = p1list.lift_to_sl2z(i) tau1p = (a * tau1 + b) / (c * tau1 + d) zp = z / (c * tau1 + d) tau2p = tau2 - c * z**2 / (c * tau1 + d) (e_tau1p, e_zp, e_tau2p) = (exp(2 * pi * i * tau1p), exp(2 * pi * i * zp), exp(2 * pi * i * tau2p)) d2_points.append((e_tau1p, e_zp, e_tau2p)) (e_tau1, e_z, e_tau2) = (exp(2 * pi * i * tau1), exp(2 * pi * i * z), exp(2 * pi * i * tau2)) self_value = s.universe().zero() trans_value = s.universe().zero() for k in precision: (a, b, c) = apply_GL_to_form(self._P1List()(k[1]), k[0]) self_value = self_value + self[k] * e_tau1**a * e_z**b * e_tau2**c for m in d1_matrices: (ap, bp, cp) = apply_GL_to_form(m, (a, b, c)) for (e_tau1p, e_zp, e_tau2p) in d2_points: trans_value = trans_value + self[(( ap, bp, cp), 0)] * e_tau1p**ap * e_zp**bp * e_tau2p**cp return trans_value / self_value
def hecke_coeff(self, expansion, ch, a_b_c_l, k, N): r""" Computes the coefficient indexed by $(a,b,c)$ of $T(\ell) (F)$ """ (a, b, c) = a_b_c_l[0] l = a_b_c_l[1] character_eval = expansion.parent()._character_eval_function() if N == 1: ## We have to consider that now (a,b,c) -> (c, b, a) raise NotImplementedError (a, b, c) = apply_GL_to_form(expansion.precision()._p1list()[l], (a, b, c)) ell = self.__l coeff = 0 for t1 in self.__l_divisors[ell]: for t2 in self.__l_divisors[t1]: for V in self.get_representatives(t1 / t2, N): (aprime, bprime, cprime) = self.change_variables(V, (a, b, c)) if aprime % t1 == 0 and bprime % t2 == 0 and cprime % ( N * t2) == 0: coeff = coeff + character_eval(V, ch) * t1**(k-2)*t2**(k-1) \ * expansion[( ch, (( (ell*aprime) //t1**2, (ell*bprime) //t1//t2, (ell*cprime) //t2**2 ), 1) )] return coeff
def decompositions(self, s) : ((a, b, c), l) = s # r t r^tr = t_1 + t_2 # \Rightleftarrow t = r t_1 r^tr + r t_2 r^tr for a1 in xrange(a + 1) : a2 = a - a1 for c1 in xrange(c + 1) : c2 = c - c1 B1 = isqrt(4*a1*c1) B2 = isqrt(4*a2*c2) for b1 in xrange(max(-B1, b - B2), min(B1 + 1, b + B2 + 1)) : h1 = apply_GL_to_form(self.__p1list[l], (a1, b1, c1)) h2 = apply_GL_to_form(self.__p1list[l], (a2, b - b1, c2)) if h1[2] % self.__level == 0 and h2[2] % self.__level == 0: yield ((h1, 1), (h2,1)) raise StopIteration
def __contains__(self, f) : r""" Check whether an index has discriminant less than ``self.__index`` and whether its bottom right entry is divisible by ``self.__level``. """ if self.__disc is infinity : return True (s, l) = f (a, _, c) = apply_GL_to_form(self.__p1list[l], s) if not c % self.__level == 0 : return False return a + c < self.index()
def gritsenko_lift(self, f, k, is_integral=False): """ INPUT: - `f` -- the Fourier expansion of a Jacobi form as a dictionary """ N = self.level() frN = 4 * N p1list = self.precision()._p1list() divisor_dict = self._divisor_dict() ##TODO: Precalculate disc_coeffs or at least use a recursive definition disc_coeffs = dict() coeffs = dict() f_index = lambda d, b: ((d + b**2) // frN, b) for ( ((a, b, c), l), eps, disc ) in self.__precision._iter_positive_forms_with_content_and_discriminant( ): (_, bp, _) = apply_GL_to_form(p1list[l], (a, b, c)) try: coeffs[((a, b, c), l)] = disc_coeffs[(disc, bp, eps)] except KeyError: disc_coeffs[(disc, bp, eps)] = \ sum(t**(k-1) * f[ f_index(disc//t**2, (bp // t) % (2 * N)) ] for t in divisor_dict[eps]) if disc_coeffs[(disc, bp, eps)] != 0: coeffs[((a, b, c), l)] = disc_coeffs[(disc, bp, eps)] for ((a, b, c), l) in self.__precision.iter_indefinite_forms(): if l == 0: coeffs[((a, b, c), l)] = ( sigma(c, k - 1) * f[(0, 0)] if c != 0 else (Integer(-bernoulli(k) / Integer(2 * k) * f[(0, 0)]) if is_integral else -bernoulli(k) / Integer(2 * k) * f[(0, 0)])) else: coeffs[((a, b, c), l)] = ( sigma(c // self.level(), k - 1) * f[(0, 0)] if c != 0 else (Integer(-bernoulli(k) / Integer(2 * k) * f[(0, 0)]) if is_integral else -bernoulli(k) / Integer(2 * k) * f[(0, 0)])) return coeffs
def gritsenko_lift(self, f, k, is_integral = False) : """ INPUT: - `f` -- the Fourier expansion of a Jacobi form as a dictionary """ N = self.level() frN = 4 * N p1list = self.precision()._p1list() divisor_dict = self._divisor_dict() ##TODO: Precalculate disc_coeffs or at least use a recursive definition disc_coeffs = dict() coeffs = dict() f_index = lambda d,b : ((d + b**2)//frN, b) for (((a,b,c),l), eps, disc) in self.__precision._iter_positive_forms_with_content_and_discriminant() : (_,bp,_) = apply_GL_to_form(p1list[l], (a,b,c)) try : coeffs[((a,b,c),l)] = disc_coeffs[(disc, bp, eps)] except KeyError : disc_coeffs[(disc, bp, eps)] = \ sum( t**(k-1) * f[ f_index(disc//t**2, (bp // t) % (2 * N)) ] for t in divisor_dict[eps] ) if disc_coeffs[(disc, bp, eps)] != 0 : coeffs[((a,b,c),l)] = disc_coeffs[(disc, bp, eps)] for ((a,b,c), l) in self.__precision.iter_indefinite_forms() : if l == 0 : coeffs[((a,b,c),l)] = ( sigma(c, k-1) * f[(0,0)] if c != 0 else ( Integer(-bernoulli(k) / Integer(2 * k) * f[(0,0)]) if is_integral else -bernoulli(k) / Integer(2 * k) * f[(0,0)] ) ) else : coeffs[((a,b,c),l)] = ( sigma(c//self.level(), k-1) * f[(0,0)] if c != 0 else ( Integer(-bernoulli(k) / Integer(2 * k) * f[(0,0)]) if is_integral else -bernoulli(k) / Integer(2 * k) * f[(0,0)] ) ) return coeffs
def __contains__(self, f) : """ Check whether an index has discriminant less than ``self.__index`` and whether its bottom right entry is divisible by ``self.__level``. """ if self.__disc is infinity : return True (s, l) = f (a, b, c) = apply_GL_to_form(self.__p1list[l], s) if not c % self.__level == 0 : return False disc = 4*a*c - b**2 if disc == 0 : return gcd([a,b,c]) < self._indefinite_content_bound() else : return disc < self.__disc
def atkin_lehner_eigenvalue_numerical(self, t): (tau1, z, tau2) = t from sage.libs.mpmath import mp from sage.libs.mpmath.mp import exp, pi from sage.libs.mpmath.mp import j as i if not Integer(self.__level()).is_prime(): raise ValueError( "The Atkin Lehner involution is only unique if the level is a prime" ) precision = ParamodularFormD2Filter_trace(self.precision()) s = Sequence([tau1, z, tau2]) if not is_ComplexField(s): mp_precision = 30 else: mp_precision = ceil(3.33 * s.universe().precision()) mp.dps = mp_precision (tau1, z, tau2) = tuple(s) (tau1p, zp, tau2p) = (self.level() * tau1, self.level() * z, self.level() * tau2) (e_tau1, e_z, e_tau2) = (exp(2 * pi * i * tau1), exp(2 * pi * i * z), exp(2 * pi * i * tau2)) (e_tau1p, e_zp, e_tau2p) = (exp(2 * pi * i * tau1p), exp(2 * pi * i * zp), exp(2 * pi * i * tau2p)) self_value = s.universe().zero() trans_value = s.universe().zero() for k in precision: (a, b, c) = apply_GL_to_form(self._P1List()(k[1]), k[0]) self_value = self_value + self[k] * (e_tau1**a * e_z**b * e_tau2**c) trans_value = trans_value + self[k] * (e_tau1p**a * e_zp**b * e_tau2p**c) return trans_value / self_value
class ParamodularFormD2FourierExpansionHeckeAction_class(SageObject): r""" Implements a Hecke operator acting on paramodular modular forms of degree 2. """ def __init__(self, n): self.__l = n self.__l_divisors = siegelmodularformg2_misc_cython.divisor_dict(n + 1) def eval(self, expansion, weight=None): if weight is None: try: weight = expansion.weight() except AttributeError: raise ValueError, "weight must be defined for the Hecke action" precision = expansion.precision() if precision.is_infinite(): precision = expansion._bounding_precision() else: precision = precision._hecke_operator(self.__l) characters = expansion.non_zero_components() expansion_level = precision.level() if gcd(expansion_level, self.__l) != 1: raise ValueError, "Level of expansion and of Hecke operator must be coprime." hecke_expansion = dict() for ch in characters: hecke_expansion[ch] = dict( (k, self.hecke_coeff(expansion, ch, k, weight, expansion_level)) for k in precision) result = expansion.parent()._element_constructor_(hecke_expansion) result._set_precision(expansion.precision()._hecke_operator(self.__l)) return result # TODO : reimplement in cython def hecke_coeff(self, expansion, ch, ((a, b, c), l), k, N): r""" Computes the coefficient indexed by $(a,b,c)$ of $T(\ell) (F)$ """ character_eval = expansion.parent()._character_eval_function() if N == 1: ## We have to consider that now (a,b,c) -> (c, b, a) raise NotImplementedError (a, b, c) = apply_GL_to_form(expansion.precision()._p1list()[l], (a, b, c)) ell = self.__l coeff = 0 for t1 in self.__l_divisors[ell]: for t2 in self.__l_divisors[t1]: for V in self.get_representatives(t1 / t2, N): (aprime, bprime, cprime) = self.change_variables(V, (a, b, c)) if aprime % t1 == 0 and bprime % t2 == 0 and cprime % ( N * t2) == 0: coeff = coeff + character_eval(V, ch) * t1**(k-2)*t2**(k-1) \ * expansion[( ch, (( (ell*aprime) //t1**2, (ell*bprime) //t1//t2, (ell*cprime) //t2**2 ), 1) )] return coeff
d1_matrices = [p1list.lift_to_sl2z(i) for i in xrange(len(p1list))] d1_matrices = map(lambda (a,b,c,d): (d,-b,-c,a), d1_matrices) ## Prepare the evaluation points corresponding to d_02(N) d2_points = list() for i in xrange(len(p1list())) : (a, b, c, d) = p1list.lift_to_sl2z(i) tau1p = (a * tau1 + b) / (c * tau1 + d) zp = z / (c * tau1 + d) tau2p = tau2 - c * z**2 / (c * tau1 + d) (e_tau1p, e_zp, e_tau2p) = (exp(2 * pi * i * tau1p), exp(2 * pi * i * zp), exp(2 * pi * i * tau2p)) d2_points.append((e_tau1p, e_zp, e_tau2p)) (e_tau1, e_z, e_tau2) = (exp(2 * pi * i * tau1), exp(2 * pi * i * z), exp(2 * pi * i * tau2)) self_value = s.universe().zero() trans_value = s.universe().zero() for k in precision : (a,b,c) = apply_GL_to_form(self._P1List()(k[1]), k[0]) self_value = self_value + self[k] * e_tau1**a * e_z**b * e_tau2**c for m in d1_matrices : (ap, bp, cp) = apply_GL_to_form(m, (a,b,c)) for (e_tau1p, e_zp, e_tau2p) in d2_points : trans_value = trans_value + self[((ap,bp,cp),0)] * e_tau1p**ap * e_zp**bp * e_tau2p**cp return trans_value / self_value