def _action2(self,A): [a,b,c,d]=A fak=1 if c<0: a=-a; b=-b; c=-c; d=-d; fak=-self._fak if c==0: if a>0: res = self._z**b else: res = self._fak*self._z**b else: arg = dedekind_sum(-d,c) arg = arg+QQ(a+d)/QQ(12*c)-QQ(1)/QQ(4) # print "arg=",arg arg=arg*QQ(2) den = arg.denominator()*self._k_den num = arg.numerator()*self._k_num K = CyclotomicField(2*den) z=K.gen() if z.multiplicative_order()>4: fak=K(fak) # z = CyclotomicField(2*arg.denominator()).gen() res = z**num #rg.numerator() if self._character: ch = self._character(d) res=res*ch res = res*fak if self._is_dual: return res**-1 return res
def _action2(self, A): [a, b, c, d] = A fak = 1 if c < 0: a = -a b = -b c = -c d = -d fak = -self._fak if c == 0: if a > 0: res = self._z**b else: res = self._fak * self._z**b else: arg = dedekind_sum(-d, c) arg = arg + QQ(a + d) / QQ(12 * c) - QQ(1) / QQ(4) # print "arg=",arg arg = arg * QQ(2) den = arg.denominator() * self._k_den num = arg.numerator() * self._k_num K = CyclotomicField(2 * den) z = K.gen() if z.multiplicative_order() > 4: fak = K(fak) # z = CyclotomicField(2*arg.denominator()).gen() res = z**num #rg.numerator() if self._character: ch = self._character(d) res = res * ch res = res * fak if self._is_dual: return res**-1 return res
def power_charpoly(f, k): r"""" INPUT: - ``f`` -- the characteristic polynomial of a linear transformation OUTPUT: the characteristic polynomial of the kth power of the linear transformation """ K = CyclotomicField(k) R = f.base_ring() RT = f.parent() f = f.change_ring(K) T = f.parent().gen() a = K.gen() g = 1 for i in range(k): g *= f(a**i * T) glist = g.list() newf = [None] * (1 + f.degree()) for i, ci in enumerate(glist): if i % k != 0: assert ci == 0, "i = %s, ci = %s" % (i, ci) else: newf[i / k] = R(ci) return RT(newf)
class TestMultiplier(MultiplierSystem): r""" Test of multiplier for f(q). As in e.g. the paper of Bringmann and Ono. """ def __init__(self,group,dchar=(0,0),dual=False,weight=QQ(1)/QQ(2),dimension=1,version=1,**kwargs): self._weight=QQ(weight) MultiplierSystem.__init__(self,group,dchar=dchar,dual=dual,dimension=dimension,**kwargs) self._k_den=self._weight.denominator() self._k_num=self._weight.numerator() self._K = CyclotomicField(12*self._k_den) self._z = self._K.gen()**self._k_num self._sqrti = CyclotomicField(8).gen() self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2*self._k_den).gen()**-self._k_num self._fak_arg=QQ(self._weight)/QQ(2) self._version = version self.is_consistent(weight) # test consistency def order(self): return 12*self._k_den def z(self): return self._z def __repr__(self): s="Test multiplier" if self._character<>None and not self._character.is_trivial(): s+="and character "+str(self._character) return s def _action(self,A): [a,b,c,d]=A fak=0 if c<0: a=-a; b=-b; c=-c; d=-d; fak=self._fak_arg if c==0: if a>0: res = self._z**-b else: res = self._fak*self._z**-b else: arg=-QQ(1)/QQ(8)+QQ(c+a*d+1)/QQ(4)-QQ(a+d)/QQ(24*c)-QQ(a)/QQ(4)+QQ(3*d*c)/QQ(8) # print "arg=",arg arg = arg-dedekind_sum(-d,c)/QQ(2)+fak #self._fak_arg den=arg.denominator() num=arg.numerator() # print "den=",den # print "num=",num res = self._K(CyclotomicField(den).gen())**num #res = res*fak if self._is_dual: return res**-1 return res
class TestMultiplier(MultiplierSystem): r""" Test of multiplier for f(q). As in e.g. the paper of Bringmann and Ono. """ def __init__(self,group,dchar=(0,0),dual=False,weight=QQ(1)/QQ(2),dimension=1,version=1,**kwargs): self._weight=QQ(weight) MultiplierSystem.__init__(self,group,dchar=dchar,dual=dual,dimension=dimension,**kwargs) self._k_den=self._weight.denominator() self._k_num=self._weight.numerator() self._K = CyclotomicField(12*self._k_den) self._z = self._K.gen()**self._k_num self._sqrti = CyclotomicField(8).gen() self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2*self._k_den).gen()**-self._k_num self._fak_arg=QQ(self._weight)/QQ(2) self._version = version self.is_consistent(weight) # test consistency def order(self): return 12*self._k_den def z(self): return self._z def __repr__(self): s="Test multiplier" if self._character<>None and not self._character.is_trivial(): s+="and character "+str(self._character) return s def _action(self,A): [a,b,c,d]=A fak=0 if c<0: a=-a; b=-b; c=-c; d=-d; fak=self._fak_arg if c==0: if a>0: res = self._z**-b else: res = self._fak*self._z**-b else: arg=-QQ(1)/QQ(8)+QQ(c+a*d+1)/QQ(4)-QQ(a+d)/QQ(24*c)-QQ(a)/QQ(4)+QQ(3*d*c)/QQ(8) # print "arg=",arg arg = arg-dedekind_sum(-d,c)/QQ(2)+fak #self._fak_arg den=arg.denominator() num=arg.numerator() # print "den=",den # print "num=",num res = self._K(CyclotomicField(den).gen())**num #res = res*fak if self._is_dual: return res**-1 return res
def induced_rep_from_twisted_cocycle(p, rho, chi, cocycle): """ The main metabelian representation from Section 7 of [HKL] for the group of a knot complement, where p is the degree of the branched cover, rho is an irreducible cyclic representation acting on the F_q vector space V, chi is a homomorpism V -> F_q, and cocycle describes the semidirect product extension. We differ from [HKL] in that all actions are on the left, meaning that this representation is defined in terms of the convention for the semidirect product discussed in:: MatrixRepresentation.semidirect_rep_from_twisted_cocycle Here is an example:: sage: G = Manifold('K12n132').fundamental_group() sage: A = matrix(GF(5), [[0, 4], [1, 4]]) sage: rho = cyclic_rep(G, A) sage: cocycle = (0, 0, 0, 1, 1, 2) sage: chi = lambda v: v[0] + 4*v[1] sage: rho_ind = induced_rep_from_twisted_cocycle(3, rho, chi, cocycle) sage: rho_ind('c').list() [0, 0, (-z^3 - z^2 - z - 1), z^2*t^-1, 0, 0, 0, (-z^3 - z^2 - z - 1)*t^-1, 0] """ q = rho.base_ring.order() n = rho.dim K = CyclotomicField(q, 'z') z = K.gen() A = rho.A R = LaurentPolynomialRing(K, 't') t = R.gen() MatSp = MatrixSpace(R, p) gens = rho.generators images = dict() for s, g in enumerate(gens): v = vector(cocycle[s * n:(s + 1) * n]) e = rho.epsilon(g)[0] U = MatSp(0) for j in range(0, p): k, l = (e + j).quo_rem(p) U[l, j] = t**k * z**chi(A**(-l) * v) images[g] = U e, v = -e, -A**(-e) * v V = MatSp(0) for j in range(0, p): k, l = (e + j).quo_rem(p) V[l, j] = t**k * z**chi(A**(-l) * v) images[g.swapcase()] = V alpha = MatrixRepresentation(gens, rho.relators, MatSp, images) alpha.epsilon = rho.epsilon return alpha
class EtaQuotientMultiplier(MultiplierSystem): r""" Eta multiplier given by eta(Az)^{r}/eta(Bz)^s The weight should be r/2-s/2 mod 2. The group is Gamma0(lcm(A,B)) """ def __init__(self,A,B,r,s,k=None,number=0,ch=None,dual=False,version=1,**kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) EXAMPLE: """ self._level=lcm(A,B) G = Gamma0(self._level) if k==None: k = (QQ(r)-QQ(s))/QQ(2) self._weight=QQ(k) if floor(self._weight-QQ(1)/QQ(2))==ceil(self._weight-QQ(1)/QQ(2)): self._half_integral_weight=1 else: self._half_integral_weight=0 MultiplierSystem.__init__(self,G,dimension=1,character=ch,dual=dual) number = number % 12 if not is_even(number): raise ValueError,"Need to have v_eta^(2(k+r)) with r even!" self._arg_num = A self._arg_den = B self._exp_num = r self._exp_den = s self._pow=QQ((self._weight+number)) ## k+r self._k_den=self._pow.denominator() self._k_num=self._pow.numerator() self._K = CyclotomicField(12*self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2*self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency def __repr__(self): s="Quotient of Eta multipliers : " s+="eta({0})^{1}/eta({2})^{3}".format(self._arg_num,self._exp_num,self._arg_den,self._exp_den) if self._character<>None and not self._character.is_trivial(): s+=" and character "+str(self._character) s+=" with weight="+str(self._weight) return s def level(self): return self._level def order(self): return 12*self._k_den def z(self): return self._z def q_shift(self): r""" Gives the 'shift' at the cusp at infinity of the q-series. The 'true' q-expansion of the eta quotient is then q^shift*q_expansion """ num = self._arg_num*self._exp_num-self._arg_den*self._exp_den return QQ(num)/QQ(24) def q_expansion(self,n=20): r""" Give the q-expansion of the quotient. """ var('q') et = qexp_eta(ZZ[['q']],n) etA= et.subs(q=q**self._arg_num).power_series(ZZ[['q']]) etB= et.subs(q=q**self._arg_den).power_series(ZZ[['q']]) res = etA**(self._exp_num)/etB**(self._exp_den) return res #def _action(self,A): # return self._action(A) def _action(self,A): [a,b,c,d]=A if not c % self._level == 0 : raise ValueError,"Need A in {0}! Got: {1}".format(self.group,A) fak=1 if c<0: a=-a; b=-b; c=-c; d=-d; fak=-self._fak #fak = fak*(-1)**(self._exp_num-self._exp_den) arg1,v1 = eta_conjugated(a,b,c,d,self._arg_num) arg2,v2 = eta_conjugated(a,b,c,d,self._arg_den) res=self._z**(arg1*self._exp_num-arg2*self._exp_den) if v1<>1: res=res*v1**self._exp_num if v2<>1: res=res/v2**self._exp_den if fak<>1: res=res*fak**(self._exp_num-self._exp_den) return res
class EtaMultiplier(MultiplierSystem): r""" Eta multiplier. Valid for any (real) weight. """ def __init__(self,G,k=QQ(1)/QQ(2),number=0,ch=None,dual=False,version=1,dimension=1,**kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) """ self._weight=QQ(k) if floor(self._weight-QQ(1)/QQ(2))==ceil(self._weight-QQ(1)/QQ(2)): self._half_integral_weight=1 else: self._half_integral_weight=0 MultiplierSystem.__init__(self,G,character=ch,dual=dual,dimension=dimension) number = number % 12 if not is_even(number): raise ValueError,"Need to have v_eta^(2(k+r)) with r even!" self._pow=QQ((self._weight+number)) ## k+r self._k_den=self._pow.denominator() self._k_num=self._pow.numerator() self._K = CyclotomicField(12*self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2*self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency def __repr__(self): s="Eta multiplier " if self._pow<>1: s+="to power 2*"+str(self._pow)+" " if self._character<>None and not self._character.is_trivial(): s+=" and character "+str(self._character) s+="with weight="+str(self._weight) return s def order(self): return 12*self._k_den def z(self): return self._z def _action(self,A): if self._version==1: return self._action1(A) elif self._version==2: return self._action2(A) else: raise ValueError def _action1(self,A): [a,b,c,d]=A return self._action0(a,b,c,d) def _action0(self,a,b,c,d): r""" Recall that the formula is valid only for c>0. Otherwise we have to use: v(A)=v((-I)(-A))=sigma(-I,-A)v(-I)v(-A). Then note that by the formula for sigma we have: sigma(-I,SL2Z[a, b, c, d])=-1 if (c=0 and d<0) or c>0 and other wise it is =1. """ fak=1 if c<0: a=-a; b=-b; c=-c; d=-d; fak=-self._fak if c==0: if a>0: res = self._z**b else: res = self._fak*self._z**b else: if is_even(c): arg = (a+d)*c-b*d*(c*c-1)+3*d-3-3*c*d v=kronecker(c,d) else: arg = (a+d)*c-b*d*(c*c-1)-3*c v=kronecker(d,c) if not self._half_integral_weight: # recall that we can use eta for any real weight v=v**(2*self._weight) arg=arg*(self._k_num) res = v*fak*self._z**arg if self._character: res = res * self._character(d) if self._is_dual: res=res**-1 return res def _action2(self,A): [a,b,c,d]=A fak=1 if c<0: a=-a; b=-b; c=-c; d=-d; fak=-self._fak if c==0: if a>0: res = self._z**b else: res = self._fak*self._z**b else: arg = dedekind_sum(-d,c) arg = arg+QQ(a+d)/QQ(12*c)-QQ(1)/QQ(4) # print "arg=",arg arg=arg*QQ(2) den = arg.denominator()*self._k_den num = arg.numerator()*self._k_num K = CyclotomicField(2*den) z=K.gen() if z.multiplicative_order()>4: fak=K(fak) # z = CyclotomicField(2*arg.denominator()).gen() res = z**num #rg.numerator() if self._character: ch = self._character(d) res=res*ch res = res*fak if self._is_dual: return res**-1 return res
class EtaMultiplier(MultiplierSystem): r""" Eta multiplier. Valid for any (real) weight. """ def __init__(self, G, k=QQ(1) / QQ(2), number=0, ch=None, dual=False, version=1, dimension=1, **kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) """ self._weight = QQ(k) if floor(self._weight - QQ(1) / QQ(2)) == ceil(self._weight - QQ(1) / QQ(2)): self._half_integral_weight = 1 else: self._half_integral_weight = 0 MultiplierSystem.__init__(self, G, character=ch, dual=dual, dimension=dimension) number = number % 12 if not is_even(number): raise ValueError("Need to have v_eta^(2(k+r)) with r even!") self._pow = QQ((self._weight + number)) ## k+r self._k_den = self._pow.denominator() self._k_num = self._pow.numerator() self._K = CyclotomicField(12 * self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2 * self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency def __repr__(self): s = "Eta multiplier " if self._pow != 1: s += "to power 2*" + str(self._pow) + " " if self._character != None and not self._character.is_trivial(): s += " and character " + str(self._character) s += "with weight=" + str(self._weight) return s def order(self): return 12 * self._k_den def z(self): return self._z def _action(self, A): if self._version == 1: return self._action1(A) elif self._version == 2: return self._action2(A) else: raise ValueError def _action1(self, A): [a, b, c, d] = A return self._action0(a, b, c, d) def _action0(self, a, b, c, d): r""" Recall that the formula is valid only for c>0. Otherwise we have to use: v(A)=v((-I)(-A))=sigma(-I,-A)v(-I)v(-A). Then note that by the formula for sigma we have: sigma(-I,SL2Z[a, b, c, d])=-1 if (c=0 and d<0) or c>0 and other wise it is =1. """ fak = 1 if c < 0: a = -a b = -b c = -c d = -d fak = -self._fak if c == 0: if a > 0: res = self._z**b else: res = self._fak * self._z**b else: if is_even(c): arg = (a + d) * c - b * d * (c * c - 1) + 3 * d - 3 - 3 * c * d v = kronecker(c, d) else: arg = (a + d) * c - b * d * (c * c - 1) - 3 * c v = kronecker(d, c) if not self._half_integral_weight: # recall that we can use eta for any real weight v = v**(2 * self._weight) arg = arg * (self._k_num) res = v * fak * self._z**arg if self._character: res = res * self._character(d) if self._is_dual: res = res**-1 return res def _action2(self, A): [a, b, c, d] = A fak = 1 if c < 0: a = -a b = -b c = -c d = -d fak = -self._fak if c == 0: if a > 0: res = self._z**b else: res = self._fak * self._z**b else: arg = dedekind_sum(-d, c) arg = arg + QQ(a + d) / QQ(12 * c) - QQ(1) / QQ(4) # print "arg=",arg arg = arg * QQ(2) den = arg.denominator() * self._k_den num = arg.numerator() * self._k_num K = CyclotomicField(2 * den) z = K.gen() if z.multiplicative_order() > 4: fak = K(fak) # z = CyclotomicField(2*arg.denominator()).gen() res = z**num #rg.numerator() if self._character: ch = self._character(d) res = res * ch res = res * fak if self._is_dual: return res**-1 return res
class EtaQuotientMultiplier_2(MultiplierSystem): r""" Eta multiplier given by eta(Az)^{r}/eta(Bz)^s The weight should be r/2-s/2 mod 2. The group is Gamma0(lcm(A,B)) """ def __init__(self, A, B, r, s, k=None, number=0, ch=None, dual=False, version=1, **kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) EXAMPLE: """ self._level = lcm(A, B) G = Gamma0(self._level) if k == None: k = (QQ(r) - QQ(s)) / QQ(2) self._weight = QQ(k) if floor(self._weight - QQ(1) / QQ(2)) == ceil(self._weight - QQ(1) / QQ(2)): self._half_integral_weight = 1 else: self._half_integral_weight = 0 MultiplierSystem.__init__(self, G, dimension=1, character=ch, dual=dual) number = number % 12 if not is_even(number): raise ValueError("Need to have v_eta^(2(k+r)) with r even!") self._arg_num = A self._arg_den = B self._exp_num = r self._exp_den = s self._pow = QQ((self._weight + number)) ## k+r self._k_den = self._pow.denominator() self._k_num = self._pow.numerator() self._K = CyclotomicField(12 * self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2 * self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency def __repr__(self): s = "Quotient of Eta multipliers : " s += "eta({0})^{1}/eta({2})^{3}".format(self._arg_num, self._exp_num, self._arg_den, self._exp_den) if self._character != None and not self._character.is_trivial(): s += " and character " + str(self._character) s += " with weight=" + str(self._weight) return s def level(self): return self._level def order(self): return 12 * self._k_den def z(self): return self._z def q_shift(self): r""" Gives the 'shift' at the cusp at infinity of the q-series. The 'true' q-expansion of the eta quotient is then q^shift*q_expansion """ num = self._arg_num * self._exp_num - self._arg_den * self._exp_den return QQ(num) / QQ(24) def q_expansion(self, n=20): r""" Give the q-expansion of the quotient. """ q = ZZ[['q']].gen() et = qexp_eta(ZZ[['q']], n) etA = et.subs(q=q**self._arg_num).power_series(ZZ[['q']]) etB = et.subs(q=q**self._arg_den).power_series(ZZ[['q']]) res = etA**(self._exp_num) * etB**(-self._exp_den) return res #def _action(self,A): # return self._action(A) def _action(self, A): [a, b, c, d] = A if not c % self._level == 0: raise ValueError("Need A in {0}! Got: {1}".format(self.group, A)) fak = 1 if c < 0: a = -a b = -b c = -c d = -d fak = -self._fak #fak = fak*(-1)**(self._exp_num-self._exp_den) arg1, v1 = eta_conjugated(a, b, c, d, self._arg_num) arg2, v2 = eta_conjugated(a, b, c, d, self._arg_den) res = self._z**(arg1 * self._exp_num - arg2 * self._exp_den) if v1 != 1: res = res * v1**self._exp_num if v2 != 1: res = res * v2**(-self._exp_den) if fak != 1: res = res * fak**(self._exp_num - self._exp_den) return res
class EtaQuotientMultiplier(MultiplierSystem): r""" Eta multiplier given by eta(Az)^{r}/eta(Bz)^s The weight should be r/2-s/2 mod 2. The group is Gamma0(lcm(A,B)) """ def __init__(self, args=[1], exponents=[1], ch=None, dual=False, version=1, **kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) EXAMPLE: """ assert len(args) == len(exponents) self._level = lcm(args) G = Gamma0(self._level) k = sum([QQ(x) * QQ(1) / QQ(2) for x in exponents]) self._weight = QQ(k) if floor(self._weight - QQ(1) / QQ(2)) == ceil(self._weight - QQ(1) / QQ(2)): self._half_integral_weight = 1 else: self._half_integral_weight = 0 MultiplierSystem.__init__(self, G, dimension=1, character=ch, dual=dual) self._arguments = args self._exponents = exponents self._pow = QQ((self._weight)) ## k+r self._k_den = self._weight.denominator() self._k_num = self._weight.numerator() self._K = CyclotomicField(12 * self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2 * self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency def __repr__(self): s = "Quotient of Eta multipliers : " for i in range(len(self._arguments)): n = self._arguments[i] e = self._exponents[i] s += "eta({0}z)^{1}".format(n, e) if i < len(self._arguments) - 1: s += "*" if self._character != None and not self._character.is_trivial(): s += " and character " + str(self._character) s += " with weight=" + str(self._weight) return s def level(self): return self._level def order(self): return 12 * self._k_den def z(self): return self._z def q_shift(self): r""" Gives the 'shift' at the cusp at infinity of the q-series. The 'true' q-expansion of the eta quotient is then q^shift*q_expansion """ num = sum([ self._argument[i] * self._exponent[i] for i in range(len(self._arguments)) ]) return QQ(num) / QQ(24) def q_expansion(self, n=20): r""" Give the q-expansion of the quotient. """ eta = qexp_eta(ZZ[['q']], n) R = eta.parent() q = R.gens()[0] res = R(1) prefak = 0 for i in range(len(self._arguments)): res = res * eta.subs({q: q**self._arguments[i] })**self._exponents[i] prefak = prefak + self._arguments[i] * self._exponents[i] if prefak % 24 == 0: return res * q**(prefak / QQ(24)) else: return res, prefak / QQ(24) #etA= et.subs(q=q**self._arg_num).power_series(ZZ[['q']]) #etB= et.subs(q=q**self._arg_den).power_series(ZZ[['q']]) #res = etA**(self._exp_num)/etB**(self._exp_den) #return res #def _action(self,A): # return self._action(A) def _action(self, A): [a, b, c, d] = A if not c % self._level == 0: raise ValueError("Need A in {0}! Got: {1}".format(self.group, A)) fak = 1 if c < 0: a = -a b = -b c = -c d = -d fak = -self._fak #fak = fak*(-1)**(self._exp_num-self._exp_den) res = 1 exp = 0 for i in range(len(self._exponents)): z = CyclotomicField(lcm(12, self._exponents[i].denominator())).gen() arg, v = eta_conjugated(a, b, c, d, self._arguments[i]) #arg2,v2 = eta_conjugated(a,b,c,d,self._arg_den) #res=self._z**(arg1*self._exp_num-arg2*self._exp_den) # exp += arg*self._exponents[i] if v != 1: res = res * v**self._exponents[i] #if v2<>1: #res=res/v2**self._exp_den res = res * z**(arg * self._exponents[i].numerator()) # res = res*self._z**exp if fak != 1: res = res * fak**exp return res
class EtaQuotientMultiplier(MultiplierSystem): r""" Eta multiplier given by eta(Az)^{r}/eta(Bz)^s The weight should be r/2-s/2 mod 2. The group is Gamma0(lcm(A,B)) """ def __init__(self,args=[1],exponents=[1],ch=None,dual=False,version=1,**kwargs): r""" Initialize the Eta multiplier system: $\nu_{\eta}^{2(k+r)}$. INPUT: - G -- Group - ch -- character - dual -- if we have the dual (in this case conjugate) - weight -- Weight (recall that eta has weight 1/2 and eta**2k has weight k. If weight<>k we adjust the power accordingly. - number -- we consider eta^power (here power should be an integer so as not to change the weight...) EXAMPLE: """ assert len(args) == len(exponents) self._level=lcm(args) G = Gamma0(self._level) k = sum([QQ(x)*QQ(1)/QQ(2) for x in exponents]) self._weight=QQ(k) if floor(self._weight-QQ(1)/QQ(2))==ceil(self._weight-QQ(1)/QQ(2)): self._half_integral_weight=1 else: self._half_integral_weight=0 MultiplierSystem.__init__(self,G,dimension=1,character=ch,dual=dual) self._arguments = args self._exponents =exponents self._pow=QQ((self._weight)) ## k+r self._k_den = self._weight.denominator() self._k_num = self._weight.numerator() self._K = CyclotomicField(12*self._k_den) self._z = self._K.gen()**self._k_num self._i = CyclotomicField(4).gen() self._fak = CyclotomicField(2*self._k_den).gen()**-self._k_num self._version = version self.is_consistent(k) # test consistency def __repr__(self): s="Quotient of Eta multipliers : " for i in range(len(self._arguments)): n = self._arguments[i] e = self._exponents[i] s+="eta({0}z)^{1}".format(n,e) if i < len(self._arguments)-1: s+="*" if self._character<>None and not self._character.is_trivial(): s+=" and character "+str(self._character) s+=" with weight="+str(self._weight) return s def level(self): return self._level def order(self): return 12*self._k_den def z(self): return self._z def q_shift(self): r""" Gives the 'shift' at the cusp at infinity of the q-series. The 'true' q-expansion of the eta quotient is then q^shift*q_expansion """ num = sum([self._argument[i]*self._exponent[i] for i in range(len(self._arguments))]) return QQ(num)/QQ(24) def q_expansion(self,n=20): r""" Give the q-expansion of the quotient. """ eta = qexp_eta(ZZ[['q']],n) R = eta.parent() q = R.gens()[0] res = R(1) prefak = 0 for i in range(len(self._arguments)): res = res*eta.subs({q:q**self._arguments[i]})**self._exponents[i] prefak = prefak+self._arguments[i]*self._exponents[i] if prefak % 24 == 0: return res*q**(prefak/24) else: return res,prefak/24 #etA= et.subs(q=q**self._arg_num).power_series(ZZ[['q']]) #etB= et.subs(q=q**self._arg_den).power_series(ZZ[['q']]) #res = etA**(self._exp_num)/etB**(self._exp_den) #return res #def _action(self,A): # return self._action(A) def _action(self,A): [a,b,c,d]=A if not c % self._level == 0 : raise ValueError,"Need A in {0}! Got: {1}".format(self.group,A) fak=1 if c<0: a=-a; b=-b; c=-c; d=-d; fak=-self._fak #fak = fak*(-1)**(self._exp_num-self._exp_den) res = 1 exp = 0 for i in range(len(self._exponents)): z = CyclotomicField(lcm(12,self._exponents[i].denominator())).gen() arg,v = eta_conjugated(a,b,c,d,self._arguments[i]) #arg2,v2 = eta_conjugated(a,b,c,d,self._arg_den) #res=self._z**(arg1*self._exp_num-arg2*self._exp_den) # exp += arg*self._exponents[i] if v<>1: res=res*v**self._exponents[i] #if v2<>1: #res=res/v2**self._exp_den res = res*z**(arg*self._exponents[i].numerator()) # res = res*self._z**exp if fak<>1: res=res*fak**exp return res