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 _sz_s( k, m, l, n): r""" OUTPUT The function $s_{k,m}(l,n)$, i.e.~the trace of $T(l) \circ W_n$ on the "certain" space $\mathcal{M}_{2k-2}^{\text{cusp}}(m)$ of modular forms as defined in [S-Z]. INPUT l -- index of the Hecke operator, rel. prime to the level $m$ n -- index of the Atkin-Lehner involution (exact divisor of $m$) k -- integer ($2k-2$ is the weight) m -- level """ k = Integer(k) m = Integer(m) l = Integer(l) n = Integer(n) if k < 2: return 0 if 1 != m.gcd(l): raise ValueError, \ "gcd(%s,%s) != 1: not yet implemented" % (m,l) ellT = 0 for np in n.divisors(): ellT -= sum( l**(k-2) \ * _gegenbauer_pol( k-2, s*s*np/l) \ * hurwitz_kronecker_class_no_x( m/n, s*s*np*np - 4*l*np) \ for s in range( -(Integer(4*l*np).isqrt()//np), \ 1+(Integer(4*l*np).isqrt()//np)) \ if (n//np).gcd(s*s).is_squarefree())/2 parT = -sum( min( lp, l//lp)**(2*k-3) \ * _ab(n)[0].gcd( lp+l//lp) \ * _ab(m/n)[0].gcd( lp-l//lp) \ for lp in l.divisors())/2 if 2 == k and (m//n).is_square(): corT = sigma(n,0)*sigma(l,1) else: corT = 0 return Integer( ellT + parT + corT)
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 _cWP(self, d, r): #\wp(z) & = \frac{1}{12} + \frac{p}{(1-p)^2} + \sum_{k,r \geq 1} k (p^k - 2 + p^{-k}) q^{kr} if d < 0: return 0 if d == 0: if r < 0: return 0 elif r == 0: return QQ(1/12) else: return r if d > 0: if r == 0: return -2*sigma(d,1) elif d % r == 0: return abs(r) else: return 0
def coeff(m): m = ZZ(m) if m < 0: return ZZ(0) elif m == 0: return ZZ(1) factor = -2*k / QQ(bernoulli(k)) / lamk sum1 = sigma(m, k-1) if M.divides(m): sum2 = (lamk-1) * sigma(ZZ(m/M), k-1) else: sum2 = ZZ(0) if (M == 1): sum3 = ZZ(0) else: if (m == 1): N = ZZ(1) else: N = ZZ(m / M**ZZ(m.valuation(M))) sum3 = -sigma(ZZ(N), k-1) * ZZ(m/N)**(k-1) / (lamk + 1) return factor * (sum1 + sum2 + sum3) * dval**m
def coeff(m): m = ZZ(m) if m < 0: return ZZ(0) elif m == 0: return ZZ(1) factor = -2 * k / QQ(bernoulli(k)) / lamk sum1 = sigma(m, k - 1) if M.divides(m): sum2 = (lamk - 1) * sigma(ZZ(m / M), k - 1) else: sum2 = ZZ(0) if (M == 1): sum3 = ZZ(0) else: if (m == 1): N = ZZ(1) else: N = ZZ(m / M**ZZ(m.valuation(M))) sum3 = -sigma(ZZ(N), k - 1) * ZZ(m / N)**(k - 1) / (lamk + 1) return factor * (sum1 + sum2 + sum3) * dval**m
def maass_form(self, f, g, k=None, is_integral=False): r""" Return the Siegel modular form `I(f,g)` (Notation as in [Sko]). INPUT: - `f` -- modular form of level `1` - `g` -- cusp form of level `1` and weight = ``weight of f + 2`` - ``is_integral`` -- ``True`` if the result is garanteed to have integer coefficients """ ## we introduce an abbreviations if is_integral: PS = self.integral_power_series_ring() else: PS = self.power_series_ring() fismodular = isinstance(f, ModularFormElement) gismodular = isinstance(g, ModularFormElement) ## We only check the arguments if f and g are ModularFormElements. ## Otherwise we trust in the user if fismodular and gismodular: assert( f.weight() + 2 == g.weight() | (f==0) | (g==0)), \ "incorrect weights!" assert ( g.q_expansion(1) == 0), "second argument is not a cusp form" qexp_prec = self._get_maass_form_qexp_prec() if qexp_prec is None: # there are no forms below prec return dict() if fismodular: k = f.weight() if f == f.parent()(0): f = PS(0, qexp_prec) else: f = PS(f.qexp(qexp_prec), qexp_prec) elif f == 0: f = PS(0, qexp_prec) else: f = PS(f(qexp_prec), qexp_prec) if gismodular: k = g.weight() - 2 if g == g.parent()(0): g = PS(0, qexp_prec) else: g = PS(g.qexp(qexp_prec), qexp_prec) elif g == 0: g = PS(0, qexp_prec) else: g = PS(g(qexp_prec), qexp_prec) if k is None: raise ValueError, "if neither f nor g are not ModularFormElements " + \ "you must pass k" fderiv = f.derivative().shift(1) f *= Integer(k / 2) gfderiv = g - fderiv ## Form A and B - the Jacobi forms used in [Sko]'s I map. ## This is not necessary if we multiply Ifg0 and Ifg1 by etapow # (A0,A1,B0,B1) = (a0*etapow, a1*etapow, b0*etapow, b1*etapow) ## Calculate the image of the pair of modular forms (f,g) under ## [Sko]'s isomorphism I : M_{k} \oplus S_{k+2} -> J_{k,1}. # Multiplication of big polynomials may take > 60 GB, so wie have # to do it in small parts; This is only implemented for integral # coefficients. """ Create the Jacobi form I(f,g) as in [Sko]. It suffices to construct for all Jacobi forms phi only the part sum_{r=0,1;n} c_phi(r^2-4n) q^n zeta^r. When, in this code part, we speak of Jacobi form we only mean this part. We need to compute Ifg = \sum_{r=0,1; n} c(r^2-4n) q^n zeta^r up to 4n-r^2 <= Dtop, i.e. n < precision """ ## Create the Jacobi forms A=a*etapow and B=b*etapow in stages. ## Recall a = sum_{s != r mod 2} s^2*(-1)^r*q^((s^2+r^2-1)/4)*zeta^r ## b = sum_{s != r mod 2} (-1)^r*q^((s^2+r^2-1)/4)*zeta^r ## r, s run over ZZ but with opposite parities. ## For r=0, we need s odd, (s^2-1)/4 < precision, with s=2t+1 hence t^2+t < precision. ## For r=1, we need s even, s^2/4 < precision, with s=2t hence t^2 < precision. ## we use a slightly overestimated ab_prec ab_prec = isqrt(qexp_prec + 1) a1dict = dict() a0dict = dict() b1dict = dict() b0dict = dict() for t in xrange(1, ab_prec + 1): tmp = t**2 a1dict[tmp] = -8 * tmp b1dict[tmp] = -2 tmp += t a0dict[tmp] = 8 * tmp + 2 b0dict[tmp] = 2 b1dict[0] = -1 a0dict[0] = 2 b0dict[0] = 2 a1 = PS(a1dict) b1 = PS(b1dict) a0 = PS(a0dict) b0 = PS(b0dict) ## Finally: I(f,g) is given by the formula below: ## We multiply by etapow explecitely and save two multiplications # Ifg0 = k/2*f*A0 - fderiv*B0 + g*B0 + O(q^precision) # Ifg1 = k/2*f*A1 - fderiv*B1 + g*B1 + O(q^precision) Ifg0 = (self._eta_power() * (f * a0 + gfderiv * b0)).list() Ifg1 = (self._eta_power() * (f * a1 + gfderiv * b1)).list() if len(Ifg0) < qexp_prec: Ifg0 += [0] * (qexp_prec - len(Ifg0)) if len(Ifg1) < qexp_prec: Ifg1 += [0] * (qexp_prec - len(Ifg1)) ## For applying the Maass' lifting to genus 2 modular forms. ## we put the coefficients of Ifg into a dictionary Chi ## so that we can access the coefficient corresponding to ## discriminant D by going Chi[D]. Cphi = dict([(0, 0)]) for i in xrange(qexp_prec): Cphi[-4 * i] = Ifg0[i] Cphi[1 - 4 * i] = Ifg1[i] del Ifg0[:], Ifg1[:] """ Create the Maas lift F := VI(f,g) as in [Sko]. """ ## The constant term is given by -Cphi[0]*B_{2k}/(4*k) ## (note in [Sko] this coeff has typos). ## For nonconstant terms, ## The Siegel coefficient of q^n * zeta^r * qdash^m is given ## by the formula \sum_{ a | gcd(n,r,m) } Cphi[D/a^2] where ## D = r^2-4*n*m is the discriminant. ## Hence in either case the coefficient ## is fully deterimined by the pair (D,gcd(n,r,m)). ## Put (D,t) -> \sum_{ a | t } Cphi[D/a^2] ## in a dictionary (hash table) maassc. maass_coeffs = dict() divisor_dict = self._divisor_dict() ## First calculate maass coefficients corresponding to strictly positive definite matrices: for disc in self._negative_fundamental_discriminants(): for s in xrange( 1, isqrt((-self.__precision.discriminant()) // disc) + 1): ## add (disc*s^2,t) as a hash key, for each t that divides s for t in divisor_dict[s]: maass_coeffs[(disc * s**2,t)] = \ sum( a**(k-1) * Cphi[disc * s**2 / a**2] for a in divisor_dict[t] ) ## Compute the coefficients of the Siegel form $F$: siegel_coeffs = dict() for (n, r, m), g in self.__precision.iter_positive_forms_with_content(): siegel_coeffs[(n, r, m)] = maass_coeffs[(r**2 - 4 * m * n, g)] ## Secondly, deal with the singular part. ## Include the coeff corresponding to (0,0,0): ## maass_coeffs = {(0,0): -bernoulli(k)/(2*k)*Cphi[0]} siegel_coeffs[(0, 0, 0)] = -bernoulli(k) / (2 * k) * Cphi[0] if is_integral: siegel_coeffs[(0, 0, 0)] = Integer(siegel_coeffs[(0, 0, 0)]) ## Calculate the other discriminant-zero maass coefficients. ## Since sigma is quite cheap it is faster to estimate the bound and ## save the time for repeated calculation for i in xrange(1, self.__precision._indefinite_content_bound()): ## maass_coeffs[(0,i)] = sigma(i, k-1) * Cphi[0] siegel_coeffs[(0, 0, i)] = sigma(i, k - 1) * Cphi[0] return siegel_coeffs
def additive_lift(self, forms, weight, with_character=False, is_integral=False): """ Borcherds additive lift to hermitian modular forms of degree `2`. This coinsides with Gritsenko's arithmetic lift after using the theta decomposition. INPUT: - ``forms`` -- A list of functions accepting an integer and returning a q-expansion. - ``weight`` -- A positive integer; The weight of the lift. - ``with_character`` -- A boolean (default: ``False``); Whether the lift has nontrivial character. - ``is_integral`` -- A boolean (default: ``False``); If ``True`` use rings of integral q-expansions over `\Z`. ALGORITHME: We use the explicite formulas in [D]. TESTS:: sage: from hermitianmodularforms.hermitianmodularformd2_fegenerators import HermitianModularFormD2AdditiveLift sage: HermitianModularFormD2AdditiveLift(4, [1,0,0], -3, 4).coefficients() {(2, 3, 2, 2): 720, (1, 1, 1, 1): 27, (1, 0, 0, 2): 270, (3, 3, 3, 3): 2943, (2, 1, 1, 3): 2592, (0, 0, 0, 2): 9, (2, 2, 2, 2): 675, (2, 3, 2, 3): 2160, (1, 1, 1, 2): 216, (3, 0, 0, 3): 8496, (2, 0, 0, 3): 2214, (1, 0, 0, 3): 720, (2, 1, 1, 2): 1080, (0, 0, 0, 1): 1, (3, 3, 2, 3): 4590, (3, 1, 1, 3): 4590, (1, 1, 1, 3): 459, (2, 0, 0, 2): 1512, (1, 0, 0, 1): 72, (0, 0, 0, 0): 1/240, (3, 4, 3, 3): 2808, (0, 0, 0, 3): 28, (3, 2, 2, 3): 4752, (2, 2, 2, 3): 1350} sage: HermitianModularFormD2AdditiveLift(4, [0,1,0], -3, 6).coefficients() {(2, 3, 2, 2): -19680, (1, 1, 1, 1): -45, (1, 0, 0, 2): -3690, (3, 3, 3, 3): -306225, (2, 1, 1, 3): -250560, (0, 0, 0, 2): 33, (2, 2, 2, 2): -13005, (2, 3, 2, 3): -153504, (1, 1, 1, 2): -1872, (3, 0, 0, 3): -1652640, (2, 0, 0, 3): -295290, (1, 0, 0, 3): -19680, (2, 1, 1, 2): -43920, (0, 0, 0, 1): 1, (3, 3, 2, 3): -948330, (3, 1, 1, 3): -1285290, (1, 1, 1, 3): -11565, (2, 0, 0, 2): -65520, (1, 0, 0, 1): -240, (0, 0, 0, 0): -1/504, (3, 4, 3, 3): -451152, (0, 0, 0, 3): 244, (3, 2, 2, 3): -839520, (2, 2, 2, 3): -108090} """ if with_character and self.__D % 4 != 0: raise ValueError( "Characters are only possible for even discriminants.") ## This will be needed if characters are implemented if with_character: if (Integer(self.__D / 4) % 4) in [-2, 2]: alpha = (-self.__D / 4, 1 / 2) else: alpha = (-self.__D / 8, 1 / 2) #minv = 1/2 if with_character else 1 R = self.power_series_ring() q = R.gen(0) (vv_expfactor, vv_basis) = self._additive_lift_vector_valued_basis() vvform = dict( (self._reduce_vector_valued_index(k), R(0)) for (k, _) in self. _semireduced_vector_valued_indices_with_discriminant_offset(1)) for (f, b) in zip(forms, vv_basis): ## We have to apply the scaling of exponents to the form f = R( f(self._qexp_precision()) ).add_bigoh(self._qexp_precision()) \ .subs({q : q**vv_expfactor}) if not f.is_zero(): for (k, e) in b.iteritems(): vvform[k] = vvform[k] + e * f ## the T = matrix(2,[*, t / 2, \bar t / 2, *] th fourier coefficients of the lift ## only depends on (- 4 * D * det(T), eps = gcd(T), \theta \cong t / eps) ## if m != 1 we consider 2*T maass_coeffs = dict() ## TODO: use divisor dictionaries if not with_character: ## The factor for the exponent of the basis of vector valued forms ## and the factor D in the formula for the discriminant are combined ## here vv_expfactor = vv_expfactor // (-self.__D) for eps in self._iterator_content(): for ( theta, offset ) in self._semireduced_vector_valued_indices_with_discriminant_offset( eps): for disc in self._iterator_discriminant(eps, offset): maass_coeffs[(disc, eps, theta)] = \ sum( a**(weight-1) * vvform[self._reduce_vector_valued_index((theta[0]//a, theta[1]//a))][vv_expfactor * disc // a**2] for a in divisors(eps)) else: ## The factor for the exponent of the basis of vector valued forms ## and the factor D in the formula for the discriminant are combined ## here vv_expfactor = (2 * vv_expfactor) // (-self.__D) if self.__D // 4 % 2 == 0: for eps in self._iterator_content(): for ( theta, offset ) in self._semireduced_vector_valued_indices_with_discriminant_offset( eps): for disc in self._iter_discriminant(eps, offset): maass_coeffs[(disc, eps, theta)] = \ sum( a**(weight-1) * (1 if (theta[0] + theta[1] - 1) % 4 == 0 else -1) * vvform[self._reduce_vector_valued_index((theta[0]//a, theta[1]//a))][vv_expfactor * disc // a**2] for a in divisors(eps)) else: for eps in self._iterator_content(): for ( theta, offset ) in self._semireduced_vector_valued_indices_with_discriminant_offset( eps): for disc in self._iter_discriminant(eps, offset): maass_coeffs[(disc, eps, theta)] = \ sum( a**(weight-1) * (1 if (theta[1] - 1) % 4 == 0 else -1) * vvform[self._reduce_vector_valued_index((theta[0]//a, theta[1]//a))][vv_expfactor * disc // a**2] for a in divisors(eps) ) lift_coeffs = dict() ## TODO: Check whether this is correct. Add the character as an argument. for ((a, b1, b2, c), eps, disc) in self.precision( ).iter_positive_forms_for_character_with_content_and_discriminant( for_character=with_character): (theta1, theta2) = self._reduce_vector_valued_index( (b1 / eps, b2 / eps)) theta = (eps * theta1, eps * theta2) try: lift_coeffs[(a, b1, b2, c)] = maass_coeffs[(disc, eps, theta)] except: raise RuntimeError( str((a, b1, b2, c)) + " ; " + str((disc, eps, theta))) # Eisenstein component for (_, _, _, c) in self.precision().iter_semidefinite_forms_for_character( for_character=with_character): if c != 0: lift_coeffs[(0, 0, 0, c)] = vvform[(0, 0)][0] * sigma(c, weight - 1) lift_coeffs[( 0, 0, 0, 0)] = -vvform[(0, 0)][0] * bernoulli(weight) / Integer(2 * weight) if is_integral: lift_coeffs[(0, 0, 0, 0)] = ZZ(lift_coeffs[(0, 0, 0, 0)]) return lift_coeffs
def maass_form( self, f, g, k = None, is_integral = False) : r""" Return the Siegel modular form `I(f,g)` (Notation as in [Sko]). INPUT: - `f` -- modular form of level `1` - `g` -- cusp form of level `1` and weight = ``weight of f + 2`` - ``is_integral`` -- ``True`` if the result is garanteed to have integer coefficients """ ## we introduce an abbreviations if is_integral : PS = self.integral_power_series_ring() else : PS = self.power_series_ring() fismodular = isinstance(f, ModularFormElement) gismodular = isinstance(g, ModularFormElement) ## We only check the arguments if f and g are ModularFormElements. ## Otherwise we trust in the user if fismodular and gismodular : assert( f.weight() + 2 == g.weight() | (f==0) | (g==0)), \ "incorrect weights!" assert( g.q_expansion(1) == 0), "second argument is not a cusp form" qexp_prec = self._get_maass_form_qexp_prec() if qexp_prec is None : # there are no forms below prec return dict() if fismodular : k = f.weight() if f == f.parent()(0) : f = PS(0, qexp_prec) else : f = PS(f.qexp(qexp_prec), qexp_prec) elif f == 0 : f = PS(0, qexp_prec) else : f = PS(f(qexp_prec), qexp_prec) if gismodular : k = g.weight() - 2 if g == g.parent()(0) : g = PS(0, qexp_prec) else : g = PS(g.qexp(qexp_prec), qexp_prec) elif g == 0 : g = PS(0, qexp_prec) else : g = PS(g(qexp_prec), qexp_prec) if k is None : raise ValueError, "if neither f nor g are not ModularFormElements " + \ "you must pass k" fderiv = f.derivative().shift(1) f *= Integer(k/2) gfderiv = g - fderiv ## Form A and B - the Jacobi forms used in [Sko]'s I map. ## This is not necessary if we multiply Ifg0 and Ifg1 by etapow # (A0,A1,B0,B1) = (a0*etapow, a1*etapow, b0*etapow, b1*etapow) ## Calculate the image of the pair of modular forms (f,g) under ## [Sko]'s isomorphism I : M_{k} \oplus S_{k+2} -> J_{k,1}. # Multiplication of big polynomials may take > 60 GB, so wie have # to do it in small parts; This is only implemented for integral # coefficients. """ Create the Jacobi form I(f,g) as in [Sko]. It suffices to construct for all Jacobi forms phi only the part sum_{r=0,1;n} c_phi(r^2-4n) q^n zeta^r. When, in this code part, we speak of Jacobi form we only mean this part. We need to compute Ifg = \sum_{r=0,1; n} c(r^2-4n) q^n zeta^r up to 4n-r^2 <= Dtop, i.e. n < precision """ ## Create the Jacobi forms A=a*etapow and B=b*etapow in stages. ## Recall a = sum_{s != r mod 2} s^2*(-1)^r*q^((s^2+r^2-1)/4)*zeta^r ## b = sum_{s != r mod 2} (-1)^r*q^((s^2+r^2-1)/4)*zeta^r ## r, s run over ZZ but with opposite parities. ## For r=0, we need s odd, (s^2-1)/4 < precision, with s=2t+1 hence t^2+t < precision. ## For r=1, we need s even, s^2/4 < precision, with s=2t hence t^2 < precision. ## we use a slightly overestimated ab_prec ab_prec = isqrt(qexp_prec + 1) a1dict = dict(); a0dict = dict() b1dict = dict(); b0dict = dict() for t in xrange(1, ab_prec + 1) : tmp = t**2 a1dict[tmp] = -8*tmp b1dict[tmp] = -2 tmp += t a0dict[tmp] = 8*tmp + 2 b0dict[tmp] = 2 b1dict[0] = -1 a0dict[0] = 2; b0dict[0] = 2 a1 = PS(a1dict); b1 = PS(b1dict) a0 = PS(a0dict); b0 = PS(b0dict) ## Finally: I(f,g) is given by the formula below: ## We multiply by etapow explecitely and save two multiplications # Ifg0 = k/2*f*A0 - fderiv*B0 + g*B0 + O(q^precision) # Ifg1 = k/2*f*A1 - fderiv*B1 + g*B1 + O(q^precision) Ifg0 = (self._eta_power() * (f*a0 + gfderiv*b0)).list() Ifg1 = (self._eta_power() * (f*a1 + gfderiv*b1)).list() if len(Ifg0) < qexp_prec : Ifg0 += [0]*(qexp_prec - len(Ifg0)) if len(Ifg1) < qexp_prec : Ifg1 += [0]*(qexp_prec - len(Ifg1)) ## For applying the Maass' lifting to genus 2 modular forms. ## we put the coefficients of Ifg into a dictionary Chi ## so that we can access the coefficient corresponding to ## discriminant D by going Chi[D]. Cphi = dict([(0,0)]) for i in xrange(qexp_prec) : Cphi[-4*i] = Ifg0[i] Cphi[1-4*i] = Ifg1[i] del Ifg0[:], Ifg1[:] """ Create the Maas lift F := VI(f,g) as in [Sko]. """ ## The constant term is given by -Cphi[0]*B_{2k}/(4*k) ## (note in [Sko] this coeff has typos). ## For nonconstant terms, ## The Siegel coefficient of q^n * zeta^r * qdash^m is given ## by the formula \sum_{ a | gcd(n,r,m) } Cphi[D/a^2] where ## D = r^2-4*n*m is the discriminant. ## Hence in either case the coefficient ## is fully deterimined by the pair (D,gcd(n,r,m)). ## Put (D,t) -> \sum_{ a | t } Cphi[D/a^2] ## in a dictionary (hash table) maassc. maass_coeffs = dict() divisor_dict = self._divisor_dict() ## First calculate maass coefficients corresponding to strictly positive definite matrices: for disc in self._negative_fundamental_discriminants() : for s in xrange(1, isqrt((-self.__precision.discriminant()) // disc) + 1) : ## add (disc*s^2,t) as a hash key, for each t that divides s for t in divisor_dict[s] : maass_coeffs[(disc * s**2,t)] = \ sum( a**(k-1) * Cphi[disc * s**2 / a**2] for a in divisor_dict[t] ) ## Compute the coefficients of the Siegel form $F$: siegel_coeffs = dict() for (n,r,m), g in self.__precision.iter_positive_forms_with_content() : siegel_coeffs[(n,r,m)] = maass_coeffs[(r**2 - 4*m*n, g)] ## Secondly, deal with the singular part. ## Include the coeff corresponding to (0,0,0): ## maass_coeffs = {(0,0): -bernoulli(k)/(2*k)*Cphi[0]} siegel_coeffs[(0,0,0)] = -bernoulli(k)/(2*k)*Cphi[0] if is_integral : siegel_coeffs[(0,0,0)] = Integer(siegel_coeffs[(0,0,0)]) ## Calculate the other discriminant-zero maass coefficients. ## Since sigma is quite cheap it is faster to estimate the bound and ## save the time for repeated calculation for i in xrange(1, self.__precision._indefinite_content_bound()) : ## maass_coeffs[(0,i)] = sigma(i, k-1) * Cphi[0] siegel_coeffs[(0,0,i)] = sigma(i, k-1) * Cphi[0] return siegel_coeffs
def additive_lift(self, forms, weight, with_character = False, is_integral = False) : """ Borcherds additive lift to hermitian modular forms of degree `2`. This coinsides with Gritsenko's arithmetic lift after using the theta decomposition. INPUT: - ``forms`` -- A list of functions accepting an integer and returning a q-expansion. - ``weight`` -- A positive integer; The weight of the lift. - ``with_character`` -- A boolean (default: ``False``); Whether the lift has nontrivial character. - ``is_integral`` -- A boolean (default: ``False``); If ``True`` use rings of integral q-expansions over `\Z`. ALGORITHME: We use the explicite formulas in [D]. TESTS:: sage: from hermitianmodularforms.hermitianmodularformd2_fegenerators import HermitianModularFormD2AdditiveLift sage: HermitianModularFormD2AdditiveLift(4, [1,0,0], -3, 4).coefficients() {(2, 3, 2, 2): 720, (1, 1, 1, 1): 27, (1, 0, 0, 2): 270, (3, 3, 3, 3): 2943, (2, 1, 1, 3): 2592, (0, 0, 0, 2): 9, (2, 2, 2, 2): 675, (2, 3, 2, 3): 2160, (1, 1, 1, 2): 216, (3, 0, 0, 3): 8496, (2, 0, 0, 3): 2214, (1, 0, 0, 3): 720, (2, 1, 1, 2): 1080, (0, 0, 0, 1): 1, (3, 3, 2, 3): 4590, (3, 1, 1, 3): 4590, (1, 1, 1, 3): 459, (2, 0, 0, 2): 1512, (1, 0, 0, 1): 72, (0, 0, 0, 0): 1/240, (3, 4, 3, 3): 2808, (0, 0, 0, 3): 28, (3, 2, 2, 3): 4752, (2, 2, 2, 3): 1350} sage: HermitianModularFormD2AdditiveLift(4, [0,1,0], -3, 6).coefficients() {(2, 3, 2, 2): -19680, (1, 1, 1, 1): -45, (1, 0, 0, 2): -3690, (3, 3, 3, 3): -306225, (2, 1, 1, 3): -250560, (0, 0, 0, 2): 33, (2, 2, 2, 2): -13005, (2, 3, 2, 3): -153504, (1, 1, 1, 2): -1872, (3, 0, 0, 3): -1652640, (2, 0, 0, 3): -295290, (1, 0, 0, 3): -19680, (2, 1, 1, 2): -43920, (0, 0, 0, 1): 1, (3, 3, 2, 3): -948330, (3, 1, 1, 3): -1285290, (1, 1, 1, 3): -11565, (2, 0, 0, 2): -65520, (1, 0, 0, 1): -240, (0, 0, 0, 0): -1/504, (3, 4, 3, 3): -451152, (0, 0, 0, 3): 244, (3, 2, 2, 3): -839520, (2, 2, 2, 3): -108090} """ if with_character and self.__D % 4 != 0 : raise ValueError( "Characters are only possible for even discriminants." ) ## This will be needed if characters are implemented if with_character : if (Integer(self.__D / 4) % 4) in [-2,2] : alpha = (-self.__D / 4, 1/2) else : alpha = (-self.__D / 8, 1/2) #minv = 1/2 if with_character else 1 R = self.power_series_ring() q = R.gen(0) (vv_expfactor, vv_basis) = self._additive_lift_vector_valued_basis() vvform = dict((self._reduce_vector_valued_index(k), R(0)) for (k,_) in self._semireduced_vector_valued_indices_with_discriminant_offset(1)) for (f,b) in zip(forms, vv_basis) : ## We have to apply the scaling of exponents to the form f = R( f(self._qexp_precision()) ).add_bigoh(self._qexp_precision()) \ .subs({q : q**vv_expfactor}) if not f.is_zero() : for (k,e) in b.iteritems() : vvform[k] = vvform[k] + e * f ## the T = matrix(2,[*, t / 2, \bar t / 2, *] th fourier coefficients of the lift ## only depends on (- 4 * D * det(T), eps = gcd(T), \theta \cong t / eps) ## if m != 1 we consider 2*T maass_coeffs = dict() ## TODO: use divisor dictionaries if not with_character : ## The factor for the exponent of the basis of vector valued forms ## and the factor D in the formula for the discriminant are combined ## here vv_expfactor = vv_expfactor // (- self.__D) for eps in self._iterator_content() : for (theta, offset) in self._semireduced_vector_valued_indices_with_discriminant_offset(eps) : for disc in self._iterator_discriminant(eps, offset) : maass_coeffs[(disc, eps, theta)] = \ sum( a**(weight-1) * vvform[self._reduce_vector_valued_index((theta[0]//a, theta[1]//a))][vv_expfactor * disc // a**2] for a in divisors(eps)) else : ## The factor for the exponent of the basis of vector valued forms ## and the factor D in the formula for the discriminant are combined ## here vv_expfactor = (2 * vv_expfactor) // (- self.__D) if self.__D // 4 % 2 == 0 : for eps in self._iterator_content() : for (theta, offset) in self._semireduced_vector_valued_indices_with_discriminant_offset(eps) : for disc in self._iter_discriminant(eps, offset) : maass_coeffs[(disc, eps, theta)] = \ sum( a**(weight-1) * (1 if (theta[0] + theta[1] - 1) % 4 == 0 else -1) * vvform[self._reduce_vector_valued_index((theta[0]//a, theta[1]//a))][vv_expfactor * disc // a**2] for a in divisors(eps)) else : for eps in self._iterator_content() : for (theta, offset) in self._semireduced_vector_valued_indices_with_discriminant_offset(eps) : for disc in self._iter_discriminant(eps, offset) : maass_coeffs[(disc, eps, theta)] = \ sum( a**(weight-1) * (1 if (theta[1] - 1) % 4 == 0 else -1) * vvform[self._reduce_vector_valued_index((theta[0]//a, theta[1]//a))][vv_expfactor * disc // a**2] for a in divisors(eps) ) lift_coeffs = dict() ## TODO: Check whether this is correct. Add the character as an argument. for ((a,b1,b2,c), eps, disc) in self.precision().iter_positive_forms_for_character_with_content_and_discriminant(for_character = with_character) : (theta1, theta2) = self._reduce_vector_valued_index((b1/eps, b2/eps)) theta = (eps * theta1, eps * theta2) try: lift_coeffs[(a,b1,b2,c)] = maass_coeffs[(disc, eps, theta)] except : raise RuntimeError(str((a,b1,b2,c)) + " ; " + str((disc, eps, theta))) # Eisenstein component for (_,_,_,c) in self.precision().iter_semidefinite_forms_for_character(for_character = with_character) : if c != 0 : lift_coeffs[(0,0,0,c)] = vvform[(0,0)][0] * sigma(c, weight - 1) lift_coeffs[(0,0,0,0)] = - vvform[(0,0)][0] * bernoulli(weight) / Integer(2 * weight) if is_integral : lift_coeffs[(0,0,0,0)] = ZZ(lift_coeffs[(0,0,0,0)]) return lift_coeffs