def test_relations_plusminus(self): I = SL2Z([1, 0, 0, 1]) S = SL2Z([0, -1, 1, 0]) U = SL2Z([1, -1, 1, 0]) U2 = SL2Z([0, -1, 1, -1]) lS = [(1, I), (1, S)] lU = [(1, I), (1, U), (1, U2)] ppp1 = {} ppp2 = {} ppp3 = {} ppp4 = {} for n in range(self._dim): p1 = self.action_by_lin_comb(n, lS, sym=1) p2 = self.action_by_lin_comb(n, lU, sym=1) ppp1[n] = p1 ppp2[n] = p2 p1 = self.action_by_lin_comb(n, lS, sym=-1) p2 = self.action_by_lin_comb(n, lU, sym=-1) ppp3[n] = p1 ppp4[n] = p2 for pp in [ppp1, ppp2, ppp3, ppp4]: maxv = 0 for p in pp.values(): if hasattr(p, "coeffs"): if p.coefficients(sparse=False) <> []: tmp = max(map(abs, p.coefficients(sparse=False))) else: tmp = 0 else: tmp = abs(p) if tmp > maxv: maxv = tmp print "maxv=", maxv
def _set_coset_reps(self): if is_prime(self._level): self._coset_reps[0] = SL2Z([1, 0, 0, 1]) for n in range(self._level): self._coset_reps[n + 1] = SL2Z([0, -1, 1, n]) else: G = Gamma0(self._level) n = 0 for A in G.coset_reps(): self._coset_reps[n] = A n += 1
def is_consistent(self, k): r""" Checks that v(-I)=(-1)^k, """ Z = SL2Z([-1, 0, 0, -1]) zi = CyclotomicField(4).gen() v = self._action(Z) if self._verbose > 0: print("test consistency for k={0}".format(k)) print("v(Z)={0}".format(v)) if self._dim == 1: if isinstance(k, Integer) or k.is_integral(): if is_even(k): v1 = ZZ(1) else: v1 = ZZ(-1) elif isinstance(k, Rational) and (k.denominator() == 2 or k == 0): v1 = zi**(-QQ(2 * k)) if self._verbose > 0: print("I**(-2k)={0}".format(v1)) else: raise ValueError( "Only integral and half-integral weight is currently supported! Got weight:{0} of type:{1}" .format(k, type(k))) else: raise NotImplementedError( "Override this function for vector-valued multipliers!") return v1 == v
def petersson_norm(self, type=1): r""" Compute the Petersson norm of f. ALGORITHM: Uses (f,f) = < rho_{f}^{+} | T - T^-1 , rho_f^{-}> for k even and (f,f) = < rho_{f}^{+} | T - T^-1 , rho_f^{+}> for k odd. See e.g. Thm 3.3. in Pasol - Popa "Modular forms and period polynomials" """ if self._peterson_norm <> 0: return self._peterson_norm T = SL2Z([1, 1, 0, 1]) Ti = SL2Z([1, -1, 0, 1]) norm = 0 for n in range(self._dim): if type == 1: p1 = self.slash_action(n, T, sym='plus') p2 = self.slash_action(n, Ti, sym='plus') else: p1 = self.slash_action(n, T, sym='minus') p2 = self.slash_action(n, Ti, sym='minus') pL = p1 - p2 #print "Pl=",pL if self.function().weight() % 2 == 1: if type == 1: pR = self.polynomial_plus(n) else: pR = self.polynomial_minus(n) else: if type == 1: pR = self.polynomial_minus(n) else: pR = self.polynomial_plus(n) #print "PR=",pR t = self.pair_two_pols(pL, pR) #print "t=",t norm += t CF = ComplexField(self._prec) c2 = CF(3) * CF(0, 2)**(self._k - 1) self._peterson_norm = -norm / c2 return self._peterson_norm
def __repr__(self): s = "Multiplier system defined by action on the generators:" if self._group == SL2Z: S, T = SL2Z.gens() Z = S * S s += "r(S)=", self.vals[S] s += "r(T)=", self.vals[T] s += "r(Z)=", self.vals[Z] else: for g in self.vals.keys(): s += "r(", g, ")=", self.vals[g] return s
def __repr__(self): s="Multiplier system defined by action on the generators:" if self._group==SL2Z: S,T=SL2Z.gens() Z=S*S s+="r(S)=",self.vals[S] s+="r(T)=",self.vals[T] s+="r(Z)=",self.vals[Z] else: for g in self.vals.keys(): s+="r(",g,")=",self.vals[g] return s
def _get_shifted_coset_m(self, n, A): r""" Get the index m s.t. A_n*A**-1 is in Gamma0(N)A_m """ An = self.coset_rep(n) if A.det() == 1: m = self._get_coset_n(An * A**-1) elif A.det() == -1 and A[0, 1] == 0 and A[1, 0] == 0: AE = SL2Z([An[0, 0], -An[0, 1], -An[1, 0], An[1, 1]]) m = self._get_coset_n(AE) else: raise ValueError, "Call with SL2Z element or [-1,0,1,0]. Got:{0}".format( E) return m
def test_relations(self): I = SL2Z([1, 0, 0, 1]) S = SL2Z([0, -1, 1, 0]) U = SL2Z([1, -1, 1, 0]) U2 = SL2Z([0, -1, 1, -1]) lS = [(1, I), (1, S)] lU = [(1, I), (1, U), (1, U2)] pS = self * lS pU = self * lU maxS = 0 maxU = 0 if self._verbose > 0: print "pS=", pS print "pU=", pU for p in pS.values(): if hasattr(p, "coeffs"): if p.coefficients(sparse=False) <> []: tmp = max(map(abs, p.coefficients(sparse=False))) else: tmp = 0 else: tmp = abs(p) if tmp > maxS: maxS = tmp for p in pU.values(): if hasattr(p, "coefficients"): if p.coefficients(sparse=False) <> []: tmp = max(map(abs, p.coefficients(sparse=False))) else: tmp = 0 else: tmp = abs(p) if tmp > maxU: maxU = tmp print "Max coeff of self|(1+S)=", maxS print "Max coeff of self|(1+U+U^2)=", maxU
def get_rk(self, n, k): r""" Compute the coefficient r_k((f|A_n)) """ if (n, k) not in self._rks: S, T = SL2Z.gens() nstar = self._get_shifted_coset_m(n, S) kstar = self._k - 2 - k i1 = self.get_integral_from_1_to_oo(n, k) i2 = self.get_integral_from_1_to_oo(nstar, kstar) if self._verbose > 0: print("i1={0}".format(i1)) print("i2={0}".format(i2)) self._rks[(n, k)] = i1 + i2 * (-1)**(k + 1) return self._rks[(n, k)]
def get_rk(self, n, k): r""" Compute the coefficient r_k((f|A_n)) """ if not self._rks.has_key((n, k)): S, T = SL2Z.gens() nstar = self._get_shifted_coset_m(n, S) kstar = self._k - 2 - k i1 = self.get_integral_from_1_to_oo(n, k) i2 = self.get_integral_from_1_to_oo(nstar, kstar) if self._verbose > 0: print "i1=", i1 print "i2=", i2 self._rks[(n, k)] = i1 + i2 * (-1)**(k + 1) return self._rks[(n, k)]
def get_rk(self,n,k): r""" Compute the coefficient r_k((f|A_n)) """ if not self._rks.has_key((n,k)): S,T = SL2Z.gens() nstar = self._get_shifted_coset_m(n,S) kstar = self._k-2-k i1 = self.get_integral_from_1_to_oo(n,k) i2 = self.get_integral_from_1_to_oo(nstar,kstar) if self._verbose>0: print "i1=",i1 print "i2=",i2 self._rks[(n,k)] = i1+i2*(-1)**(k+1) return self._rks[(n,k)]
def _action(self, A): #if A not in self._group: # raise ValueError,"Action is only defined for {0}!".format(self._group) a, b, c, d = A [z, n, l] = factor_matrix_in_sl2z(int(a), int(b), int(c), int(d)) #l,ep = factor_matrix_in_sl2z_in_S_and_T(A_in) res = copy(self.T.parent().one()) if z == -1 and self.v != None: tmp = self.v(SL2Z([-1, 0, 0, -1])) for j in range(self._dim): res[j, j] = tmp if n != 0: res = self.T**n for i in range(len(l)): res = res * self.S * self.T**l[i] return res
def weight(self): r""" Return (modulo 2) which weight self is a multiplier system consistent with """ if self._is_trivial: self._weight = 0 return self._weight if self._dim == 1: if self._weight is None: Z = SL2Z([-1, 0, 0, -1]) v = self._action(Z) if v == 1: self._weight = QQ(0) if v == -1: self._weight = QQ(1) elif v == -I: self._weight = QQ(1) / QQ(2) elif v == I: self._weight = QQ(1) / QQ(2) else: raise NotImplementedError return self._weight
def __init__(self,G,v=None,**kwargs): r""" G should be a subgroup of PSL(2,Z). EXAMPLE:: sage: te=TestMultiplier(Gamma0(2),weight=1/2) sage: r=InducedRepresentation(Gamma0(2),v=te) """ dim = len(list(G.coset_reps())) MultiplierSystem.__init__(self,Gamma0(1),dimension=dim) self._induced_from=G # setup the action on S and T (should be faster...) self.v = v if v<>None: k = v.order() if k>2: K = CyclotomicField(k) else: K=ZZ self.S=matrix(K,dim,dim) self.T=matrix(K,dim,dim) else: self.S=matrix(dim,dim) self.T=matrix(dim,dim) S,T=SL2Z.gens() if hasattr(G,"coset_reps"): if isinstance(G.coset_reps(),list): Vl=G.coset_reps() else: Vl=list(G.coset_reps()) elif hasattr(G,"_G"): Vl=list(G._G.coset_reps()) else: raise ValueError,"Could not get coset representatives from {0}!".format(G) self.repsT=dict() self.repsS=dict() for i in range(dim): Vi=Vl[i] for j in range(dim): Vj=Vl[j] BS = Vi*S*Vj**-1 BT = Vi*T*Vj**-1 #print "i,j #print "ViSVj^-1=",BS #print "ViTVj^-1=",BT if BS in G: if v<>None: vS=v(BS) else: vS=1 self.S[i,j]=vS self.repsS[(i,j)]=BS if BT in G: if v<>None: vT=v(BT) else: vT=1 self.T[i,j]=vT self.repsT[(i,j)]=BT
def rho(self,M,silent=0,numeric=0,prec=-1): r""" The Weil representation acting on SL(2,Z). INPUT:: -``M`` -- element of SL2Z - ''numeric'' -- set to 1 to return a Matrix_complex_dense with prec=prec instead of exact - ''prec'' -- precision EXAMPLES:: sage: WR=WeilRepDiscriminantForm(1,dual=False) sage: S,T=SL2Z.gens() sage: WR.rho(S) [ [-zeta8^3 -zeta8^3] [-zeta8^3 zeta8^3], sqrt(1/2) ] sage: WR.rho(T) [ [ 1 0] [ 0 -zeta8^2], 1 ] sage: A=SL2Z([-1,1,-4,3]); WR.rho(A) [ [zeta8^2 0] [ 0 1], 1 ] sage: A=SL2Z([41,77,33,62]); WR.rho(A) [ [-zeta8^3 zeta8^3] [ zeta8 zeta8], sqrt(1/2) ] """ N=self._N; D=2*N; D2=2*D if numeric==0: K=CyclotomicField (lcm(4*self._N,8)) z=K(CyclotomicField(4*self._N).gen()) rho=matrix(K,D) else: CF = MPComplexField(prec) RF = CF.base() MS = MatrixSpace(CF,int(D),int(D)) rho = Matrix_complex_dense(MS) #arg = RF(2)*RF.pi()/RF(4*self._N) z = CF(0,RF(2)*RF.pi()/RF(4*self._N)).exp() [a,b,c,d]=M fak=1; sig=1 if c<0: # need to use the reflection # r(-A)=r(Z)r(A)sigma(Z,A) where sigma(Z,A)=-1 if c>0 sig=-1 if numeric==0: fz=CyclotomicField(4).gen() # = i else: fz=CF(0,1) # the factor is rho(Z) sigma(Z,-A) #if(c < 0 or (c==0 and d>0)): # fak=-fz #else: #sig=1 #fz=1 fak=fz a=-a; b=-b; c=-c; d=-d; A=SL2Z([a,b,c,d]) if numeric==0: chi=self.xi(A) else: chi=CF(self.xi(A).complex_embedding(prec)) if(silent>0): print("fz={0}".format(fz)) print("chi={0}".format(chi)) elif c == 0: # then we use the simple formula if d < 0: sig=-1 if numeric == 0: fz=CyclotomicField(4).gen() else: fz=CF(0,1) fak=fz a=-a; b=-b; c=-c; d=-d; else: fak=1 for alpha in range(D): arg=(b*alpha*alpha ) % D2 if(sig==-1): malpha = (D - alpha) % D rho[malpha,alpha]=fak*z**arg else: #print "D2=",D2 #print "b=",b #print "arg=",arg rho[alpha,alpha]=z**arg return [rho,1] else: if numeric==0: chi=self.xi(M) else: chi=CF(self.xi(M).complex_embedding(prec)) Nc=gcd(Integer(D),Integer(c)) #chi=chi*sqrt(CF(Nc)/CF(D)) if(valuation(Integer(c),2)==valuation(Integer(D),2)): xc=Integer(N) else: xc=0 if silent>0: print("c={0}".format(c)) print("xc={0}".format(xc)) print("chi={0}".format(chi)) for alpha in range(D): al=QQ(alpha)/QQ(D) for beta in range(D): be=QQ(beta)/QQ(D) c_div=False if(xc==0): alpha_minus_dbeta=(alpha-d*beta) % D else: alpha_minus_dbeta=(alpha-d*beta-xc) % D if silent > 0: # and alpha==7 and beta == 7): print("alpha,beta={0},{1}".format(alpha,beta)) print("c,d={0},{1}".format(c,d)) print("alpha-d*beta={0}".format(alpha_minus_dbeta)) invers=0 for r in range(D): if (r*c - alpha_minus_dbeta) % D ==0: c_div=True invers=r break if c_div and silent > 0: print("invers={0}".format(invers)) print(" inverse(alpha-d*beta) mod c={0}".format(invers)) elif(silent>0): print(" no inverse!") if(c_div): y=invers if xc==0: argu=a*c*y**2+b*d*beta**2+2*b*c*y*beta else: argu=a*c*y**2+2*xc*(a*y+b*beta)+b*d*beta**2+2*b*c*y*beta argu = argu % D2 tmp1=z**argu # exp(2*pi*I*argu) if silent>0:# and alpha==7 and beta==7): print("a,b,c,d={0},{1},{2},{3}".format(a,b,c,d)) print("xc={0}".format(xc)) print("argu={0}".format(argu)) print("exp(...)={0}".format(tmp1)) print("chi={0}".format(chi)) print("sig={0}".format(sig)) if sig == -1: minus_alpha = (D - alpha) % D rho[minus_alpha,beta]=tmp1*chi else: rho[alpha,beta]=tmp1*chi #print "fak=",fak if numeric==0: return [fak*rho,sqrt(QQ(Nc)/QQ(D))] else: return [CF(fak)*rho,RF(sqrt(QQ(Nc)/QQ(D)))]
def nice_coset_reps(G): r""" Compute a better/nicer list of right coset representatives [V_j] i.e. SL2Z = \cup G V_j Use this routine for known congruence subgroups. EXAMPLES:: sage: G=MySubgroup(Gamma0(5)) sage: G._get_coset_reps_from_G(Gamma0(5)) [[1 0] [0 1], [ 0 -1] [ 1 0], [ 0 -1] [ 1 1], [ 0 -1] [ 1 -1], [ 0 -1] [ 1 2], [ 0 -1] [ 1 -2]] """ cl = list() S, T = SL2Z.gens() lvl = G.generalised_level() # Start with identity rep. cl.append(SL2Z([1, 0, 0, 1])) if (not S in G): cl.append(S) # If the original group is given as a Gamma0 then # the reps are not the one we want # I.e. we like to have a fundamental domain in # -1/2 <=x <= 1/2 for Gamma0, Gamma1, Gamma for j in range(1, ZZ(ceil(RR(lvl / 2.0)) + 2)): for ep in [1, -1]: if (len(cl) >= G.index()): break # The ones about 0 are all of this form A = SL2Z([0, -1, 1, ep * j]) # just make sure they are inequivalent try: for V in cl: if ((A <> V and A * V**-1 in G) or cl.count(A) > 0): raise StopIteration() cl.append(A) except StopIteration: pass # We now addd the rest of the "flips" of these reps. # So that we end up with a connected domain i = 1 while (True): lold = len(cl) for V in cl: for A in [S, T, T**-1]: B = V * A try: for W in cl: if ((B * W**-1 in G) or cl.count(B) > 0): raise StopIteration() cl.append(B) except StopIteration: pass if (len(cl) >= G.index() or lold >= len(cl)): # If we either did not addd anything or if we addded enough # we exit break # If we missed something (which is unlikely) if (len(cl) <> G.index()): print "cl=", cl raise ValueError, "Problem getting coset reps! Need %s and got %s" % ( G.index(), len(cl)) return cl
def nice_coset_reps(G): r""" Compute a better/nicer list of right coset representatives [V_j] i.e. SL2Z = \cup G V_j Use this routine for known congruence subgroups. EXAMPLES:: sage: G=MySubgroup(Gamma0(5)) sage: G._get_coset_reps_from_G(Gamma0(5)) [[1 0] [0 1], [ 0 -1] [ 1 0], [ 0 -1] [ 1 1], [ 0 -1] [ 1 -1], [ 0 -1] [ 1 2], [ 0 -1] [ 1 -2]] """ cl=list() S,T=SL2Z.gens() lvl=G.generalised_level() # Start with identity rep. cl.append(SL2Z([1 ,0 ,0 ,1 ])) if(not S in G): cl.append(S) # If the original group is given as a Gamma0 then # the reps are not the one we want # I.e. we like to have a fundamental domain in # -1/2 <=x <= 1/2 for Gamma0, Gamma1, Gamma for j in range(1 , ZZ( ceil(RR(lvl/2.0))+2)): for ep in [1 ,-1 ]: if(len(cl)>=G.index()): break # The ones about 0 are all of this form A=SL2Z([0 ,-1 ,1 ,ep*j]) # just make sure they are inequivalent try: for V in cl: if((A<>V and A*V**-1 in G) or cl.count(A)>0 ): raise StopIteration() cl.append(A) except StopIteration: pass # We now addd the rest of the "flips" of these reps. # So that we end up with a connected domain i=1 while(True): lold=len(cl) for V in cl: for A in [S,T,T**-1 ]: B=V*A try: for W in cl: if( (B*W**-1 in G) or cl.count(B)>0 ): raise StopIteration() cl.append(B) except StopIteration: pass if(len(cl)>=G.index() or lold>=len(cl)): # If we either did not addd anything or if we addded enough # we exit break # If we missed something (which is unlikely) if(len(cl)<>G.index()): print "cl=",cl raise ValueError,"Problem getting coset reps! Need %s and got %s" %(G.index(),len(cl)) return cl
def __init__(self, G, v=None, **kwargs): r""" G should be a subgroup of PSL(2,Z). EXAMPLE:: sage: te=TestMultiplier(Gamma0(2),weight=1/2) sage: r=InducedRepresentation(Gamma0(2),v=te) """ dim = len(list(G.coset_reps())) MultiplierSystem.__init__(self, Gamma0(1), dimension=dim) self._induced_from = G # setup the action on S and T (should be faster...) self.v = v if v != None: k = v.order() if k > 2: K = CyclotomicField(k) else: K = ZZ self.S = matrix(K, dim, dim) self.T = matrix(K, dim, dim) else: self.S = matrix(dim, dim) self.T = matrix(dim, dim) S, T = SL2Z.gens() if hasattr(G, "coset_reps"): if isinstance(G.coset_reps(), list): Vl = G.coset_reps() else: Vl = list(G.coset_reps()) elif hasattr(G, "_G"): Vl = list(G._G.coset_reps()) else: raise ValueError( "Could not get coset representatives from {0}!".format(G)) self.repsT = dict() self.repsS = dict() for i in range(dim): Vi = Vl[i] for j in range(dim): Vj = Vl[j] BS = Vi * S * Vj**-1 BT = Vi * T * Vj**-1 #print "i,j #print "ViSVj^-1=",BS #print "ViTVj^-1=",BT if BS in G: if v != None: vS = v(BS) else: vS = 1 self.S[i, j] = vS self.repsS[(i, j)] = BS if BT in G: if v != None: vT = v(BT) else: vT = 1 self.T[i, j] = vT self.repsT[(i, j)] = BT