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
Example #3
0
    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
Example #4
0
    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()
Example #7
0
    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
Example #10
0
    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
Example #12
0
 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