def genus_symbol_string_to_dict(s): sl = s.split('.') d = dict() for s in sl: L1 = s.split('^') if len(L1) > 2: raise ValueError() elif len(L1) == 1: nn = 1 else: nn = L1[1] n = Integer(nn) L1 = L1[0].split("_") q = Integer(L1[0]) if len(L1) > 2: # more than one _ in item raise ValueError elif len(L1) == 2: if Integer(L1[1]) in range(8): t = Integer(L1[1]) else: raise ValueError, "Type given, which ist not in 0..7: %s" % ( L1[1]) else: t = None if not (n != 0 and q != 1 and q.is_prime_power() and (None == t or (is_even(q) and t % 2 == n % 2)) and (not (None == t and is_even(q)) or 0 == n % 2)): raise ValueError, "{0} is not a valid signature!".format(s) p = q.prime_factors()[0] r = q.factor()[0][1] eps = sign(n) n = abs(n) if not d.has_key(p): d[p] = list() if p == 2: if t == None: print "eps = ", eps if not is_even(n): raise ValueError() d[p].append([ r, n, 3 * (-1)**(Integer(n - 2) / 2) % 8 if eps == -1 else (-1)**(Integer(n)), t, 4 if eps == -1 else 0 ]) print d else: if t.kronecker(2) == eps: det = t % 8 else: if eps == -1: det = 3 else: det = 1 d[p].append([r, n, det, 1, t % 8]) else: d[p].append([r, n, eps]) return d
def genus_symbol_string_to_dict(s): sl = s.split('.') d = dict() for s in sl: L1 = s.split('^') if len(L1)>2: raise ValueError() elif len(L1) == 1: nn = 1 else: nn = L1[1] n = Integer(nn) L1= L1[0].split("_") q = Integer(L1[0]) if len(L1) > 2: # more than one _ in item raise ValueError elif len(L1) == 2: if Integer(L1[1]) in range(8): t = Integer(L1[1]) else: raise ValueError, "Type given, which ist not in 0..7: %s"%(L1[1]) else: t = None if not (n != 0 and q != 1 and q.is_prime_power() and ( None == t or (is_even(q) and t%2 == n%2)) and ( not (None == t and is_even(q)) or 0 == n%2) ): raise ValueError,"{0} is not a valid signature!".format(s) p = q.prime_factors()[0] r = q.factor()[0][1] eps = sign(n) n = abs(n) if not d.has_key(p): d[p]=list() if p==2: if t == None: print "eps = ", eps if not is_even(n): raise ValueError() d[p].append([r, n, 3*(-1)**(Integer(n-2)/2) % 8 if eps == -1 else (-1)**(Integer(n)),t,4 if eps == -1 else 0]) print d else: if t.kronecker(2) == eps: det = t % 8 else: if eps == -1: det = 3 else: det = 1 d[p].append([r,n,det,1,t % 8]) else: d[p].append([r,n,eps]) return d
def check_character_values(self, rec, verbose=False): """ The x's listed in values and values_gens should be coprime to the modulus N in the label. For x's that appear in both values and values_gens, the value should be the same. """ # TIME about 3000s for full table N = Integer(rec['modulus']) v2, u2 = N.val_unit(2) if v2 == 1: # Z/2 doesn't contribute generators, but 2 divides N adjust2 = -1 elif v2 >= 3: # Z/8 and above requires two generators adjust2 = 1 else: adjust2 = 0 if N == 1: # The character stores a value in the case N=1 ngens = 1 else: ngens = len(N.factor()) + adjust2 vals = rec['values'] val_gens = rec['values_gens'] val_gens_dict = dict(val_gens) if len(vals) != min(12, euler_phi(N)) or len(val_gens) != ngens: if verbose: print "Length failure", len(vals), euler_phi(N), len( val_gens), ngens return False if N > 2 and (vals[0][0] != N - 1 or vals[1][0] != 1 or vals[1][1] != 0 or vals[0][1] not in [0, rec['order'] // 2]): if verbose: print "Initial value failure", N, rec['order'], vals[:2] return False if any(N.gcd(g) > 1 for g, gval in val_gens + vals): if verbose: print "gcd failure", [ g for g, gval in val_gens + vals if N.gcd(g) > 1 ] return False for g, val in vals: if g in val_gens_dict and val != val_gens_dict[g]: if verbose: print "Mismatch failure", g, val, val_gens_dict[g] return False return True
def check_character_values(self, rec, verbose=False): """ The x's listed in values and values_gens should be coprime to the modulus N in the label. For x's that appear in both values and values_gens, the value should be the same. """ # TIME about 3000s for full table N = Integer(rec['modulus']) v2, u2 = N.val_unit(2) if v2 == 1: # Z/2 doesn't contribute generators, but 2 divides N adjust2 = -1 elif v2 >= 3: # Z/8 and above requires two generators adjust2 = 1 else: adjust2 = 0 if N == 1: # The character stores a value in the case N=1 ngens = 1 else: ngens = len(N.factor()) + adjust2 vals = rec['values'] val_gens = rec['values_gens'] val_gens_dict = dict(val_gens) if len(vals) != min(12, euler_phi(N)) or len(val_gens) != ngens: if verbose: print "Length failure", len(vals), euler_phi(N), len(val_gens), ngens return False if N > 2 and (vals[0][0] != N-1 or vals[1][0] != 1 or vals[1][1] != 0 or vals[0][1] not in [0, rec['order']//2]): if verbose: print "Initial value failure", N, rec['order'], vals[:2] return False if any(N.gcd(g) > 1 for g, gval in val_gens+vals): if verbose: print "gcd failure", [g for g, gval in val_gens+vals if N.gcd(g) > 1] return False for g, val in vals: if g in val_gens_dict and val != val_gens_dict[g]: if verbose: print "Mismatch failure", g, val, val_gens_dict[g] return False return True
class ConreyCharacter: """ tiny implementation on Conrey index only """ def __init__(self, modulus, number): assert gcd(modulus, number) == 1 self.modulus = Integer(modulus) self.number = Integer(number) @property def texname(self): from lmfdb.characters.web_character import WebDirichlet return WebDirichlet.char2tex(self.modulus, self.number) @cached_method def modfactor(self): return self.modulus.factor() @cached_method def conductor(self): cond = Integer(1) number = self.number for p, e in self.modfactor(): mp = Mod(number, p**e) if mp == 1: continue if p == 2: cond = 4 if number % 4 == 3: mp = -mp else: cond *= p mp = mp**(p - 1) while mp != 1: cond *= p mp = mp**p return cond def is_primitive(self): return self.conductor() == self.modulus @cached_method def parity(self): number = self.number par = 0 for p, e in self.modfactor(): if p == 2: if number % 4 == 3: par = 1 - par else: phi2 = (p - 1) / Integer(2) * p**(e - 1) if Mod(number, p**e)**phi2 != 1: par = 1 - par return par def is_odd(self): return self.parity() == 1 def is_even(self): return self.parity() == 0 @cached_method def multiplicative_order(self): return Mod(self.number, self.modulus).multiplicative_order() @property def order(self): return self.multiplicative_order() @cached_method def kronecker_symbol(self): c = self.conductor() p = self.parity() return kronecker_symbol(symbol_numerator(c, p))
class ConreyCharacter: """ tiny implementation on Conrey index only """ def __init__(self, modulus, number): assert gcd(modulus, number)==1 self.modulus = Integer(modulus) self.number = Integer(number) @property def texname(self): return WebDirichlet.char2tex(self.modulus, self.number) @cached_method def modfactor(self): return self.modulus.factor() @cached_method def conductor(self): cond = Integer(1); number = self.number for p,e in self.modfactor(): mp = Mod(number, p**e); if mp == 1: continue if p == 2: cond = 4 if number % 4 == 3: mp = -mp else: cond *= p mp = mp**(p-1) while mp != 1: cond *= p mp = mp**p return cond def is_primitive(self): return self.conductor() == self.modulus @cached_method def parity(self): number = self.number par = 0; for p,e in self.modfactor(): if p == 2: if number % 4 == 3: par = 1 - par else: phi2 = (p-1)/Integer(2) * p **(e-1) if Mod(number, p ** e)**phi2 != 1: par = 1 - par return par def is_odd(self): return self.parity() == 1 def is_even(self): return self.parity() == 0 @cached_method def multiplicative_order(self): return Mod(self.number, self.modulus).multiplicative_order() @property def order(self): return self.multiplicative_order() @cached_method def kronecker_symbol(self): c = self.conductor() p = self.parity() return kronecker_symbol(symbol_numerator(c, p))
class ConreyCharacter(object): """ tiny implementation on Conrey index only """ def __init__(self, modulus, number): assert gcd(modulus, number) == 1 self.modulus = Integer(modulus) self.number = Integer(number) self.G = Pari("znstar({},1)".format(modulus)) self.chi_pari = pari("znconreylog(%s,%d)" % (self.G, self.number)) self.chi_0 = None self.indlabel = None @property def texname(self): from lmfdb.characters.web_character import WebDirichlet return WebDirichlet.char2tex(self.modulus, self.number) @cached_method def modfactor(self): return self.modulus.factor() @cached_method def conductor(self): B = pari("znconreyconductor(%s,%s,&chi0)" % (self.G, self.chi_pari)) if B.type() == 't_INT': # means chi is primitive self.chi_0 = self.chi_pari self.indlabel = self.number return int(B) else: self.chi_0 = pari("chi0") G_0 = Pari("znstar({},1)".format(B)) self.indlabel = int(pari("znconreyexp(%s,%s)" % (G_0, self.chi_0))) return int(B[0]) def is_primitive(self): return self.conductor() == self.modulus @cached_method def parity(self): number = self.number par = 0 for p, e in self.modfactor(): if p == 2: if number % 4 == 3: par = 1 - par else: phi2 = (p - 1) / Integer(2) * p**(e - 1) if Mod(number, p**e)**phi2 != 1: par = 1 - par return par def is_odd(self): return self.parity() == 1 def is_even(self): return self.parity() == 0 @cached_method def multiplicative_order(self): return Mod(self.number, self.modulus).multiplicative_order() @property def order(self): return self.multiplicative_order() @cached_method def kronecker_symbol(self): c = self.conductor() p = self.parity() return kronecker_symbol(symbol_numerator(c, p)) def conreyangle(self, x): return Rational( pari("chareval(%s,znconreylog(%s,%d),%d)" % (self.G, self.G, self.number, x))) def gauss_sum_numerical(self, a): # There seems to be a bug in pari when a is a multiple of the modulus, # so we deal with that separately if self.modulus.divides(a): if self.conductor() == 1: return euler_phi(self.modulus) else: return Integer(0) else: return pari("znchargauss(%s,%s,a=%d)" % (self.G, self.chi_pari, a)) def sage_zeta_order(self, order): return 1 if self.modulus <= 2 else lcm(2, order) 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))