def codeinit(self): self.exnum = self.galorbnums[0] self.exchi = ConreyCharacter(self.modulus, self.exnum) values_gens = db.char_dir_values.lookup( "{}.{}".format(self.modulus, self.exnum), projection='values_gens' ) vals = [int(v) for g, v in values_gens] sage_zeta_order = self.exchi.sage_zeta_order(self.order) self._genvalues_for_code = get_sage_genvalues(self.modulus, self.order, vals, sage_zeta_order) return { 'sage': [ 'from sage.modular.dirichlet import DirichletCharacter', 'H = DirichletGroup({}, base_ring=CyclotomicField({}))'.format( self.modulus, sage_zeta_order), 'M = H._module', 'chi = DirichletCharacter(H, M([{}]))'.format( ','.join(str(val) for val in self._genvalues_for_code) ), 'chi.galois_orbit()' ], 'pari': [ '[g,chi] = znchar(Mod(%i,%i))' % (self.exnum, self.modulus), 'order = charorder(g,chi)', '[ charpow(g,chi, k % order) | k <-[1..order-1], gcd(k,order)==1 ]' ] }
def nextprimchar(m, n): if m < 3: return 3, 2 while 1: n += 1 if n >= m: m, n = m + 1, 2 if gcd(m, n) != 1: continue # we have a character, test if it is primitive chi = ConreyCharacter(m,n) if chi.is_primitive(): return m, n
def prevprimchar(m, n): if m <= 3: return 1, 1 while True: n -= 1 if n <= 1: # (m,1) is never primitive for m>1 m, n = m - 1, m - 1 if m <= 2: return 1, 1 if gcd(m, n) != 1: continue # we have a character, test if it is primitive chi = ConreyCharacter(m,n) if chi.is_primitive(): return m, n
def __init__(self, **kwargs): self.type = "Dirichlet" self.isorbit = True self.modulus = kwargs.get('modulus', None) if self.modulus: self.modulus = int(self.modulus) self.modlabel = self.modulus self.number = kwargs.get('number', None) if self.number: self.number = int(self.number) self.numlabel = self.number if self.modulus: # Needed for Gauss sums, etc self.H = PariConreyGroup(self.modulus) if self.number: self.chi = ConreyCharacter(self.modulus, self.number) self.codelangs = ('pari', 'sage') self.orbit_label = kwargs.get('orbit_label', None) # this is what the user inserted, so might be banana self.label = "{}.{}".format(self.modulus, self.orbit_label) self.orbit_data = self.get_orbit_data(self.orbit_label) # this is the meat self.maxrows = 30 self.rowtruncate = False self._set_galoisorbit(self.orbit_data) self.maxcols = 10 self._contents = None self._set_groupelts()
def check_ap2_slow(rec): # Check a_{p^2} = a_p^2 - chi(p) for primes up to 31 ls = rec['lfunction_label'].split('.') level, weight, chi = map(int, [ls[0], ls[1], ls[-2]]) char = ConreyCharacter(level, chi) Z = rec['an_normalized[0:1000]'] for p in prime_range(31 + 1): if level % p != 0: # a_{p^2} = a_p^2 - chi(p) charval = CC(2 * char.conreyangle(int(p)) * CC.pi() * CC.gens()[0]).exp() else: charval = 0 if (CC(*Z[p**2 - 1]) - (CC(*Z[p - 1])**2 - charval)).abs() > 1e-11: return False return True
def get_dirchar(char_mod, char_num, char_order): """Helper method to compute Dirichlet Character on the fly""" char_values_data = db.char_dir_values.lookup("{}.{}".format( char_mod, char_num)) char_valuepairs = char_values_data['values_gens'] char_genvalues = [int(v) for g, v in char_valuepairs] return ConreyCharacter(char_mod, char_num).sage_character(char_order, char_genvalues)
def __init__(self, **kwargs): self.type = "Dirichlet" self.modulus = kwargs.get('modulus', None) if self.modulus: self.modulus = int(self.modulus) self.modlabel = self.modulus self.number = kwargs.get('number', None) if self.number: self.number = int(self.number) self.numlabel = self.number if self.modulus: # Needed for Gauss sums, etc self.H = PariConreyGroup(self.modulus) if self.number: self.chi = ConreyCharacter(self.modulus, self.number) self.maxcols = 30 self.codelangs = ('pari', 'sage') self._compute()
def check_ap2_slow(self, rec, verbose=False): """ Check a_{p^2} = a_p^2 - chi(p) for primes up to 31 """ ls = rec['label'].split('.') level, weight, chi = map(int, [ls[0], ls[1], ls[-2]]) char = ConreyCharacter(level, chi) Z = rec['an_normalized'] for p in prime_range(31+1): if level % p != 0: # a_{p^2} = a_p^2 - chi(p) charval = CC(2*char.conreyangle(int(p)) * CC.pi()*CC.gens()[0]).exp() else: charval = 0 if (CC(*Z[p**2 - 1]) - (CC(*Z[p-1])**2 - charval)).abs() > 1e-13: if verbose: print("ap2 failure", p, CC(*Z[p**2 - 1]), CC(*Z[p-1])**2 - charval) return False return True
def jacobi_sum(self, val): mod, num = self.modulus, self.number try: val = int(val) except ValueError: raise Warning ("n must be a positive integer coprime to the modulus {} and no greater than it".format(mod)) if gcd(mod, val) > 1: raise Warning ("n must be coprime to the modulus : %s"%mod) if val > mod: raise Warning ("n must be less than the modulus : %s"%mod) if val < 0: raise Warning ("n must be positive") chi_values_data = db.char_dir_values.lookup( "{}.{}".format(mod, num) ) chi_valuepairs = chi_values_data['values_gens'] chi_genvalues = [int(v) for g, v in chi_valuepairs] chi = self.chi.sage_character(self.order, chi_genvalues) psi = ConreyCharacter(self.modulus, val) psi_values_data = db.char_dir_values.lookup( "{}.{}".format(self.modulus, val) ) psi_valuepairs = psi_values_data['values_gens'] psi_genvalues = [int(v) for g, v in psi_valuepairs] psi = psi.sage_character(self.order, psi_genvalues) jacobi_sum = chi.jacobi_sum(psi) chitex = self.char2tex(mod, num, tag=False) psitex = self.char2tex(mod, val, tag=False) Gtex = r'\Z/%s\Z' % mod chitexr = self.char2tex(mod, num, 'r', tag=False) psitex1r = self.char2tex(mod, val, '1-r', tag=False) deftex = r'\sum_{r\in %s} %s %s'%(Gtex,chitexr,psitex1r) return r"\( \displaystyle J(%s,%s) = %s = %s \)" % (chitex, psitex, deftex, latex(jacobi_sum))
def check_order_parity(self, rec, verbose=False): """ check order and parity by constructing a Conrey character in Sage (use the first index in galois_orbit) """ # TIME about 30000s for full table char = ConreyCharacter(rec['modulus'], rec['galois_orbit'][0]) parity = 1 if char.is_even() else -1 success = (parity == rec['parity'] and char.conductor() == rec['conductor'] and char.multiplicative_order() == rec['order']) if verbose and not success: print("Order-parity failure", parity, rec['parity'], char.conductor(), rec['conductor'], char.multiplicative_order(), rec['order']) return success
def get_character_modulus(a, b, limit=7): """ this function is also used by lfunctions/LfunctionPlot.py """ headers = list(range(1, limit)) headers.append("more") entries = {} rows = list(range(a, b + 1)) for row in rows: if row != 1: G = Integers(row).list_of_elements_of_multiplicative_group() else: G = [1] for chi_n in G: chi = ConreyCharacter(row, chi_n) multorder = chi.multiplicative_order() if multorder <= limit: el = chi col = multorder entry = entries.get((row, col), []) entry.append(el) entries[(row, col)] = entry entries2 = {} out = lambda chi: (chi.number, chi.is_primitive(), chi.multiplicative_order(), chi.is_even()) for k, v in entries.items(): l = [] v = sorted(v, key=lambda x: x.number) while v: e1 = v.pop(0) e1_num = e1.number inv_num = 1 if e1_num == 1 else e1_num.inverse_mod(e1.modulus) inv = ConreyCharacter(e1.modulus, inv_num) if e1_num == inv_num: l.append((out(e1), )) else: l.append((out(e1), out(inv))) v = [ x for x in v if (x.modulus, x.number) != (inv.modulus, inv.number) ] if k[1] == "more": l = sorted(l, key=lambda e: e[0][2]) entries2[k] = l cols = headers return headers, entries2, rows, cols
class WebSmallDirichletCharacter(WebChar, WebDirichlet): """ Heritage: WebChar -> __init__() WebDirichlet -> _compute() """ def _compute(self): self.modulus = int(self.modlabel) self.number = int(self.numlabel) self.chi = ConreyCharacter(self.modulus, self.number) self.codelangs = ('pari', 'sage') @lazy_attribute def conductor(self): return self.chi.conductor() @lazy_attribute def indlabel(self): if self.chi.indlabel is not None: return self.chi.indlabel else: # Calling conductor computes the indlabel self.chi.conductor() return self.chi.indlabel @lazy_attribute def codeinit(self): return { 'sage': [ 'H = DirichletGroup(%i)'%(self.modulus), 'chi = H[%i]'%(self.number) ], 'pari': '[g,chi] = znchar(Mod(%i,%i))'%(self.number,self.modulus), } @lazy_attribute def title(self): return r"Dirichlet character %s" % (self.texname) @lazy_attribute def texname(self): return self.char2tex(self.modulus, self.number) @lazy_attribute def codeisprimitive(self): return { 'sage': 'chi.is_primitive()', 'pari': '#znconreyconductor(g,chi)==1 \\\\ if not primitive returns [cond,factorization]' } @lazy_attribute def codecond(self): return { 'sage': 'chi.conductor()', 'pari': 'znconreyconductor(g,chi)' } @lazy_attribute def parity(self): return (parity_string(-1),parity_string(1))[self.chi.is_even()] @lazy_attribute def codeparity(self): return { 'sage': 'chi.is_odd()', 'pari': 'zncharisodd(g,chi)' } def symbol_numerator(self): """ chi is equal to a kronecker symbol if and only if it is real """ if self.order != 2: return None return symbol_numerator(self.conductor, self.chi.is_odd()) @lazy_attribute def symbol(self): return kronecker_symbol(self.symbol_numerator()) @lazy_attribute def codesymbol(self): m = self.symbol_numerator() if m: return { 'sage': 'kronecker_character(%i)'%m, 'pari': 'znchartokronecker(g,chi)' } return None @lazy_attribute def codegaloisorbit(self): return { 'sage': ['chi.galois_orbit()'], 'pari': [ 'order = charorder(g,chi)', '[ charpow(g,chi, k % order) | k <-[1..order-1], gcd(k,order)==1 ]' ] }
def set_info_for_gamma1(level,weight,weight2=None): dimension_table_name = WebModFormSpace._dimension_table_name if weight != None and weight2>weight: w1 = weight; w2 = weight2 else: w1 = weight; w2 = weight table = {'galois_orbit':{},'galois_orbits_reps':{},'cells':{}} table['weights']=range(w1,w2+1) emf_logger.debug("dimension table name={0}".format(dimension_table_name)) db_dim = getDBConnection()['modularforms2'][dimension_table_name] s = {'level':int(level),'weight':{"$lt":int(w2+1),"$gt":int(w1-1)},'cchi':{"$exists":True}} q = db_dim.find(s).sort([('cchi',int(1)),('weight',int(1))]) if q.count() == 0: emf_logger.debug("No spaces in the database!") flash('The database does not currently contain any spaces matching these parameters. Please try again!') return None #'error':'The database does not currently contain any spaces matching these parameters!'} else: table['maxGalCount']=1 for r in q: xi = r['cchi'] orbit = r['character_orbit'] k = r['weight'] ## This is probably still quicker if it is in the database parity = r.get('character_parity','n/a') if parity == 'n/a': chi = ConreyCharacter(level,xi) if chi.is_odd(): parity = -1 elif chi.is_even(): parity = 1 else: emf_logger.critical("Could not determine the parity of ConreyCharacter({0},{1})".format(xi,level)) trivial_trivially = "" if parity != 'n/a': if k % 2 == (1 + parity)/2: # is space empty because of parity? trivial_trivially = "yes" else: trivial_trivially = "" if parity == 1: parity = 'even' elif parity == -1: parity = 'odd' d = r.get('d_newf',"n/a") indb = r.get('in_wdb',0) if d == 0: indb = 1 if indb: url = url_for('emf.render_elliptic_modular_forms', level=level, weight=k, character=xi) else: url = '' if not table['galois_orbits_reps'].has_key(xi): table['galois_orbits_reps'][xi]={ 'head' : "\(\chi_{{{0}}}({1},\cdot) \)".format(level,xi), # yes, {{{ is required 'chi': "{0}".format(xi), 'url': url_for('characters.render_Dirichletwebpage', modulus=level, number=xi), 'parity':parity} table['galois_orbit'][xi]= [ { #'head' : "\(\chi_{{{0}}}({1},\cdot) \)".format(level,xci), # yes, {{{ is required ## 'head' : "\(S_{{{0}}}({1},\chi({2}, \cdot) ) \)".format(weight,level,xci), # yes, {{{ is required ## 'head' : "\(S_{{{0}}}(\chi({1}, \cdot) ) \)".format(weight,xci), # yes, {{{ is required 'head' : r"\(S_{{{0}}}(\chi_{{{1}}}({2}, \cdot)) \)".format(weight,level,xci), # yes, {{{ is required # 'head' : "\({0}\)".format(xci), 'chi': "{0}".format(xci), # 'url': url_for('characters.render_Dirichletwebpage', modulus=level, number=xci) 'url': url_for('emf.render_elliptic_modular_forms', level=level, weight=k, character=xci) if indb else '' } for xci in orbit] if len(orbit)>table['maxGalCount']: table['maxGalCount']=len(orbit) table['cells'][xi]={} table['cells'][xi][k] ={'N': level, 'k': k, 'chi': xi, 'url': url, 'dim': d, 'trivial_trivially': trivial_trivially,} table['galois_orbits_reps_numbers']=table['galois_orbits_reps'].keys() table['galois_orbits_reps_numbers'].sort() #emf_logger.debug("Table:{0}".format(table)) return table
class WebSmallDirichletCharacter(WebChar, WebDirichlet): """ Heritage: WebChar -> __init__() WebDirichlet -> _compute() """ def _compute(self): self.modulus = int(self.modlabel) self.number = int(self.numlabel) self.chi = ConreyCharacter(self.modulus, self.number) self.credit = '' self.codelangs = ('pari', 'sage') @property def conductor(self): return self.chi.conductor() @property def previous(self): return None @property def next(self): return None @property def genvalues(self): return None @property def indlabel(self): return None def value(self, *args): return None def charsums(self, *args): return False def gauss_sum(self, *args): return None def jacobi_sum(self, *args): return None def kloosterman_sum(self, *args): return None @property def codeinit(self): return { 'sage': [ 'from dirichlet_conrey import DirichletGroup_conrey # requires nonstandard Sage package to be installed', 'H = DirichletGroup_conrey(%i)'%(self.modulus), 'chi = H[%i]'%(self.number) ], 'pari': '[g,chi] = znchar(Mod(%i,%i))'%(self.number,self.modulus), } @property def title(self): return r"Dirichlet Character %s" % (self.texname) @property def texname(self): return self.char2tex(self.modulus, self.number) @property def codeisprimitive(self): return { 'sage': 'chi.is_primitive()', 'pari': '#znconreyconductor(g,chi)==1 \\\\ if not primitive returns [cond,factorization]' } @property def codecond(self): return { 'sage': 'chi.conductor()', 'pari': 'znconreyconductor(g,chi)' } @property def parity(self): return ('Odd', 'Even')[self.chi.is_even()] @property def codeparity(self): return { 'sage': 'chi.is_odd()', 'pari': 'zncharisodd(g,chi)' } @property def galoisorbit(self): order = self.order mod, num = self.modulus, self.number prim = self.isprimitive #beware this **must** be a generator orbit = ( power_mod(num, k, mod) for k in xsrange(1, order) if gcd(k, order) == 1) # use xsrange not xrange return ( self._char_desc(num, prim=prim) for num in orbit ) def symbol_numerator(self): """ chi is equal to a kronecker symbol if and only if it is real """ if self.order != 2: return None return symbol_numerator(self.conductor, self.chi.is_odd()) @property def symbol(self): return kronecker_symbol(self.symbol_numerator()) @property def codesymbol(self): m = self.symbol_numerator() if m: return { 'sage': 'kronecker_character(%i)'%m } return None @property def codegaloisorbit(self): return { 'sage': 'chi.sage_character().galois_orbit()', 'pari': [ 'order = charorder(g,chi)', '[ charpow(g,chi, k % order) | k <-[1..order-1], gcd(k,order)==1 ]' ] }
class WebDBDirichlet(WebDirichlet): """ A base class using data stored in the database. Currently this is all Dirichlet characters with modulus up to 10000. """ def __init__(self, **kwargs): self.type = "Dirichlet" self.modulus = kwargs.get('modulus', None) if self.modulus: self.modulus = int(self.modulus) self.modlabel = self.modulus self.number = kwargs.get('number', None) if self.number: self.number = int(self.number) self.numlabel = self.number if self.modulus: # Needed for Gauss sums, etc self.H = PariConreyGroup(self.modulus) if self.number: self.chi = ConreyCharacter(self.modulus, self.number) self.maxcols = 30 self.codelangs = ('pari', 'sage') self._compute() @lazy_attribute def texname(self): return self.char2tex(self.modulus, self.number) def _compute(self): self._populate_from_db() def _populate_from_db(self): values_data = db.char_dir_values.lookup( "{}.{}".format(self.modulus, self.number) ) self.orbit_index = int(values_data['orbit_label'].partition('.')[-1]) # The -1 in the line below is because labels index at 1, while # the Cremona letter code indexes at 0 self.orbit_label = cremona_letter_code(self.orbit_index - 1) self.order = int(values_data['order']) self.indlabel = int(values_data['prim_label'].partition('.')[-1]) self._set_values_and_groupelts(values_data) self._set_generators_and_genvalues(values_data) orbit_data = db.char_dir_orbits.lucky( {'modulus': self.modulus, 'orbit_index': self.orbit_index} ) self.conductor = int(orbit_data['conductor']) self._set_isprimitive(orbit_data) self._set_isminimal(orbit_data) self._set_parity(orbit_data) self._set_galoisorbit(orbit_data) self._set_kernel_field_poly(orbit_data) def _set_generators_and_genvalues(self, values_data): """ The char_dir_values db collection contains `values_gens`, which contains the generators for the unit group U(modulus) and the values of the character on those generators. """ valuepairs = values_data['values_gens'] if self.modulus == 1: self.generators = r"\(1\)" self.genvalues = r"\(1\)" else: gens = [int(g) for g, v in valuepairs] vals = [int(v) for g, v in valuepairs] self._genvalues_for_code = get_sage_genvalues(self.modulus, self.order, vals, self.chi.sage_zeta_order(self.order)) self.generators = self.textuple([str(g) for g in gens]) self.genvalues = self.textuple([self._tex_value(v) for v in vals]) def _set_values_and_groupelts(self, values_data): """ The char_dir_values db collection contains `values`, which contains several group elements and the corresponding values. """ valuepairs = values_data['values'] if self.modulus == 1: self.groupelts = [1] self.values = [r"\(1\)"] else: self.groupelts = [int(g) for g, v in valuepairs] self.groupelts[0] = -1 raw_values = [int(v) for g, v in valuepairs] self.values = [ self._tex_value(v, self.order, texify=True) for v in raw_values ] def _tex_value(self, numer, denom=None, texify=False): r""" Formats the number e**(2 pi i * numer / denom), detecting if this simplifies to +- 1 or +- i. Surround the output i MathJax `\(..\)` tags if `texify` is True. `denom` defaults to self.order. """ if not denom: denom = self.order g = gcd(numer, denom) if g > 1: numer = numer // g denom = denom // g # Reduce mod the denominator numer = (numer % denom) if denom == 1: ret = '1' elif (numer % denom) == 0: ret = '1' elif numer == 1 and denom == 2: ret = '-1' elif numer == 1 and denom == 4: ret = 'i' elif numer == 3 and denom == 4: ret = '-i' else: ret = r"e\left(\frac{%s}{%s}\right)" % (numer, denom) if texify: return r"\({}\)".format(ret) else: return ret def _set_isprimitive(self, orbit_data): self.isprimitive = bool_string(orbit_data['is_primitive']) def _set_isminimal(self, orbit_data): self.isminimal = bool_string(orbit_data['is_minimal']) def _set_parity(self, orbit_data): self.parity = parity_string(int(orbit_data['parity'])) def _set_galoisorbit(self, orbit_data): if self.modulus == 1: self.galoisorbit = [self._char_desc(1, mod=1,prim=True)] return upper_limit = min(200, self.order + 1) orbit = orbit_data['galois_orbit'][:upper_limit] self.galoisorbit = list( self._char_desc(num, prim=self.isprimitive) for num in orbit ) def _set_kernel_field_poly(self, orbit_data): if 'kernel_field_poly' in orbit_data.keys(): self.kernel_field_poly = orbit_data['kernel_field_poly'] else: self.kernel_field_poly = None
def _compute(self): self.modulus = int(self.modlabel) self.number = int(self.numlabel) self.chi = ConreyCharacter(self.modulus, self.number) self.credit = '' self.codelangs = ('pari', 'sage')
def set_info_for_gamma1(level, weight, weight2=None): dimension_table_name = WebModFormSpace._dimension_table_name if weight != None and weight2 > weight: w1 = weight w2 = weight2 else: w1 = weight w2 = weight table = {'galois_orbit': {}, 'galois_orbits_reps': {}, 'cells': {}} table['weights'] = range(w1, w2 + 1) emf_logger.debug("dimension table name={0}".format(dimension_table_name)) db_dim = getDBConnection()['modularforms2'][dimension_table_name] s = { 'level': int(level), 'weight': { "$lt": int(w2 + 1), "$gt": int(w1 - 1) }, 'cchi': { "$exists": True } } q = db_dim.find(s).sort([('cchi', int(1)), ('weight', int(1))]) if q.count() == 0: emf_logger.debug("No spaces in the database!") flash( 'The database does not currently contain any spaces matching these parameters. Please try again!' ) return None #'error':'The database does not currently contain any spaces matching these parameters!'} else: table['maxGalCount'] = 1 for r in q: xi = r['cchi'] orbit = r['character_orbit'] k = r['weight'] ## This is probably still quicker if it is in the database parity = r.get('character_parity', 'n/a') if parity == 'n/a': chi = ConreyCharacter(level, xi) if chi.is_odd(): parity = -1 elif chi.is_even(): parity = 1 else: emf_logger.critical( "Could not determine the parity of ConreyCharacter({0},{1})" .format(xi, level)) trivial_trivially = "" if parity != 'n/a': if k % 2 == (1 + parity) / 2: # is space empty because of parity? trivial_trivially = "yes" else: trivial_trivially = "" if parity == 1: parity = 'even' elif parity == -1: parity = 'odd' d = r.get('d_newf', "n/a") indb = r.get('in_wdb', 0) if d == 0: indb = 1 if indb: url = url_for('emf.render_elliptic_modular_forms', level=level, weight=k, character=xi) else: url = '' if not table['galois_orbits_reps'].has_key(xi): table['galois_orbits_reps'][xi] = { 'head': "\(\chi_{{{0}}}({1},\cdot) \)".format( level, xi), # yes, {{{ is required 'chi': "{0}".format(xi), 'url': url_for('characters.render_Dirichletwebpage', modulus=level, number=xi), 'parity': parity } table['galois_orbit'][xi] = [ { #'head' : "\(\chi_{{{0}}}({1},\cdot) \)".format(level,xci), # yes, {{{ is required ## 'head' : "\(S_{{{0}}}({1},\chi({2}, \cdot) ) \)".format(weight,level,xci), # yes, {{{ is required ## 'head' : "\(S_{{{0}}}(\chi({1}, \cdot) ) \)".format(weight,xci), # yes, {{{ is required 'head': r"\(S_{{{0}}}(\chi_{{{1}}}({2}, \cdot)) \)".format( weight, level, xci), # yes, {{{ is required # 'head' : "\({0}\)".format(xci), 'chi': "{0}".format(xci), # 'url': url_for('characters.render_Dirichletwebpage', modulus=level, number=xci) 'url': url_for('emf.render_elliptic_modular_forms', level=level, weight=k, character=xci) if indb else '' } for xci in orbit ] if len(orbit) > table['maxGalCount']: table['maxGalCount'] = len(orbit) table['cells'][xi] = {} table['cells'][xi][k] = { 'N': level, 'k': k, 'chi': xi, 'url': url, 'dim': d, 'trivial_trivially': trivial_trivially, } table['galois_orbits_reps_numbers'] = table['galois_orbits_reps'].keys() table['galois_orbits_reps_numbers'].sort() #emf_logger.debug("Table:{0}".format(table)) return table
def charisprimitive(self,mod,num): return ConreyCharacter(mod, num).is_primitive()
def _compute(self): self.modulus = int(self.modlabel) self.number = int(self.numlabel) self.chi = ConreyCharacter(self.modulus, self.number) self.codelangs = ('pari', 'sage')
class WebDBDirichletOrbit(WebChar, WebDBDirichlet): """ A class using data stored in the database. Currently, this is all Dirichlet characters with modulus up to 10000. """ headers = ['Character'] _keys = [ 'title', 'codelangs', 'type', 'nf', 'nflabel', 'nfpol', 'modulus', 'modlabel', 'number', 'numlabel', 'texname', 'codeinit', 'symbol', 'codesymbol','headers', 'previous', 'next', 'conductor', 'condlabel', 'codecond', 'isprimitive', 'codeisprimitive', 'inducing','rowtruncate','ind_orbit_label', 'indlabel', 'codeind', 'order', 'codeorder', 'parity', 'codeparity', 'isreal', 'generators', 'codegenvalues', 'genvalues', 'logvalues', 'groupelts', 'values', 'codeval', 'galoisorbit', 'codegaloisorbit', 'valuefield', 'vflabel', 'vfpol', 'kerfield', 'kflabel', 'kfpol', 'contents', 'properties', 'friends', 'coltruncate', 'charsums', 'codegauss', 'codejacobi', 'codekloosterman', 'orbit_label', 'orbit_index', 'isminimal', 'isorbit', 'degree'] def __init__(self, **kwargs): self.type = "Dirichlet" self.isorbit = True self.modulus = kwargs.get('modulus', None) if self.modulus: self.modulus = int(self.modulus) self.modlabel = self.modulus self.number = kwargs.get('number', None) if self.number: self.number = int(self.number) self.numlabel = self.number if self.modulus: # Needed for Gauss sums, etc self.H = PariConreyGroup(self.modulus) if self.number: self.chi = ConreyCharacter(self.modulus, self.number) self.codelangs = ('pari', 'sage') self.orbit_label = kwargs.get('orbit_label', None) # this is what the user inserted, so might be banana self.label = "{}.{}".format(self.modulus, self.orbit_label) self.orbit_data = self.get_orbit_data(self.orbit_label) # this is the meat self.maxrows = 30 self.rowtruncate = False self._set_galoisorbit(self.orbit_data) self.maxcols = 10 self._contents = None self._set_groupelts() @lazy_attribute def title(self): return "Dirichlet character orbit {}.{}".format(self.modulus, self.orbit_label) def _set_galoisorbit(self, orbit_data): if self.modulus == 1: self.galoisorbit = [self._char_desc(1, mod=1,prim=True)] return upper_limit = min(self.maxrows + 1, self.degree + 1) if self.maxrows < self.degree + 1: self.rowtruncate = True self.galorbnums = orbit_data['galois_orbit'][:upper_limit] self.galoisorbit = list( self._char_desc(num, prim=orbit_data['is_primitive']) for num in self.galorbnums ) def get_orbit_data(self, orbit_label): mod_and_label = "{}.{}".format(self.modulus, orbit_label) orbit_data = db.char_dir_orbits.lucky( {'modulus': self.modulus, 'label': mod_and_label} ) if orbit_data is None: raise ValueError # Since we've got this, might as well set a bunch of stuff self.conductor = orbit_data['conductor'] self.order = orbit_data['order'] self.degree = orbit_data['char_degree'] self.isprimitive = bool_string(orbit_data['is_primitive']) self.isminimal = bool_string(orbit_data['is_minimal']) self.parity = parity_string(int(orbit_data['parity'])) self._set_kernel_field_poly(orbit_data) self.ind_orbit_label = cremona_letter_code(int(orbit_data['prim_orbit_index']) - 1) self.inducing = "{}.{}".format(self.conductor, self.ind_orbit_label) return orbit_data def _set_kernel_field_poly(self, orbit_data): if 'kernel_field_poly' in orbit_data.keys(): self.kernel_field_poly = orbit_data['kernel_field_poly'] else: self.kernel_field_poly = None @lazy_attribute def friends(self): friendlist = [] cglink = url_character(type=self.type, modulus=self.modulus) friendlist.append( ("Character group", cglink) ) if self.type == "Dirichlet" and self.isprimitive == bool_string(True): friendlist.append( ('Sato-Tate group', '/SatoTateGroup/0.1.%d' % self.order) ) if len(self.vflabel) > 0: friendlist.append( ("Value field", '/NumberField/' + self.vflabel) ) if self.symbol_numerator(): if self.symbol_numerator() > 0: assoclabel = '2.2.%d.1' % self.symbol_numerator() else: assoclabel = '2.0.%d.1' % -self.symbol_numerator() friendlist.append(("Associated quadratic field", '/NumberField/' + assoclabel)) if self.type == "Dirichlet" and self.isprimitive == bool_string(False): friendlist.append(('Primitive orbit '+self.inducing, url_for('characters.render_Dirichletwebpage', modulus=self.conductor, orbit_label=self.ind_orbit_label))) return friendlist @lazy_attribute def contents(self): if self._contents is None: self._contents = [] self._fill_contents() return self._contents def _fill_contents(self): for c in self.galorbnums: self.add_row(c) def add_row(self, c): """ Add a row to _contents for display on the webpage. Each row of content takes the form character_name, (header..data), (several..values) where `header..data` is expected to be a tuple of length the same size as `len(headers)`, and given in the same order as in `headers`, and where `several..values` are the values of the character on self.groupelts, in order. """ mod = self.modulus num = c valuepairs = db.char_dir_values.lookup( "{}.{}".format(mod, num), projection='values' ) prim = self.isprimitive == bool_string(True) self._contents.append(( self._char_desc(num, mod=mod, prim=prim), self._determine_values(valuepairs, self.order) )) def symbol_numerator(self): """ chi is equal to a kronecker symbol if and only if it is real """ if self.order != 2: return None if self.parity == parity_string(-1): return symbol_numerator(self.conductor, True) return symbol_numerator(self.conductor, False) @lazy_attribute def symbol(self): return kronecker_symbol(self.symbol_numerator()) @lazy_attribute def codesymbol(self): m = self.symbol_numerator() if m: return { 'sage': 'kronecker_character(%i)'%m, 'pari': 'znchartokronecker(g,chi)' } return None def _determine_values(self, valuepairs, order): """ Translate the db's values into the actual values. """ raw_values = [int(v) for g, v in valuepairs] values = [ self._tex_value(v, order, texify=True) for v in raw_values ] return values def _set_groupelts(self): if self.modulus == 1: self.groupelts = [1] else: db_data = db.char_dir_values.lookup( "{}.{}".format(self.modulus, 1) ) valuepairs = db_data['values'] self.groupelts = [int(g) for g, v in valuepairs] self.groupelts[0] = -1 @lazy_attribute def codeinit(self): self.exnum = self.galorbnums[0] self.exchi = ConreyCharacter(self.modulus, self.exnum) values_gens = db.char_dir_values.lookup( "{}.{}".format(self.modulus, self.exnum), projection='values_gens' ) vals = [int(v) for g, v in values_gens] sage_zeta_order = self.exchi.sage_zeta_order(self.order) self._genvalues_for_code = get_sage_genvalues(self.modulus, self.order, vals, sage_zeta_order) return { 'sage': [ 'from sage.modular.dirichlet import DirichletCharacter', 'H = DirichletGroup({}, base_ring=CyclotomicField({}))'.format( self.modulus, sage_zeta_order), 'M = H._module', 'chi = DirichletCharacter(H, M([{}]))'.format( ','.join(str(val) for val in self._genvalues_for_code) ), 'chi.galois_orbit()' ], 'pari': [ '[g,chi] = znchar(Mod(%i,%i))' % (self.exnum, self.modulus), 'order = charorder(g,chi)', '[ charpow(g,chi, k % order) | k <-[1..order-1], gcd(k,order)==1 ]' ] } @lazy_attribute def codeisprimitive(self): return { 'sage': 'chi.is_primitive()', 'pari': '#znconreyconductor(g,chi)==1' } @lazy_attribute def codecond(self): return { 'sage': 'chi.conductor()', 'pari': 'znconreyconductor(g,chi)' } @lazy_attribute def codeparity(self): return { 'sage': 'chi.is_odd()', 'pari': 'zncharisodd(g,chi)' }