def init_tensor_product(self, V, W): """ We are given two Galois representations and we will return their tensor product. """ self.original_object = V.original_object + W.original_object self.object_type = "tensorproduct" self.V1 = V self.V2 = W self.dim = V.dim * W.dim self.motivic_weight = V.motivic_weight + W.motivic_weight self.langlands = False # status 2014 :) self.besancon_bound = min(V.besancon_bound, W.besancon_bound) bad2 = ZZ(W.conductor).prime_factors() bad_primes = [x for x in ZZ(V.conductor).prime_factors() if x in bad2] for p in bad_primes: if (p not in V.bad_semistable_primes and p not in W.bad_semistable_primes): # this condition above only applies to the current type of objects # for general reps we would have to test the lines below # to be certain that the formulae are correct. #if ((p not in V.bad_semistable_primes or p not in W.bad_pot_good) and #(p not in W.bad_semistable_primes or p not in V.bad_pot_good) and #(p not in V.bad_semistable_primes or p not in W.bad_semistable_primes)): raise NotImplementedError( "Currently tensor products of Galois representations are only implemented under some conditions.", "The behaviour at %d is too wild (both factors must be semistable)." % p) # check for the possibily of getting poles if V.weight == W.weight and V.conductor == W.conductor: Vans = V.algebraic_coefficients(50) Wans = W.algebraic_coefficients(50) CC = ComplexField() if ((Vans[2] in ZZ and Wans[2] in ZZ and all(Vans[n] == Wans[n] for n in range(1, 50))) or all(CC(Vans[n]) == CC(Wans[n]) for n in range(1, 50))): raise NotImplementedError( "It seems you are asking to tensor a " + "Galois representation with its dual " + "which results in the L-function having " + "a pole. This is not implemented here.") scommon = [ x for x in V.bad_semistable_primes if x in W.bad_semistable_primes ] N = W.conductor**V.dim N *= V.conductor**W.dim for p in bad_primes: n1_tame = V.dim - V.local_euler_factor(p).degree() n2_tame = W.dim - W.local_euler_factor(p).degree() nn = n1_tame * n2_tame N = N // p**nn if p in scommon: # both are degree 1 in this case N = N // p self.conductor = N h1 = selberg_to_hodge(V.motivic_weight, V.mu_fe, V.nu_fe) h2 = selberg_to_hodge(W.motivic_weight, W.mu_fe, W.nu_fe) h = tensor_hodge(h1, h2) w, m, n = hodge_to_selberg(h) self.mu_fe = m self.nu_fe = n _, self.gammaV = gamma_factors(h) # this is used in getting the Dirichlet coefficients. self.bad_primes_info = [] for p in bad_primes: # we have to check if this works in all bad cases ! f1 = V.local_euler_factor(p) f2 = W.local_euler_factor(p) # might be dodgy if f1 or f2 is an approx to the Euler factor if p in scommon: E = tensor_local_factors(f1, f2, V.dim * W.dim) T = f1.parent().gens()[0] # right answer is E(T)*E(pT) self.bad_primes_info.append( [p, E * E(p * T), 1 - T] ) #bad_primes_info.append() with 1-T as the second argument is equivalent to taking the first argument as the results (it does a convolution, as in the next line) else: self.bad_primes_info.append([p, f1, f2]) CC = ComplexField() I = CC.gens()[0] self.sign = I**root_number_at_oo(h) self.sign /= I**(root_number_at_oo(h1) * V.dim) self.sign /= I**(root_number_at_oo(h2) * W.dim) self.sign *= V.sign**W.dim self.sign *= W.sign**V.dim for p in bad_primes: if p not in V.bad_semistable_primes or p not in V.bad_semistable_primes: f1 = V.local_euler_factor(p) f2 = W.local_euler_factor(p) det1 = f1.leading_coefficient() * (-1)**f1.degree() det2 = f2.leading_coefficient() * (-1)**f2.degree() n1_tame = V.dim - f1.degree() n2_tame = W.dim - f2.degree() n1_wild = ZZ(V.conductor).valuation(p) - n1_tame n2_wild = ZZ(W.conductor).valuation(p) - n2_tame # additionally, we would need to correct this by # replacing det1 by chi1(p) if p is semistable for V # however for all the possible input this currently does # not affect the sign if p in V.bad_semistable_primes: chi1p = 1 # here else: chi1p = det1 if p in W.bad_semistable_primes: chi2p = 1 # here else: chi2p = det2 corr = chi1p**n2_wild corr *= det1**n2_tame corr *= chi2p**n1_wild corr *= det2**n1_tame corr *= (-1)**(n1_tame * n2_tame) self.sign *= corr / corr.abs() #self.primitive = False self.set_dokchitser_Lfunction() # maybe we should change this to take as many coefficients as implemented # in other Lfunctions self.set_number_of_coefficients() someans = self.algebraic_coefficients(50) # why not. if all(x in ZZ for x in someans): self.selfdual = True else: CC = ComplexField() self.selfdual = all(CC(an).imag().abs() < 0.0001 for an in someans) self.coefficient_type = max(V.coefficient_type, W.coefficient_type) self.coefficient_period = ZZ(V.coefficient_period).lcm( W.coefficient_period) self.ld.gp().quit()
def init_tensor_product(self, V, W): """ We are given two Galois representations and we will return their tensor product. """ self.original_object = V.original_object + W.original_object self.object_type = "tensorproduct" self.V1 = V self.V2 = W self.dim = V.dim * W.dim self.motivic_weight = V.motivic_weight + W.motivic_weight self.langlands = False # status 2014 :) self.besancon_bound = min(V.besancon_bound, W.besancon_bound) bad2 = ZZ(W.conductor).prime_factors() bad_primes = [x for x in ZZ(V.conductor).prime_factors() if x in bad2] for p in bad_primes: if ( p not in V.bad_semistable_primes and p not in W.bad_semistable_primes) : # this condition above only applies to the current type of objects # for general reps we would have to test the lines below # to be certain that the formulae are correct. #if ((p not in V.bad_semistable_primes or p not in W.bad_pot_good) and #(p not in W.bad_semistable_primes or p not in V.bad_pot_good) and #(p not in V.bad_semistable_primes or p not in W.bad_semistable_primes)): raise NotImplementedError("Currently tensor products of Galois representations are only implemented under some conditions.", "The behaviour at %d is too wild (both factors must be semistable)." % p) # check for the possibily of getting poles if V.weight == W.weight and V.conductor == W.conductor : Vans = V.algebraic_coefficients(50) Wans = W.algebraic_coefficients(50) CC = ComplexField() if ((Vans[2] in ZZ and Wans[2] in ZZ and all(Vans[n] == Wans[n] for n in range(1,50) ) ) or all( CC(Vans[n]) == CC(Wans[n]) for n in range(1,50) ) ): raise NotImplementedError("It seems you are asking to tensor a "+ "Galois representation with its dual " + "which results in the L-function having "+ "a pole. This is not implemented here.") scommon = [x for x in V.bad_semistable_primes if x in W.bad_semistable_primes] N = W.conductor ** V.dim N *= V.conductor ** W.dim for p in bad_primes: n1_tame = V.dim - V.local_euler_factor(p).degree() n2_tame = W.dim - W.local_euler_factor(p).degree() nn = n1_tame * n2_tame N = N // p ** nn if p in scommon: # both are degree 1 in this case N = N // p self.conductor = N h1 = selberg_to_hodge(V.motivic_weight,V.mu_fe,V.nu_fe) h2 = selberg_to_hodge(W.motivic_weight,W.mu_fe,W.nu_fe) h = tensor_hodge(h1, h2) w,m,n = hodge_to_selberg(h) self.mu_fe = m self.nu_fe = n _, self.gammaV = gamma_factors(h) # this is used in getting the Dirichlet coefficients. self.bad_primes_info = [] for p in bad_primes: # we have to check if this works in all bad cases ! f1 = V.local_euler_factor(p) f2 = W.local_euler_factor(p) # might be dodgy if f1 or f2 is an approx to the Euler factor if p in scommon: E = tensor_local_factors(f1,f2,V.dim*W.dim) T = f1.parent().gens()[0] # right answer is E(T)*E(pT) self.bad_primes_info.append([p,E*E(p*T),1-T]) #bad_primes_info.append() with 1-T as the second argument is equivalent to taking the first argument as the results (it does a convolution, as in the next line) else: self.bad_primes_info.append([p,f1,f2]) CC = ComplexField() I = CC.gens()[0] self.sign = I ** root_number_at_oo(h) self.sign /= I ** (root_number_at_oo(h1) * V.dim) self.sign /= I ** (root_number_at_oo(h2) * W.dim) self.sign *= V.sign ** W.dim self.sign *= W.sign ** V.dim for p in bad_primes: if p not in V.bad_semistable_primes or p not in V.bad_semistable_primes: f1 = V.local_euler_factor(p) f2 = W.local_euler_factor(p) det1 = f1.leading_coefficient() * (-1) ** f1.degree() det2 = f2.leading_coefficient() * (-1) ** f2.degree() n1_tame = V.dim - f1.degree() n2_tame = W.dim - f2.degree() n1_wild = ZZ(V.conductor).valuation(p) - n1_tame n2_wild = ZZ(W.conductor).valuation(p) - n2_tame # additionally, we would need to correct this by # replacing det1 by chi1(p) if p is semistable for V # however for all the possible input this currently does # not affect the sign if p in V.bad_semistable_primes: chi1p = 1 # here else: chi1p = det1 if p in W.bad_semistable_primes: chi2p = 1 # here else: chi2p = det2 corr = chi1p ** n2_wild corr *= det1 ** n2_tame corr *= chi2p ** n1_wild corr *= det2 ** n1_tame corr *= (-1) ** (n1_tame * n2_tame) self.sign *= corr/corr.abs() #self.primitive = False self.set_dokchitser_Lfunction() # maybe we should change this to take as many coefficients as implemented # in other Lfunctions self.set_number_of_coefficients() someans = self.algebraic_coefficients(50) # why not. if all( x in ZZ for x in someans): self.selfdual = True else: CC = ComplexField() self.selfdual = all( CC(an).imag().abs() < 0.0001 for an in someans) self.coefficient_type = max(V.coefficient_type, W.coefficient_type) self.coefficient_period = ZZ(V.coefficient_period).lcm(W.coefficient_period) self.ld.gp().quit()