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)
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 __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 __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 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
def coefficient_at_coset(self, n): r""" Compute Fourier coefficients of f|A_n """ if hasattr(n, "matrix"): n = self._get_coset_n(n) if not self._base_coeffs: self.coefficients_f() CF = ComplexField(self._prec) if not self._coefficients_at_coset.has_key(n): M = self.truncation_M(n) h, w = self.get_shift_and_width_for_coset(n) zN = CyclotomicField(w).gens()[0] prec1 = self._prec + ceil(log_b(M, 2)) RF = RealField(prec1) coeffs = [] fak = RF(w)**-(RF(self._k) / RF(2)) #print "f=",f,n for i in range(M): al = CF(self.atkin_lehner(n)) c0 = self._base_coeffs_embedding[i] #if hasattr(c0,"complex_embeddings"): # c0 = c0.complex_embedding(prec1) #else: # c0 = CF(c0) qN = zN**((i + 1) * h) #print "qN=",qN,type(qN) an = fak * al * c0 * qN.complex_embedding(prec1) #an = self.atkin_lehner(n)*self._base_coeffs[i]*zN**((i+1)*h) #an = f*an.complex_embedding(prec1) coeffs.append(an) self._coefficients_at_coset[n] = coeffs return self._coefficients_at_coset[n]
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 character_formatted(self): char_vals = self.character() charfield = int(self.character_field()) zet = CyclotomicField(charfield).gen() print char_vals s = [sum([y[j] * zet**j for j in range(len(y))])._latex_() for y in char_vals] return s
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
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 __init__(self, group, dchar=(0, 0), dual=False, is_trivial=False, dimension=1, **kwargs): if not ZZ(4).divides(group.level()): raise ValueError(" Need level divisible by 4. Got: {0} ".format( self._group.level())) MultiplierSystem.__init__(self, group, dchar=dchar, dual=dual, is_trivial=is_trivial, dimension=dimension, **kwargs) self._i = CyclotomicField(4).gen() self._one = self._i**4 self._weight = QQ(kwargs.get("weight", QQ(1) / QQ(2))) ## We have to make sure that we have the correct multiplier & character ## for the desired weight if self._weight != None: if floor(2 * self._weight) != ceil(2 * self._weight): raise ValueError( " Use ThetaMultiplier for half integral or integral weight only!" ) t = self.is_consistent(self._weight) if not t: self.set_dual() t1 = self.is_consistent(self._weight) if not t1: raise ArithmeticError( "Could not find consistent theta multiplier! Try to add a character." )
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 sage_character(self, order, genvalues): H = DirichletGroup(self.modulus, base_ring=CyclotomicField( self.sage_zeta_order(order))) M = H._module order_corrected_genvalues = get_sage_genvalues( self.modulus, order, genvalues, self.sage_zeta_order(order)) return DirichletCharacter(H, M(order_corrected_genvalues))
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 to_dirichlet_character(self, character): if character['order'] == 1: from sage.all import trivial_character return trivial_character(character['modulus']) from sage.all import DirichletGroup, CyclotomicField, QQ from sage.modular.dirichlet import DirichletCharacter zeta_order = character['zeta_order'] R = QQ if zeta_order == 2 else CyclotomicField(zeta_order) G = DirichletGroup(character['modulus'], R, zeta_order=zeta_order) v = G.an_element().element().parent()(character['element']) return DirichletCharacter(G, v)
def parse_field_string(F): # parse Q, Qsqrt2, Qsqrt-4, Qzeta5, etc if F == 'Q': return '1.1.1.1' if F == 'Qi': return '2.0.4.1' # Change unicode dash with minus sign F = F.replace(u'\u2212', '-') # remove non-ascii characters from F F = F.decode('utf8').encode('ascii', 'ignore') fail_string = str( F + ' is not a valid field label or name or polynomial, or is not ') if len(F) == 0: return "Entry for the field was left blank. You need to enter a field label, field name, or a polynomial." if F[0] == 'Q': if F[1:5] in ['sqrt', 'root']: try: d = ZZ(str(F[5:])).squarefree_part() except ValueError: return fail_string if d % 4 in [2, 3]: D = 4 * d else: D = d absD = D.abs() s = 0 if D < 0 else 2 return '2.%s.%s.1' % (s, str(absD)) if F[1:5] == 'zeta': try: d = ZZ(str(F[5:])) except ValueError: return fail_string if d < 1: return fail_string if d % 4 == 2: d /= 2 # Q(zeta_6)=Q(zeta_3), etc) if d == 1: return '1.1.1.1' deg = euler_phi(d) if deg > 23: return '%s is not ' % F adisc = CyclotomicField(d).discriminant().abs() # uses formula! return '%s.0.%s.1' % (deg, adisc) return fail_string # check if a polynomial was entered F = F.replace('X', 'x') if 'x' in F: F1 = F.replace('^', '**') # print F F1 = poly_to_field_label(F1) if F1: return F1 return str(F + ' is not ') return F
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 factor_perm_repn(self, nfgg=None): if 'artincoefs' in self._data: return self._data['artincoefs'] try: if nfgg is not None: self._data["nfgg"] = nfgg else: if "nfgg" not in self._data: from artin_representations.math_classes import NumberFieldGaloisGroup nfgg = NumberFieldGaloisGroup(self._data['coeffs']) self._data["nfgg"] = nfgg else: nfgg = self._data["nfgg"] cc = nfgg.conjugacy_classes() # cc is list, each has methods group, size, order, representative ccreps = [x.representative() for x in cc] ccns = [int(x.size()) for x in cc] ccreps = [x.cycle_string() for x in ccreps] ccgen = '[' + ','.join(ccreps) + ']' ar = nfgg.artin_representations() # list of artin reps from db arfull = nfgg.artin_representations_full_characters( ) # list of artin reps from db gap.set( 'fixed', 'function(a,b) if a*b=a then return 1; else return 0; fi; end;' ) g = gap.Group(ccgen) h = g.Stabilizer('1') rc = g.RightCosets(h) # Permutation character for our field permchar = [gap.Sum(rc, 'j->fixed(j,' + x + ')') for x in ccreps] charcoefs = [0 for x in arfull] # list of lists (inner are giving char values ar2 = [x[0] for x in arfull] for j in range(len(ar)): fieldchar = int(arfull[j][1]) zet = CyclotomicField(fieldchar).gen() ar2[j] = [psum(zet, x) for x in ar2[j]] for j in range(len(ar)): charcoefs[j] = 0 for k in range(len(ccns)): charcoefs[j] += int(permchar[k]) * ccns[k] * ar2[j][k] charcoefs = [x / int(g.Size()) for x in charcoefs] self._data['artincoefs'] = charcoefs return charcoefs except AttributeError: return [] return []
def xi(self, A): r""" The eight-root of unity in front of the Weil representation. INPUT: -''N'' -- integer -''A'' -- element of PSL(2,Z) EXAMPLES:: sage: A=SL2Z([41,77,33,62]) sage: WR.xi(A) -zeta8^3] sage: S,T=SL2Z.gens() sage: WR.xi(S) -zeta8^3 sage: WR.xi(T) 1 sage: A=SL2Z([-1,1,-4,3]) sage: WR.xi(A) -zeta8^2 sage: A=SL2Z([0,1,-1,0]) sage: WR.xi(A) -zeta8 """ a = Integer(A[0, 0]) b = Integer(A[0, 1]) c = Integer(A[1, 0]) d = Integer(A[1, 1]) if (c == 0): return 1 z = CyclotomicField(8).gen() N = self._N N2 = odd_part(N) Neven = ZZ(2 * N).divide_knowing_divisible_by(N2) c2 = odd_part(c) Nc = gcd(Integer(2 * N), Integer(c)) cNc = ZZ(c).divide_knowing_divisible_by(Nc) f1 = kronecker(-a, cNc) f2 = kronecker(cNc, ZZ(2 * N).divide_knowing_divisible_by(Nc)) if (is_odd(c)): s = c * N2 elif (c % Neven == 0): s = (c2 + 1 - N2) * (a + 1) else: s = (c2 + 1 - N2) * (a + 1) - N2 * a * c2 r = -1 - QQ(N2) / QQ(gcd(c, N2)) + s xi = f1 * f2 * z**r return xi
def parse_field_string(F): # parse Q, Qsqrt2, Qsqrt-4, Qzeta5, etc if F == 'Q': return '1.1.1.1' if F == 'Qi': return '2.0.4.1' fail_string = str( F + ' is not a valid field label or name or polynomial, or is not ') if len(F) == 0: return "Entry for the field was left blank. You need to enter a field label, field name, or a polynomial." if F[0] == 'Q': if F[1:5] in ['sqrt', 'root']: try: d = ZZ(str(F[5:])).squarefree_part() except ValueError: return fail_string if d % 4 in [2, 3]: D = 4 * d else: D = d absD = D.abs() s = 0 if D < 0 else 2 return '2.%s.%s.1' % (s, str(absD)) if F[1:5] == 'zeta': try: d = ZZ(str(F[5:])) except ValueError: return fail_string if d < 1: return fail_string if d % 4 == 2: d /= 2 # Q(zeta_6)=Q(zeta_3), etc) if d == 1: return '1.1.1.1' deg = euler_phi(d) if deg > 20: return fail_string adisc = CyclotomicField(d).discriminant().abs() # uses formula! return '%s.0.%s.1' % (deg, adisc) return fail_string # check if a polynomial was entered F = F.replace('X', 'x') if 'x' in F: F = F.replace('^', '**') # print F F = poly_to_field_label(F) if F: return F return fail_string return F
def K(self, m, n, c): r""" K(m,n,c) = sum_{d (c)} e((md+n\bar{d})/c) """ summa = 0 z = CyclotomicField(c).gen() print("z={0}".format(z)) for d in range(c): if gcd(d, c) > 1: continue try: dbar = inverse_mod(d, c) except ZeroDivisionError: print("c={0}".format(c)) print("d={0}".format(d)) raise ZeroDivisionError arg = m * dbar + n * d #print "arg=",arg summa = summa + z**arg return summa
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
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 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
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 __init__(self,N,k=None,dual=False,sym_type=0,verbose=0): r""" Creates a Weil representation (or its dual) of the discriminant form given by D=Z/2NZ. EXAMPLES:: sage: WR=WeilRepDiscriminantForm(1,dual=True) sage: WR.D [0, 1/2] sage: WR.D_as_integers [0, 1] sage: WR.Qv [0, -1/4] sage: WR=WeilRepDiscriminantForm(1,dual=False) sage: WR.D [0, 1/2] sage: WR.D_as_integers [0, 1] sage: WR.Qv [0, 1/4] """ ## If N<0 we use |N| and set dual rep. to true self._verbose = verbose if N<0: self._N=-N self.dual = not dual self._is_dual_rep= not dual # do we use dual representation or not else: self._N=N self._is_dual_rep=dual N2=Integer(2*self._N) self.group=SL2Z self._level=4*self._N self._D_as_integers=list(range(0,N2)) self._even_submodule=[] self._odd_submodule=[] self._D=list() for x in range(0,N2): y=QQ(x)/QQ(N2) self._D.append(y) self.Qv=list() # List of +- q(x) for x in D self.Qv_times_level=list() # List of +- 4N*q(x) for x in D if self._is_dual_rep: # we add this already here for efficiency sig=-1 else: sig=1 for x in self._D: y=sig*self.Q(x) self.Qv.append(y) self.Qv_times_level.append(self._level*y) self._signature = sig self._sigma_invariant = CyclotomicField(8).gens()[0]**-self._signature self._rank = N2 self._weight = None self._sym_type = sym_type if sym_type==0 and k != None: # Then we set it self._weight = QQ(k) if ((self._weight-QQ(1)/QQ(2)) % 2) == 0: sym_type = sig elif ((self._weight-QQ(3)/QQ(2)) % 2) == 0: sym_type = -sig else: raise ValueError("Got incompatible weight and signature!") elif sym_type != 0 and k == None: ## Set the weight if sig==sym_type: self._weight = QQ(1)/QQ(2) elif sig==-sym_type: self._weight = QQ(3)/QQ(2) else: raise ValueError("Got incompatible symmetry type and signature!") elif sym_type==0 and k==None: ## Set the weight ## We make a choice self._sym_type = sig self._weight = QQ(1)/QQ(2) else: ## Check consistency self._weight = QQ(k) if ((self._weight-QQ(1)/QQ(2)) % 2) == 0 and self._sym_type == sig: pass elif ((self._weight-QQ(3)/QQ(2)) % 2) == 0 and self._sym_type == -sig: pass else: raise ValueError("Need either sym type or weight!")
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(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
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,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
def nf_string_to_label(F): # parse Q, Qsqrt2, Qsqrt-4, Qzeta5, etc if F == 'Q': return '1.1.1.1' if F == 'Qi' or F == 'Q(i)': return '2.0.4.1' # Change unicode dash with minus sign F = F.replace(u'\u2212', '-') # remove non-ascii characters from F F = F.decode('utf8').encode('ascii', 'ignore') if len(F) == 0: raise ValueError( "Entry for the field was left blank. You need to enter a field label, field name, or a polynomial." ) if F[0] == 'Q': if '(' in F and ')' in F: F = F.replace('(', '').replace(')', '') if F[1:5] in ['sqrt', 'root']: try: d = ZZ(str(F[5:])).squarefree_part() except (TypeError, ValueError): d = 0 if d == 0: raise ValueError( "After {0}, the remainder must be a nonzero integer. Use {0}5 or {0}-11 for example." .format(F[:5])) if d == 1: return '1.1.1.1' if d % 4 in [2, 3]: D = 4 * d else: D = d absD = D.abs() s = 0 if D < 0 else 2 return '2.%s.%s.1' % (s, str(absD)) if F[1:5] == 'zeta': if '_' in F: F = F.replace('_', '') try: d = ZZ(str(F[5:])) except ValueError: d = 0 if d < 1: raise ValueError( "After {0}, the remainder must be a positive integer. Use {0}5 for example." .format(F[:5])) if d % 4 == 2: d /= 2 # Q(zeta_6)=Q(zeta_3), etc) if d == 1: return '1.1.1.1' deg = euler_phi(d) if deg > 23: raise ValueError('%s is not in the database.' % F) adisc = CyclotomicField(d).discriminant().abs() # uses formula! return '%s.0.%s.1' % (deg, adisc) raise ValueError( 'It is not a valid field name or label, or a defining polynomial.') # check if a polynomial was entered F = F.replace('X', 'x') if 'x' in F: F1 = F.replace('^', '**') # print F from lmfdb.number_fields.number_field import poly_to_field_label F1 = poly_to_field_label(F1) if F1: return F1 raise ValueError('%s does not define a number field in the database.' % F) # Expand out factored labels, like 11.11.11e20.1 if not re.match(r'\d+\.\d+\.[0-9e_]+\.\d+', F): raise ValueError("It must be of the form d.r.D.n, such as 2.2.5.1.") parts = F.split(".") def raise_power(ab): if ab.count("e") == 0: return ZZ(ab) elif ab.count("e") == 1: a, b = ab.split("e") return ZZ(a)**ZZ(b) else: raise ValueError( "Malformed absolute discriminant. It must be a sequence of strings AeB for A and B integers, joined by _s. For example, 2e7_3e5_11." ) parts[2] = str(prod(raise_power(c) for c in parts[2].split("_"))) return ".".join(parts)
def gauss_sum(a, p): K = CyclotomicField(p, names=('zeta',)) (zeta,) = K.gens() return sum(legendre_symbol(n, p) * zeta**(a * n) for n in range(Integer(1), p))