def central_character(self): r""" Return the central character of this representation. This is the restriction to `\QQ_p^\times` of the unique smooth character `\omega` of `\mathbf{A}^\times / \QQ^\times` such that `\omega(\varpi_\ell) = \ell^j \varepsilon(\ell)` for all primes `\ell \nmid Np`, where `\varpi_\ell` is a uniformiser at `\ell`, `\varepsilon` is the Nebentypus character of the newform `f`, and `j` is the twist factor (see the documentation for :func:`~LocalComponent`). EXAMPLES:: sage: LocalComponent(Newform('27a'), 3).central_character() Character of Q_3*, of level 0, mapping 3 |--> 1 sage: LocalComponent(Newforms(Gamma1(5), 5, names='c')[0], 5).central_character() Character of Q_5*, of level 1, mapping 2 |--> c0 + 1, 5 |--> 125 sage: LocalComponent(Newforms(DirichletGroup(24)([1, -1,-1]), 3, names='a')[0], 2).central_character() Character of Q_2*, of level 3, mapping 7 |--> 1, 5 |--> -1, 2 |--> -2 """ from sage.arith.all import crt chi = self.newform().character() f = self.prime() ** self.conductor() N = self.newform().level() // f G = DirichletGroup(f, self.coefficient_field()) chip = G([chi(crt(ZZ(x), 1, f, N)) for x in G.unit_gens()]).primitive_character() a = crt(1, self.prime(), f, N) if chip.conductor() == 1: return SmoothCharacterGroupQp(self.prime(), self.coefficient_field()).character(0, [chi(a) * self.prime()**self.twist_factor()]) else: return SmoothCharacterGroupQp(self.prime(), self.coefficient_field()).character(chip.conductor().valuation(self.prime()), list((~chip).values_on_gens()) + [chi(a) * self.prime()**self.twist_factor()])
def lift_to_gamma1(g, m, n): r""" If ``g = [a,b,c,d]`` is a list of integers defining a `2 \times 2` matrix whose determinant is `1 \pmod m`, return a list of integers giving the entries of a matrix which is congruent to `g \pmod m` and to `\begin{pmatrix} 1 & * \\ 0 & 1 \end{pmatrix} \pmod n`. Here `m` and `n` must be coprime. Here `m` and `n` should be coprime positive integers. Either of `m` and `n` can be `1`. If `n = 1`, this still makes perfect sense; this is what is called by the function :func:`~lift_matrix_to_sl2z`. If `m = 1` this is a rather silly question, so we adopt the convention of always returning the identity matrix. The result is always a list of Sage integers (unlike ``lift_to_sl2z``, which tends to return Python ints). EXAMPLE:: sage: from sage.modular.local_comp.liftings import lift_to_gamma1 sage: A = matrix(ZZ, 2, lift_to_gamma1([10, 11, 3, 11], 19, 5)); A [371 68] [ 60 11] sage: A.det() == 1 True sage: A.change_ring(Zmod(19)) [10 11] [ 3 11] sage: A.change_ring(Zmod(5)) [1 3] [0 1] sage: m = list(SL2Z.random_element()) sage: n = lift_to_gamma1(m, 11, 17) sage: assert matrix(Zmod(11), 2, n) == matrix(Zmod(11),2,m) sage: assert matrix(Zmod(17), 2, [n[0], 0, n[2], n[3]]) == 1 sage: type(lift_to_gamma1([10,11,3,11],19,5)[0]) <type 'sage.rings.integer.Integer'> Tests with `m = 1` and with `n = 1`:: sage: lift_to_gamma1([1,1,0,1], 5, 1) [1, 1, 0, 1] sage: lift_to_gamma1([2,3,11,22], 1, 5) [1, 0, 0, 1] """ if m == 1: return [ZZ(1), ZZ(0), ZZ(0), ZZ(1)] a, b, c, d = [ZZ(x) for x in g] if not (a * d - b * c) % m == 1: raise ValueError("Determinant is {0} mod {1}, should be 1".format( (a * d - b * c) % m, m)) c2 = crt(c, 0, m, n) d2 = crt(d, 1, m, n) a3, b3, c3, d3 = [ZZ(_) for _ in lift_to_sl2z(c2, d2, m * n)] r = (a3 * b - b3 * a) % m return [a3 + r * c3, b3 + r * d3, c3, d3]
def lift_to_gamma1(g, m, n): r""" If ``g = [a,b,c,d]`` is a list of integers defining a `2 \times 2` matrix whose determinant is `1 \pmod m`, return a list of integers giving the entries of a matrix which is congruent to `g \pmod m` and to `\begin{pmatrix} 1 & * \\ 0 & 1 \end{pmatrix} \pmod n`. Here `m` and `n` must be coprime. Here `m` and `n` should be coprime positive integers. Either of `m` and `n` can be `1`. If `n = 1`, this still makes perfect sense; this is what is called by the function :func:`~lift_matrix_to_sl2z`. If `m = 1` this is a rather silly question, so we adopt the convention of always returning the identity matrix. The result is always a list of Sage integers (unlike ``lift_to_sl2z``, which tends to return Python ints). EXAMPLES:: sage: from sage.modular.local_comp.liftings import lift_to_gamma1 sage: A = matrix(ZZ, 2, lift_to_gamma1([10, 11, 3, 11], 19, 5)); A [371 68] [ 60 11] sage: A.det() == 1 True sage: A.change_ring(Zmod(19)) [10 11] [ 3 11] sage: A.change_ring(Zmod(5)) [1 3] [0 1] sage: m = list(SL2Z.random_element()) sage: n = lift_to_gamma1(m, 11, 17) sage: assert matrix(Zmod(11), 2, n) == matrix(Zmod(11),2,m) sage: assert matrix(Zmod(17), 2, [n[0], 0, n[2], n[3]]) == 1 sage: type(lift_to_gamma1([10,11,3,11],19,5)[0]) <type 'sage.rings.integer.Integer'> Tests with `m = 1` and with `n = 1`:: sage: lift_to_gamma1([1,1,0,1], 5, 1) [1, 1, 0, 1] sage: lift_to_gamma1([2,3,11,22], 1, 5) [1, 0, 0, 1] """ if m == 1: return [ZZ(1),ZZ(0),ZZ(0),ZZ(1)] a,b,c,d = [ZZ(x) for x in g] if not (a*d - b*c) % m == 1: raise ValueError( "Determinant is {0} mod {1}, should be 1".format((a*d - b*c) % m, m) ) c2 = crt(c, 0, m, n) d2 = crt(d, 1, m, n) a3,b3,c3,d3 = [ZZ(_) for _ in lift_to_sl2z(c2,d2,m*n)] r = (a3*b - b3*a) % m return [a3 + r*c3, b3 + r*d3, c3, d3]
def lift_ramified(g, p, u, n): r""" Given four integers `a,b,c,d` with `p \mid c` and `ad - bc = 1 \pmod{p^u}`, find `a',b',c',d'` congruent to `a,b,c,d \pmod{p^u}`, with `c' = c \pmod{p^{u+1}}`, such that `a'd' - b'c'` is exactly 1, and `\begin{pmatrix} a & b \\ c & d \end{pmatrix}` is in `\Gamma_1(n)`. Algorithm: Uses :func:`~lift_to_gamma1` to get a lifting modulo `p^u`, and then adds an appropriate multiple of the top row to the bottom row in order to get the bottom-left entry correct modulo `p^{u+1}`. EXAMPLES:: sage: from sage.modular.local_comp.liftings import lift_ramified sage: lift_ramified([2,2,3,2], 3, 1, 1) [5, 8, 3, 5] sage: lift_ramified([8,2,12,2], 3, 2, 23) [323, 110, -133584, -45493] sage: type(lift_ramified([8,2,12,2], 3, 2, 23)[0]) <type 'sage.rings.integer.Integer'> """ a,b,c,d = lift_to_gamma1(g, p**u, n) r = crt( (c - g[2]) / p**u * inverse_mod(a, p), 0, p, n) c = c - p**u * r * a d = d - p**u * r * b # assert (c - g[2]) % p**(u+1) == 0 return [a,b,c,d]
def parallel_function_combination(point_p_max): r""" Function used in parallel computation, computes rational points lifted. """ rat_points = set() for tupl in xmrange(len_modulo_points): point = [] for k in range(N): # lift all coordinates of given point using chinese remainder theorem L = [ modulo_points[j][tupl[j]][k].lift() for j in range(len_primes - 1) ] L.append(point_p_max[k].lift()) point.append(crt(L, primes_list)) for i in range(num_comp): for j in range(comp_dim_relative[i]): m[i][j] = point[dim_prefix[i] + j] # generating matrix to compute LLL reduction for each component M = [matrix(ZZ, comp_dim_relative[i] + 1, comp_dim_relative[i], m[i]) \ for i in range(num_comp)] A = [M[i].LLL() for i in range(num_comp)] point = [] for i in range(num_comp): point.extend(A[i][1]) # check if all coordinates of this point satisfy height bound bound_satisfied = True for coordinate in point: if coordinate.abs() > bound: bound_satisfied = False break if not bound_satisfied: continue try: rat_points.add( X(point)) # checks if this point lies on X or not except: pass return [list(_) for _ in rat_points]
def group(self): r""" Return a `\Gamma_H` group which is the level of all of the relevant twists of `f`. EXAMPLE:: sage: from sage.modular.local_comp.type_space import example_type_space sage: example_type_space().group() Congruence Subgroup Gamma_H(98) with H generated by [57] """ p = self.prime() r = self.conductor() d = max(self.character_conductor(), r // 2) n = self.tame_level() chi = self.form().character() tame_H = [i for i in chi.kernel() if (i % p**r) == 1] wild_H = [crt(1 + p**d, 1, p**r, n)] return GammaH(n * p**r, tame_H + wild_H)
def group(self): r""" Return a `\Gamma_H` group which is the level of all of the relevant twists of `f`. EXAMPLE:: sage: from sage.modular.local_comp.type_space import example_type_space sage: example_type_space().group() Congruence Subgroup Gamma_H(98) with H generated by [57] """ p = self.prime() r = self.conductor() d = max(self.character_conductor(), r//2) n = self.tame_level() chi = self.form().character() tame_H = [i for i in chi.kernel() if (i % p**r) == 1] wild_H = [crt(1 + p**d, 1, p**r, n)] return GammaH(n * p**r, tame_H + wild_H)
def _unif_ramified(self): r""" Return the action of [0,-1,p,0], in the ramified (odd p-power level) case. EXAMPLES:: sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(3) sage: T._unif_ramified() [-1 0] [ 0 -1] """ p = self.prime() k = self.form().weight() return (self.t_space.atkin_lehner_operator(p).matrix().transpose() * p**(-(k - 2) * self.u()) * self.t_space.diamond_bracket_matrix( crt(1, p**self.u(), p**self.u(), self.tame_level())).transpose())
def parallel_function_combination(point_p_max): r""" Function used in parallel computation, computes rational points lifted. """ rat_points = set() for tupl in xmrange(len_modulo_points): point = [] for k in range(N + 1): # lift all coordinates of given point using chinese remainder theorem L = [ modulo_points[j][tupl[j]][k].lift() for j in range(len_primes - 1) ] L.append(point_p_max[k].lift()) point.append(crt(L, primes_list)) for i in range(N + 1): m[i] = point[i] M = matrix(ZZ, N + 2, N + 1, m) A = M.LLL() point = list(A[1]) # check if all coordinates of this point satisfy height bound bound_satisfied = True for coordinate in point: if coordinate.abs() > bound: bound_satisfied = False break if not bound_satisfied: continue try: pt = X(list(A[1])) except TypeError: pass else: rat_points.add(pt) return [list(_) for _ in rat_points]
def group(self): r""" Return a `\Gamma_H` group which is the level of all of the relevant twists of `f`. EXAMPLES:: sage: from sage.modular.local_comp.type_space import example_type_space sage: example_type_space().group() Congruence Subgroup Gamma_H(98) with H generated by [15, 29, 43] """ # Implementation here is not the most efficient but this is heavily not # time-critical, and getting it wrong can lead to subtle bugs. p = self.prime() r = self.conductor() d = max(self.character_conductor(), r // 2) n = self.tame_level() chi = self.form().character() tame_H = [i for i in chi.kernel() if (i % p**r) == 1] wild_H = [crt(x, 1, p**r, n) for x in range(p**r) if x % (p**d) == 1] return GammaH(n * p**r, tame_H + wild_H)
def rho(self, g): r""" Calculate the action of the group element `g` on the type space. EXAMPLE:: sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(2) sage: m = T.rho([2,0,0,1]); m [ 1 -2 1 0] [ 1 -1 0 1] [ 1 0 -1 1] [ 0 1 -2 1] sage: v = T.eigensymbol_subspace().basis()[0] sage: m * v == v True We test that it is a left action:: sage: T = example_type_space(0) sage: a = [0,5,4,3]; b = [0,2,3,5]; ab = [1,4,2,2] sage: T.rho(ab) == T.rho(a) * T.rho(b) True An odd level example:: sage: from sage.modular.local_comp.type_space import TypeSpace sage: T = TypeSpace(Newform('54a'), 3) sage: a = [0,1,3,0]; b = [2,1,0,1]; ab = [0,1,6,3] sage: T.rho(ab) == T.rho(a) * T.rho(b) True """ if not self.is_minimal(): raise NotImplementedError( "Group action on non-minimal type space not implemented") if self.u() == 0: # silly special case: rep is principal series or special, so SL2 # action on type space is trivial raise ValueError("Representation is not supercuspidal") p = self.prime() f = p**self.u() g = [ZZ(_) for _ in g] d = (g[0] * g[3] - g[2] * g[1]) # g is in S(K_0) (easy case) if d % f == 1: return self._rho_s(g) # g is in K_0, but not in S(K_0) if d % p != 0: try: a = self._a except AttributeError: self._discover_torus_action() a = self._a i = 0 while (d * a**i) % f != 1: i += 1 if i > f: raise ArithmeticError return self._rho_s([a**i * g[0], g[1], a**i * g[2], g[3] ]) * self._amat**(-i) # funny business if (self.conductor() % 2 == 0): if all([x.valuation(p) > 0 for x in g]): eps = self.form().character()(crt(1, p, f, self.tame_level())) return ~eps * self.rho([x // p for x in g]) else: raise ArithmeticError("g(={0}) not in K".format(g)) else: m = matrix(ZZ, 2, g) s = m.det().valuation(p) mm = (matrix(QQ, 2, [0, -1, p, 0])**(-s) * m).change_ring(ZZ) return self._unif_ramified()**s * self.rho(mm.list())
def rho(self, g): r""" Calculate the action of the group element `g` on the type space. EXAMPLE:: sage: from sage.modular.local_comp.type_space import example_type_space sage: T = example_type_space(2) sage: m = T.rho([2,0,0,1]); m [ 1 -2 1 0] [ 1 -1 0 1] [ 1 0 -1 1] [ 0 1 -2 1] sage: v = T.eigensymbol_subspace().basis()[0] sage: m * v == v True We test that it is a left action:: sage: T = example_type_space(0) sage: a = [0,5,4,3]; b = [0,2,3,5]; ab = [1,4,2,2] sage: T.rho(ab) == T.rho(a) * T.rho(b) True An odd level example:: sage: from sage.modular.local_comp.type_space import TypeSpace sage: T = TypeSpace(Newform('54a'), 3) sage: a = [0,1,3,0]; b = [2,1,0,1]; ab = [0,1,6,3] sage: T.rho(ab) == T.rho(a) * T.rho(b) True """ if not self.is_minimal(): raise NotImplementedError( "Group action on non-minimal type space not implemented" ) if self.u() == 0: # silly special case: rep is principal series or special, so SL2 # action on type space is trivial raise ValueError( "Representation is not supercuspidal" ) p = self.prime() f = p**self.u() g = [ZZ(_) for _ in g] d = (g[0]*g[3] - g[2]*g[1]) # g is in S(K_0) (easy case) if d % f == 1: return self._rho_s(g) # g is in K_0, but not in S(K_0) if d % p != 0: try: a = self._a except AttributeError: self._discover_torus_action() a = self._a i = 0 while (d * a**i) % f != 1: i += 1 if i > f: raise ArithmeticError return self._rho_s([a**i*g[0], g[1], a**i*g[2], g[3]]) * self._amat**(-i) # funny business if (self.conductor() % 2 == 0): if all([x.valuation(p) > 0 for x in g]): eps = self.form().character()(crt(1, p, f, self.tame_level())) return ~eps * self.rho([x // p for x in g]) else: raise ArithmeticError( "g(={0}) not in K".format(g) ) else: m = matrix(ZZ, 2, g) s = m.det().valuation(p) mm = (matrix(QQ, 2, [0, -1, p, 0])**(-s) * m).change_ring(ZZ) return self._unif_ramified()**s * self.rho(mm.list())