CoCalc Public Fileswww / cgi-bin / mfd / mfd.pyOpen with one click!
Author: William A. Stein
Compute Environment: Ubuntu 18.04 (Deprecated)
1
import misc
2
import constants
3
import magma, pari
4
import pg # postgresql access
5
import mfd_opendb
6
import mfd_compression
7
import os, string
8
import heegner
9
import mfe_source
10
import sys
11
12
db = mfd_opendb.opendb()
13
14
DATA = constants.home + '/data'
15
16
UNKNOWN = constants.not_computed
17
18
def terminal_error(where, message):
19
raise "ERROR in %s: %s"%(where,message)
20
21
def sql_format(s):
22
s=s.replace("'","\\'")
23
return s
24
25
SEPARATOR = ";";
26
class Software:
27
def __init__(self, init_string):
28
d = init_string.split(SEPARATOR)
29
self.name = ""
30
self.version = ""
31
self.packages = ""
32
if len(d) > 0:
33
self.name = d[0]
34
if len(d) > 1:
35
self.version = d[1]
36
if len(d) > 2:
37
self.packages = d[2]
38
def __repr__(self):
39
return "%s%s%s%s%s"%(self.name, SEPARATOR, self.version, SEPARATOR, self.packages)
40
def get_name(self):
41
return self.name
42
def get_version(self):
43
return self.version
44
def get_packages(self):
45
return self.packages
46
47
##################################################################################
48
#
49
# Where a piece of data in the database came from.
50
#
51
# Represents the following postgresql table:
52
#
53
# Column | Type | Modifiers
54
#----------+-----------+---------------------------------------------------
55
# id | integer | not null default nextval('"source_id_seq"'::text)
56
# author | text |
57
# date | date |
58
# software | text |
59
# notes | text |
60
# Unique keys: source_id_key
61
class Source:
62
def init_from_id(self, id):
63
query = "SELECT * FROM source WHERE id=%s;"%id
64
out = db.query(query).dictresult()
65
if len(out) == 0:
66
raise "Error: Couldn't find Source with given id."
67
self.author = out[0]["author"]
68
self.date = out[0]["date"]
69
self.software = Software(out[0]["software"])
70
self.notes = out[0]["notes"]
71
self.id = id
72
73
def __init__(self, author, date="", software="::", notes=""):
74
if type(author) == type(1):
75
self.init_from_id(author)
76
return
77
self.id = -1
78
self.author = author
79
self.date = date
80
if type(software) == type(""):
81
self.software = Software(software)
82
else:
83
self.software = software
84
self.notes = notes
85
self.save_to_database()
86
87
def __repr__(self):
88
return "%s, %s, %s, %s"%self.get()
89
90
def HTML(self):
91
#td = '<td bgcolor="%s">'%constants.TABLE_BGCOLOR
92
td = '<td bgcolor="%s">'%"white"
93
s = "<table border=3><tr><td><table border=0 cellspacing=2 cellpadding=10 bgcolor=black>"
94
if self.get_author()!="":
95
author = self.get_author()
96
if author=="William Stein":
97
author='<a href="/">William Stein</a>'
98
s=s+"<tr>%s<b>Author</b></td>%s %s&nbsp</td></tr>"%(td,td,author)
99
if str(self.get_date()) != "None":
100
s=s+"<tr>%s<b>Date</b></td>%s%s&nbsp</td></tr>"%(td,td,self.get_date())
101
if self.get_software().get_name()!="":
102
sw = self.get_software()
103
if sw.get_packages() != "":
104
packages = "(Extra packages: %s)"%sw.get_packages()
105
else:
106
packages = ""
107
s=s+"<tr>%s<b>Software</b></td>%s%s, Version %s %s&nbsp</td></tr>"%(td,td,sw.get_name(), sw.get_version(), packages)
108
if str(self.get_notes())!="None" and str(self.get_notes())!="":
109
s=s+"<tr>%s<b>Notes</b></td>%s%s&nbsp</td></tr>"%(td,td,self.get_notes())
110
s=s+"</table></td></tr></table>"
111
return s
112
113
def __del__(self):
114
self.save_to_database()
115
116
def save_to_database(self):
117
id = self.get_id()
118
q1 = "UPDATE source SET author='%s' WHERE id=%s;"%(sql_format(self.author), id)
119
if self.date == "" or self.date == None:
120
q2 = "UPDATE source SET date=NULL WHERE id=%s;"%id
121
else:
122
q2 = "UPDATE source SET date='%s' WHERE id=%s;"%(self.date, id)
123
q3 = "UPDATE source SET software='%s' WHERE id=%s;"%(sql_format(str(self.software)), id)
124
q4 = "UPDATE source SET notes='%s' WHERE id=%s;"%(sql_format(self.notes), id)
125
query = q1+q2+q3+q4
126
db.query(query)
127
128
def set_author(self, author):
129
self.author = author
130
def set_date(self, date):
131
self.date = date
132
def set_software(self, software):
133
self.software = software
134
def set_notes(self, notes):
135
self.notes = notes
136
137
def get(self):
138
return (self.author, self.date, self.software, self.notes)
139
140
def get_id(self):
141
if self.id > -1:
142
return self.id
143
v = self.get()
144
values = (sql_format(v[0]),v[1],sql_format(str(v[2])),sql_format(v[3]))
145
query = "SELECT id FROM source WHERE author='%s' AND date='%s' \
146
AND software='%s' AND notes='%s'"%values
147
out = db.query(query).dictresult()
148
if len(out) == 0: # create new record in database
149
insert_query = "INSERT INTO source(author, date, software, notes) "+\
150
"VALUES('%s','%s','%s','%s')"%values
151
db.query(insert_query)
152
out = db.query(query).dictresult()
153
self.id=out[0]['id']
154
return self.id
155
156
def get_author(self):
157
return self.author
158
def get_date(self):
159
return self.date
160
def get_software(self):
161
return self.software
162
def get_notes(self):
163
return self.notes
164
165
166
##################################################################################
167
168
169
def delete(modsym, table):
170
query = "DELETE FROM %s WHERE mod_id = %s"%(table,modsym.id)
171
if table == 'mod':
172
query = query.replace('mod_id', 'id')
173
db.query(query)
174
175
def remove(modsym):
176
tables = ['a_invariants', 'anomalous_j_invariants', 'atkin_lehner',\
177
'charpoly', 'congruence_modulus', 'cuspidal_subgroup',\
178
'cusps', 'dimension', 'dimension_new', 'discriminant', 'equation',\
179
'hecke_field', 'j_invariant', 'leading_coefficient',\
180
'leading_ratio', 'lratio', 'lratio_odd', 'minus_volume',\
181
'modular_degree', 'modular_degree_odd',\
182
'mw_generators', 'mwrank', 'real_volume', 'regulator',\
183
'sha_an', 'sha_an_odd', 'slopes', 'torsion_subgroup', \
184
'traces', 'weierstrass_discriminant', 'inner_twists', \
185
'notes', 'heegner_heights'];
186
187
for i in range(0,len(tables)):
188
delete(modsym,tables[i])
189
190
query = "DELETE FROM mod WHERE id = %s"%modsym.id
191
db.query(query)
192
193
def insert(modsym, table, field, data):
194
# insert array of data into table for modular forms object modsym.
195
# use 'NULL' for NULL data...
196
if type(data) == type([1]):
197
data = misc.list_to_sqlstring(data)
198
if table_exists(modsym,table):
199
if data == 'NULL':
200
query = "UPDATE %s SET %s = NULL WHERE mod_id = %s"%(table,field,modsym.id)
201
else:
202
query = "UPDATE %s SET %s = '%s' WHERE mod_id = %s"%(table,field,data,modsym.id)
203
if table == 'mod':
204
query = query.replace('mod_id', 'id')
205
else:
206
if data != 'NULL':
207
query = "INSERT INTO %s(mod_id, %s) VALUES(%s, %s) " % \
208
(table, field, modsym.id, "'" + str(data) + "'")
209
db.query(query)
210
211
def lo_insert(modsym, table, field, fname, field2='', value2=''):
212
if table_exists(modsym,table,field2,value2):
213
if field2 != '':
214
extra2 = "AND %s = %s"%(field2,value2)
215
else:
216
extra2 = ""
217
query = "UPDATE %s SET %s = lo_import('%s') WHERE "\
218
"mod_id = %s %s"%(table,field,fname,modsym.id,extra2)
219
else:
220
if field2 != '':
221
extra2a = ", %s"%field2
222
extra2b = ", %s "%value2
223
else:
224
extra2a = ""
225
extra2b = ""
226
query = "INSERT INTO %s(mod_id, %s %s) VALUES(%s, lo_import('%s') %s) " % \
227
(table, field, extra2a, modsym.id, fname, extra2b)
228
db.query(query)
229
230
def table_exists(modsym, table, field2='', value2=''):
231
if field2 != '':
232
extra2 = " AND %s = %s"%(field2,value2)
233
else:
234
extra2 = ""
235
query = "SELECT * FROM %s WHERE mod_id = %s %s"%(table,modsym.id,extra2)
236
if table == 'mod':
237
query = query.replace('mod_id', 'id')
238
r = db.query(query).dictresult()
239
return len(r) != 0
240
241
def select(modsym, table, field, extra=""):
242
query = "SELECT %s FROM %s WHERE mod_id = %s %s"%(field,table,modsym.id,extra)
243
r = db.query(query).dictresult()
244
if len(r) == 0 or '%s'%r[0][field] == 'None':
245
return constants.not_computed
246
return r[0][field]
247
248
def lo_select(modsym, table, field, fname, field2='', value2=''):
249
if field2 != '':
250
extra2 = "AND %s = %s"%(field2,value2)
251
else:
252
extra2 = ""
253
query = "SELECT lo_export(%s,'%s') FROM %s "\
254
"WHERE mod_id = %s %s"%(field,fname,table,modsym.id, extra2)
255
db.query(query)
256
257
def get_data(fileid):
258
fname=DATA+'/'+str(fileid)
259
fnamebz2=fname+'.bz2'
260
if not os.path.exists(fnamebz2):
261
return constants.not_computed
262
os.system('/usr/bin/bunzip2 -fk '+fnamebz2);
263
file=open(fname,'r')
264
d=file.read()
265
file.close()
266
os.system('/bin/rm '+fname)
267
return d
268
269
def set_data(fileid, data):
270
fname=DATA+'/'+str(fileid)
271
file=open(fname,'w')
272
file.write(data)
273
file.close()
274
os.system('/usr/bin/bzip2 -f '+fname);
275
276
277
class ModSym:
278
def __init__(self, _level=1, _weight=2, _iso_class=0, \
279
_dirchar='1', _base_field='Q', number=1):
280
281
self.number_one_modsym=0 # unknown
282
self.maxp=0 #unknown
283
284
if type(_level)== type("11A"):
285
t = ModSym_From_Code(_level)
286
self.level = t.level
287
self.weight = t.weight
288
self.iso_class = t.iso_class
289
self.dirchar = t.dirchar
290
self.base_field = t.base_field
291
self.number = t.number
292
self.id = t.id
293
return
294
295
self.level = int(_level)
296
self.weight = int(_weight)
297
self.iso_class = int(_iso_class)
298
self.dirchar = string.replace(_dirchar,' ','')
299
self.base_field = _base_field
300
self.number = number
301
t = self.tuple()
302
query = ("SELECT id FROM mod WHERE level=%s AND weight=%s " +\
303
" AND iso_class=%s AND dirchar='%s' AND base_field='%s' AND number=%s") % t
304
i = db.query(query).dictresult()
305
if len(i) == 0: # insert new mod entry
306
print "Creation of new spaces disabled!! Things won't work."
307
self.id=0
308
return
309
query = ("INSERT INTO mod(level, weight, iso_class, dirchar, base_field, number) " +\
310
"VALUES(%s,%s,%s,'%s','%s','%s')") % t
311
db.query(query)
312
i = db.query(("SELECT id FROM MOD WHERE level=%s AND weight=%s " + \
313
" AND iso_class=%s AND dirchar='%s' AND base_field='%s' " + \
314
" AND number='%s'") % t\
315
).dictresult()
316
self.id=i[0]['id']
317
318
def __repr__(self):
319
if self.iso_class != 0:
320
num = self.number
321
else:
322
num = ""
323
return "ModSym_%s(%s%s%s;%s)(%s)" % \
324
(self.weight, self.level, misc.ToIsogenyCode(self.iso_class),\
325
num, self.base_field, self.dirchar)
326
327
def code(self):
328
c = "%s"%self.level
329
if self.weight != 2:
330
c = c + "k%s"%self.weight
331
if self.iso_class != 0:
332
c = c + misc.ToIsogenyCode(self.iso_class)
333
if self.dirchar != '1':
334
c = c + self.dirchar
335
if self.base_field != 'Q':
336
c = c + self.base_field
337
if self.iso_class != 0:
338
c = c + str(self.number)
339
return c
340
341
def tuple(self):
342
return (self.level, self.weight, self.iso_class,\
343
self.dirchar, self.base_field, self.number)
344
345
def number_one(self):
346
if self.number == 1:
347
return self
348
if type(self.number_one_modsym) == type(0):
349
self.number_one_modsym = ModSym(self.level, self.weight, self.iso_class, \
350
self.dirchar, self.base_field, 1)
351
return self.number_one_modsym
352
def set_source(self, table, source):
353
if type(source) == type(1):
354
insert(self, table, 'source', source)
355
else:
356
insert(self, table, 'source', source.get_id())
357
358
def source(self, table):
359
if type(table) == type(1): # also call with a source id
360
return Source(table)
361
id = select(self, table, 'source')
362
if id == constants.not_computed:
363
return constants.not_computed
364
else:
365
return Source(int(id))
366
367
368
def change_iso_class(self, new_isoclass): # use with caution.
369
# print "changing iso_class",self.iso_class," to",new_isoclass
370
db.query('UPDATE mod SET iso_class = %s WHERE id=%s'%(new_isoclass, self.id))
371
372
def dimension(self):
373
if self.number > 1:
374
return self.number_one().dimension()
375
dim = select(self, 'dimension', 'dimension')
376
if dim != constants.not_computed:
377
return int(dim)
378
if dim == constants.not_computed:
379
if self.iso_class == 0:
380
if self.base_field=='Q':
381
d = magma.dimension_cuspforms(self.level,self.weight,self.dirchar)
382
self.set_dimension(d)
383
return d
384
return constants.not_computed
385
return int(d)
386
387
def set_dimension(self, d):
388
insert(self, 'dimension', 'dimension', d)
389
390
def dimension_new(self):
391
if self.number > 1:
392
return self.number_one().dimension_new()
393
dim = select(self, 'dimension_new', 'dimension_new')
394
if dim == constants.not_computed:
395
if self.iso_class == 0:
396
if self.base_field=='Q':
397
d = magma.dimension_new_cuspforms(self.level,self.weight,self.dirchar)
398
self.set_dimension_new(d)
399
return d
400
return constants.not_computed
401
return int(dim)
402
403
def set_dimension_new(self, d):
404
insert(self, 'dimension_new', 'dimension_new', d)
405
406
407
def is_known(self, table, field, extra=""):
408
query = "SELECT %s FROM %s WHERE mod_id=%s %s"%(field,table,self.id,extra)
409
return len(db.query(query).dictresult())>0
410
411
412
##############################################################################################
413
########### charpoly: in the process of being migrated from being large objects ##############
414
##############################################################################################
415
416
def charpoly_is_known(self, n):
417
return self.is_known('charpoly','charpoly',' and n=%s'%n) or\
418
self.is_known('charpoly_2','charpoly',' and n=%s'%n) or\
419
self.is_known('charpoly_2', 'compressed_charpoly', ' and n=%s'%n)
420
421
def charpoly_no_lo(self, n):
422
return mfd_compression.select_charpoly_compressed(self.id, n)
423
424
def charpoly(self, n, fname=""):
425
if self.number > 1:
426
return self.number_one().charpoly(n, fname)
427
if not table_exists(self, 'charpoly', 'n', n):
428
return self.charpoly_no_lo(n)
429
if fname != "":
430
lo_select(self, 'charpoly', 'charpoly', fname, 'n', n)
431
else:
432
fname = misc.newtempfilename()
433
self.charpoly(n, fname)
434
file = open(fname)
435
ans = file.read()
436
file.close()
437
os.system("rm "+fname)
438
return ans
439
440
def known_charpolys(self):
441
query = "SELECT n FROM charpoly WHERE mod_id=%s"%self.id
442
out = db.query(query).dictresult()
443
query = "SELECT n FROM charpoly_2 WHERE mod_id=%s"%self.id
444
out2 = db.query(query).dictresult()
445
return [int(o['n']) for o in out] + [int(o['n']) for o in out2]
446
447
def charpoly_source(self, n):
448
query = "SELECT source FROM charpoly_2 WHERE mod_id=%s AND n=%s"%(self.id,n)
449
out = db.query(query).dictresult()
450
if len(out) == 0 or str(out[0]['source']) == 'None':
451
return constants.not_computed
452
return out[0]['source']
453
454
def set_charpoly(self, n, charpoly,source=0):
455
mfd_compression.set_charpoly_compressed(self.id, charpoly, source)
456
457
##################################################
458
################ End Charpoly ####################
459
##################################################
460
461
462
def discriminant(self):
463
if self.number > 1:
464
return self.number_one().discriminant()
465
return select(self, 'discriminant', 'discriminant')
466
467
def discriminant_factored(self):
468
if self.number > 1:
469
return self.number_one().discriminant()
470
return select(self, 'discriminant', 'factorization')
471
472
def weierstrass_discriminant(self):
473
return select(self, 'weierstrass_discriminant', 'discriminant')
474
475
def set_weierstrass_discriminant(self, discriminant):
476
insert(self, 'weierstrass_discriminant', 'discriminant', discriminant)
477
478
def set_dirchar(self, dirchar):
479
insert(self, 'mod', 'dirchar', dirchar)
480
self.dirchar = dirchar
481
482
def set_dirchar_data(self, dirchar_data):
483
insert(self, 'mod', 'dirchar_data', dirchar_data)
484
self.dirchar_data = dirchar_data
485
486
def get_dirchar_data(self): # this could be optimized by caching, if need be.
487
return select(self, 'mod', 'dirchar_data')
488
489
def cuspidal_subgroup(self):
490
return misc.parse_sqlarray(select(self, 'cuspidal_subgroup', 'invariants'))
491
492
def fileid(self, description):
493
query = "SELECT id FROM fileid WHERE mod_id = %s AND description = '%s'"%\
494
(self.id,description);
495
q = db.query(query).dictresult()
496
if len(q) == 0:
497
db.query("INSERT INTO fileid(mod_id, description) VALUES(%s,'%s')"%\
498
(self.id, description))
499
query = "SELECT id FROM fileid WHERE mod_id = %s AND description = '%s'"%\
500
(self.id,description);
501
q = db.query(query).dictresult()
502
return q[0]['id']
503
504
def notes(self):
505
return select(self, 'notes', 'notes')
506
507
def set_notes(self, notes):
508
insert(self, 'notes', 'notes', notes)
509
510
def equation(self):
511
return select(self, 'equation', 'equation')
512
513
def set_equation(self, eqn):
514
insert(self, 'equation', 'equation', eqn)
515
516
def cusps(self):
517
return select(self, 'cusps', 'cusps')
518
519
def set_cusps(self, eqn):
520
insert(self, 'cusps', 'cusps', eqn)
521
522
def hecke_field(self):
523
if self.number > 1:
524
return self.number_one().hecke_field()
525
ans = select(self, 'hecke_field', 'hecke_field')
526
if ans == constants.not_computed:
527
if self.dimension() == 1:
528
return "x-1"
529
ans = self.ap_field() # get from q-expansion
530
return ans
531
532
def set_hecke_field(self, eqn):
533
insert(self, 'hecke_field', 'hecke_field', eqn)
534
535
def hecke_field_discriminant(self):
536
if self.number > 1:
537
return self.number_one().hecke_field_discriminant()
538
return select(self, 'hecke_field', 'discriminant')
539
540
def set_hecke_field_discriminant(self, eqn):
541
insert(self, 'hecke_field', 'discriminant', eqn)
542
543
def a_invariants(self):
544
s=select(self, 'a_invariants', 'a_invariants')
545
s=s.replace("(","[")
546
s=s.replace(")","]")
547
return s
548
549
def set_a_invariants(self, a_invs):
550
insert(self, 'a_invariants', 'a_invariants', a_invs)
551
552
def mwrank(self):
553
if self.number > 1:
554
return self.number_one().mwrank()
555
return select(self, 'mwrank', 'mwrank')
556
def set_mwrank(self, r):
557
insert(self, 'mwrank', 'mwrank', r)
558
559
def regulator(self):
560
return select(self, 'regulator', 'regulator')
561
def set_regulator(self, r):
562
insert(self, 'regulator', 'regulator', r)
563
564
def leading_coefficient(self):
565
return select(self, 'leading_coefficient', 'leading_coefficient')
566
def set_leading_coefficient(self, r):
567
insert(self, 'leading_coefficient', 'leading_coefficient', r)
568
569
def real_volume(self):
570
return select(self, 'real_volume', 'real_volume')
571
572
def set_real_volume(self, r):
573
insert(self, 'real_volume', 'real_volume', r)
574
575
def torsion_subgroup(self):
576
return misc.parse_sqlarray(select(self, 'torsion_subgroup', 'invariants'))
577
def set_torsion_subgroup(self, invs):
578
insert(self, 'torsion_subgroup', 'invariants', invs)
579
580
def torsion_size(self):
581
return select(self, 'torsion_subgroup', 'size')
582
def set_torsion_size(self, size):
583
insert(self, 'torsion_subgroup', 'size', size)
584
def torsion_lower_bound(self):
585
return select(self, 'torsion_subgroup', 'lower_bound')
586
def set_torsion_lower_bound(self, bound, prec=0):
587
insert(self, 'torsion_subgroup', 'lower_bound', bound)
588
if prec>0:
589
insert(self, 'torsion_subgroup', 'lower_bound_prec', prec)
590
591
def torsion_upper_bound(self, prec=0):
592
if prec==0:
593
return select(self, 'torsion_subgroup', 'upper_bound')
594
my_prec = select(self, 'torsion_subgroup', 'upper_bound_prec')
595
if my_prec != constants.not_computed and int(my_prec) >= prec:
596
return select(self, 'torsion_subgroup', 'upper_bound')
597
if self.iso_class == 0:
598
if self.dirchar != '1':
599
return constants.not_computed
600
charpols = []
601
for p in pari.primes(3,prec):
602
cp = self.charpoly(p)
603
if cp==constants.not_computed:
604
return constants.not_computed
605
charpols.append([p,cp])
606
bound = pari.torsion_bound(self.level, prec, charpols)
607
if bound == 0:
608
return constants.not_computed
609
self.set_torsion_upper_bound(bound,prec)
610
return bound
611
else:
612
maxp = self.aplist_maxp()
613
if maxp == constants.not_computed:
614
print "Can't compute torsion upper bound, since aplist not known."
615
return
616
if maxp < prec:
617
print "aplist is only known to precision %s, which is less than needed."%maxp
618
return
619
bound = magma.torsion_upper_bound(self.aplist(), self.level, prec)
620
self.set_torsion_upper_bound(bound,prec)
621
return bound
622
623
def set_torsion_upper_bound(self, bound, prec=0):
624
insert(self, 'torsion_subgroup', 'upper_bound', bound)
625
if prec>0:
626
insert(self, 'torsion_subgroup', 'upper_bound_prec', prec)
627
628
def torsion_odd_upper_bound(self):
629
return select(self, 'torsion_odd_upper_bound', 'torsion_odd_upper_bound')
630
def set_torsion_odd_upper_bound(self, bound):
631
insert(self, 'torsion_odd_upper_bound', 'torsion_odd_upper_bound', bound)
632
633
def torsion_size(self):
634
return select(self, 'torsion_subgroup', 'size')
635
def set_torsion_size(self, bound):
636
insert(self, 'torsion_subgroup', 'size', bound)
637
638
def j_invariant(self):
639
return select(self, 'j_invariant', 'j_invariant')
640
def set_j_invariant(self, j):
641
insert(self, 'j_invariant', 'j_invariant', j)
642
643
def anomalous_j_invariants(self):
644
w = select(self, 'anomalous_j_invariants', 'j_invariants')
645
w = string.replace(w,"{","[")
646
w = string.replace(w,"}","]")
647
return w
648
649
def set_anomalous_j_invariants(self, js):
650
js = string.replace(js,"[","{")
651
js = string.replace(js,"]","}")
652
insert(self, 'anomalous_j_invariants', 'j_invariants', js)
653
654
def atkin_lehner(self):
655
if self.number > 1:
656
return self.number_one().atkin_lehner()
657
w = select(self, 'atkin_lehner', 'atkin_lehner')
658
w = string.replace(w,"{","[")
659
w = string.replace(w,"}","]")
660
return w
661
662
def set_atkin_lehner(self, signs):
663
signs = string.replace(signs,"[","{")
664
signs = string.replace(signs,"]","}")
665
insert(self, 'atkin_lehner', 'atkin_lehner', signs)
666
667
def tamagawa_numbers(self):
668
w = select(self, 'tamagawa_numbers', 'tamagawa_numbers')
669
w = string.replace(w,"{","[")
670
w = string.replace(w,"}","]")
671
w = string.replace(w,'"','')
672
return w
673
674
def set_tamagawa_numbers(self, signs):
675
signs = string.replace(signs,"[","{")
676
signs = string.replace(signs,"]","}")
677
insert(self, 'tamagawa_numbers', 'tamagawa_numbers', signs)
678
679
def tamagawa_numbers_odd(self):
680
w = select(self, 'tamagawa_numbers_odd', 'tamagawa_numbers_odd')
681
w = string.replace(w,"{","[")
682
w = string.replace(w,"}","]")
683
w = string.replace(w,'"','')
684
return w
685
686
def set_tamagawa_numbers_odd(self, signs):
687
signs = string.replace(signs,"[","{")
688
signs = string.replace(signs,"]","}")
689
insert(self, 'tamagawa_numbers_odd', 'tamagawa_numbers_odd', signs)
690
691
def traces(self):
692
if self.number > 1:
693
return self.number_one().traces()
694
return misc.parse_sqlarray(select(self, 'traces', 'traces'))
695
696
def set_traces(self, t):
697
insert(self, 'traces', 'traces', t)
698
699
def mw_generators(self):
700
gens = select(self, 'mw_generators', 'mw_generators')
701
gens = string.replace(gens,'"','')
702
gens = string.replace(gens,'{','(')
703
gens = string.replace(gens,'}',')')
704
gens = gens[1:-1]
705
gens = string.replace(gens,"),(","), (")
706
return gens
707
708
709
def set_mw_generators(self, gens):
710
insert(self, 'mw_generators', 'mw_generators', gens)
711
712
def congruence_modulus(self):
713
if self.number > 1:
714
return self.number_one().congruence_modulus()
715
return select(self, 'congruence_modulus', 'congruence_modulus')
716
717
def set_congruence_modulus(self, r):
718
insert(self, 'congruence_modulus', 'congruence_modulus', r)
719
720
def congruence_modulus_primes(self):
721
if self.number > 1:
722
return self.number_one().congruence_modulus_primes()
723
return select(self, 'congruence_modulus', 'primes')
724
725
def set_congruence_modulus_primes(self, r):
726
insert(self, 'congruence_modulus', 'primes', r)
727
728
def modular_degree(self):
729
return select(self, 'modular_degree', 'modular_degree')
730
def set_modular_degree(self, r):
731
insert(self, 'modular_degree', 'modular_degree', r)
732
733
def modular_degree_primes(self):
734
return select(self, 'modular_degree', 'primes')
735
def set_modular_degree_primes(self, r):
736
insert(self, 'modular_degree', 'primes', r)
737
738
def modular_degree_odd(self):
739
return select(self, 'modular_degree_odd', 'modular_degree_odd')
740
def set_modular_degree_odd(self, r):
741
insert(self, 'modular_degree_odd', 'modular_degree_odd', r)
742
743
def modular_degree_odd_primes(self):
744
return select(self, 'modular_degree_odd', 'primes')
745
def set_modular_degree_odd_primes(self, r):
746
insert(self, 'modular_degree_odd', 'primes', r)
747
748
def lratio(self):
749
l = select(self, 'lratio', 'lratio')
750
if l == constants.not_computed:
751
return l
752
return eval(l)
753
754
def lratio_k2(self):
755
L = self.lratio()
756
if L == constants.not_computed:
757
return constants.not_computed
758
return L[0]
759
def set_lratio_k2(self, L1):
760
self.set_lratio("['%s']"%L1)
761
762
def set_lratio(self, ratios): # format: ['lrat1', 'lrat2', etc.]
763
insert(self, 'lratio', 'lratio', ratios)
764
765
def lratio_odd(self):
766
l = select(self, 'lratio_odd', 'lratio_odd')
767
if l == constants.not_computed:
768
return l
769
return eval(l)
770
771
def set_lratio_odd(self, ratios):
772
insert(self, 'lratio_odd', 'lratio_odd', ratios)
773
774
def set_lratio_odd_k2(self, L1):
775
self.set_lratio_odd("['%s']"%L1)
776
777
def lratio_odd_k2(self):
778
L = self.lratio_odd()
779
if L == constants.not_computed:
780
return constants.not_computed
781
return L[0]
782
783
def sha_an(self):
784
return select(self, 'sha_an', 'sha_an');
785
786
def set_sha_an(self, sha):
787
insert(self, 'sha_an', 'sha_an', sha);
788
789
def sha_an_odd(self):
790
return select(self, 'sha_an_odd', 'sha_an_odd');
791
def set_sha_an_odd(self, sha):
792
insert(self, 'sha_an_odd', 'sha_an_odd', sha);
793
def sha_an_odd_upper_bound(self):
794
return select(self, 'sha_an_odd', 'upper_bound');
795
def set_sha_an_odd_upper_bound(self, upper_bound):
796
insert(self, 'sha_an_odd', 'upper_bound', upper_bound);
797
def sha_an_odd_lower_bound(self):
798
return select(self, 'sha_an_odd', 'lower_bound');
799
def set_sha_an_odd_lower_bound(self, lower_bound):
800
insert(self, 'sha_an_odd', 'lower_bound', lower_bound);
801
def sha_an_odd_lower_bound2(self):
802
numerator = select(self, 'sha_an_odd_lower_bound', 'numerator');
803
denominator = select(self, 'sha_an_odd_lower_bound', 'denominator');
804
if denominator=='1':
805
return numerator
806
return "%s/%s"%(numerator,denominator)
807
def set_sha_an_odd_lower_bound2(self, bound):
808
i = string.find(bound,"/")
809
if i != -1:
810
numerator = bound[:i]
811
denominator = bound[i+1:]
812
else:
813
numerator = bound
814
denominator = '1'
815
insert(self, 'sha_an_odd_lower_bound', 'numerator', numerator);
816
insert(self, 'sha_an_odd_lower_bound', 'denominator', denominator);
817
818
def heegner_heights(self):
819
discriminants = select(self, 'heegner_heights', 'discriminants')
820
heights = select(self, 'heegner_heights', 'heights')
821
if discriminants == constants.not_computed or heights == constants.not_computed:
822
return constants.not_computed
823
return [eval(discriminants), eval(heights)]
824
825
def set_heegner_heights(self, discriminants, heights):
826
insert(self, 'heegner_heights', 'discriminants', '%s'%discriminants)
827
heights='%s'%heights
828
heights=heights.replace("'",'"')
829
insert(self, 'heegner_heights', 'heights', heights)
830
831
def compute_heegner_heights(self, n):
832
invs = self.a_invariants()
833
if invs == constants.not_computed:
834
return
835
cmd = 'read("/var/www/cgi-bin/mfd/heegner.gp"); '\
836
'heegner_heights(ellinit(%s),%s);'%(invs,n)
837
cmd = cmd.replace("'","")
838
h = pari.pari(cmd)
839
discriminants = h[1:h.find(']')+1]
840
heights = h[h.find('], ')+3:-1]
841
self.set_heegner_heights(discriminants, heights)
842
return self.heegner_heights()
843
844
def heegner_indexes_odd(self):
845
indexes = select(self, 'heegner_indexes_odd', 'indexes')
846
proofs = select(self, 'heegner_indexes_odd', 'proofs')
847
if indexes == constants.not_computed or \
848
proofs == constants.not_computed:
849
return constants.not_computed
850
return [indexes, proofs]
851
852
def set_heegner_indexes_odd(self, indexes, proofs):
853
insert(self, 'heegner_indexes_odd', 'indexes', indexes)
854
insert(self, 'heegner_indexes_odd', 'proofs', proofs)
855
856
def compute_heegner_indexes_odd(self):
857
if self.dimension() == 1:
858
heegner.compute_heegner_indexes_odd(self)
859
return self.heegner_indexes_odd()
860
861
def modp_gcd_upper_bound(self):
862
bound = select(self, 'modp_gcd_upper_bound', 'bound')
863
max_prime = select(self, 'modp_gcd_upper_bound', 'max_prime')
864
if bound == constants.not_computed or max_prime == constants.not_computed:
865
return constants.not_computed
866
max_prime = int(max_prime)
867
return [max_prime, bound]
868
869
def set_modp_gcd_upper_bound(self, max_prime, bound):
870
insert(self, 'modp_gcd_upper_bound', 'max_prime', max_prime)
871
insert(self, 'modp_gcd_upper_bound', 'bound', bound)
872
873
def compute_modp_gcd_upper_bound(self):
874
if self.dimension() == 1:
875
aplist = self.aplist()
876
if aplist == constants.not_computed:
877
return self.modp_gcd_upper_bound()
878
aplist = aplist[aplist.find(',')+1:]; aplist = aplist[:aplist.find(']]')]
879
aplist = aplist.replace('[',''); aplist = aplist.replace(']',''); aplist = '[' + aplist + ']'
880
N = self.level
881
cmd ="p=1; bnd=0; aplist=%s; N=%s;"%(aplist,N) + \
882
"for(i=1,length(aplist),"\
883
" p = nextprime(p+1);"\
884
" if((2*N) % p != 0, bnd=gcd(bnd,p+1-aplist[i]))"\
885
");"\
886
"[bnd,p];"
887
ans = pari.pari(cmd)
888
print "ans = ", ans
889
max_prime = ans[ans.find(',')+2:ans.find(']')]
890
bound = ans[1:ans.find(',')]
891
self.set_modp_gcd_upper_bound(max_prime, bound)
892
return self.modp_gcd_upper_bound()
893
894
def visibility(self):
895
return select(self, 'visibility', 'visibility');
896
897
def set_visibility(self, data):
898
insert(self, 'visibility', 'visibility', data);
899
900
def is_elliptic_curve(self):
901
return self.dimension() == 1 and self.weight == 2 \
902
and self.iso_class > 0 and self.dirchar == '1' \
903
and self.base_field == 'Q'
904
905
def miscellaneous(self):
906
query = "SELECT * FROM miscellaneous WHERE mod_id=%s"%self.id
907
return db.query(query).dictresult()
908
909
def known_slopes(self):
910
query = "SELECT prime FROM slopes WHERE mod_id=%s"%self.id
911
out = db.query(query).dictresult()
912
return [int(o['prime']) for o in out]
913
914
def slopes(self, prime):
915
query = "SELECT slopes FROM slopes WHERE mod_id=%s and prime=%s"%(self.id,prime)
916
out = db.query(query).dictresult()
917
if len(out) == 0:
918
return constants.not_computed
919
ans=out[0]['slopes']
920
ans=ans.replace("{","[")
921
ans=ans.replace("}","]")
922
return ans
923
924
########## START: ap table: ap, traces, charpolys #########################
925
def remove_all_ap(self):
926
query = "DELETE FROM ap WHERE mod_id=%s"%self.id
927
out=db.query(query)
928
929
def known_ap(self):
930
query = "SELECT p FROM ap WHERE mod_id=%s ORDER BY p"%self.id
931
out=db.query(query).dictresult()
932
return [x['p'] for x in out]
933
934
def known_ap_value(self):
935
query = "SELECT p, value FROM ap WHERE mod_id=%s AND value IS NOT NULL "%self.id
936
out=db.query(query).dictresult()
937
return [x['p'] for x in out]
938
939
# SHOULD BE REWRITTEN IF AP's ARE COMPRESSED (Dimitar)
940
def ap(self, p):
941
query = "SELECT value FROM ap WHERE mod_id=%s and p=%s"%(self.id,p)
942
print query
943
out=db.query(query).dictresult()
944
if len(out) == 0:
945
return UNKNOWN
946
return out[0]['value']
947
948
949
def trace_ap(self, p):
950
query = "SELECT trace FROM ap WHERE mod_id=%s and p=%s"%(self.id,p)
951
out=db.query(query).dictresult()
952
if len(out) == 0 or "%s"%out[0]['trace'] == 'None':
953
return UNKNOWN
954
return out[0]['trace']
955
def known_trace_ap(self):
956
query = "SELECT p, trace FROM ap WHERE mod_id=%s AND trace IS NOT NULL"%self.id
957
out=db.query(query).dictresult()
958
return [x['p'] for x in out]
959
def charpoly_ap(self, p):
960
query = "SELECT charpoly FROM ap WHERE mod_id=%s and p=%s"%(self.id,p)
961
out=db.query(query).dictresult()
962
if len(out) == 0 or "%s"%out[0]['charpoly'] == 'None':
963
return UNKNOWN
964
return out[0]['charpoly']
965
def known_charpoly_ap(self):
966
query = "SELECT p, charpoly FROM ap WHERE mod_id=%s AND charpoly IS NOT NULL"%self.id
967
out=db.query(query).dictresult()
968
return [x['p'] for x in out]
969
970
# SHOULD BE REWRITTEN IF AP's ARE COMPRESSED (Dimitar)
971
def set_ap(self, p, ap):
972
self.maxp=0 # invalidate, since now we don't know it.
973
query = "SELECT * FROM ap WHERE mod_id=%s AND p=%s"%(self.id,p)
974
if len(db.query(query).dictresult()) == 0:
975
query = "INSERT INTO ap(mod_id, p, value) VALUES(%s,%s,'%s')"%(self.id,p,ap)
976
else:
977
query = "UPDATE ap SET value='%s' WHERE mod_id=%s AND p=%s"%(ap,self.id,p)
978
db.query(query)
979
980
def set_trace_ap(self, p, trace):
981
query = "SELECT * FROM ap where mod_id=%s and p=%s"%(self.id,p)
982
if len(db.query(query).dictresult()) == 0:
983
query = "INSERT INTO ap(mod_id, p, trace) VALUES(%s,%s,'%s')"%(self.id,p,trace)
984
else:
985
query = "UPDATE ap SET trace='%s' WHERE mod_id=%s AND p=%s"%(trace,self.id,p)
986
db.query(query)
987
988
def set_charpoly_ap(self, p, charpoly):
989
charpoly=charpoly.replace(" ","")
990
query = "SELECT * FROM ap where mod_id=%s and p=%s"%(self.id,p)
991
if len(db.query(query).dictresult()) == 0:
992
query = "INSERT INTO ap(mod_id, p, charpoly) VALUES(%s,%s,'%s')"%(self.id,p,charpoly)
993
else:
994
query = "UPDATE ap SET charpoly='%s' WHERE mod_id=%s AND p=%s"%(charpoly,self.id,p)
995
db.query(query)
996
997
def set_ap_data(self, field='x-1', embedding='[]', source=0):
998
query = "DELETE FROM ap_data WHERE mod_id=%s"%self.id
999
db.query(query)
1000
mfd_compression.set_ap_data_compress(self.id, field, embedding, source)
1001
1002
def ap_field(self):
1003
return select(self, "ap_data", "field")
1004
1005
def ap_embedding(self):
1006
# return select(self, "ap_data", "embedding")
1007
return mfd_compression.select_ap_embedding(self.id)
1008
1009
def ap_source(self):
1010
return select(self, "ap_data", "source")
1011
1012
# this is a temporary function, which we'll eliminate
1013
def ap_set_using_aplist(self):
1014
x = self.aplist().replace(" ","")
1015
if x==constants.not_computed:
1016
return
1017
i=x.find("<")+1
1018
j=x.find(",")
1019
field=x[i:j]
1020
i=x.find("]]")+3
1021
j=x.find(">")
1022
embedding=x[i:j]
1023
source=12 # ap that come from aplist
1024
self.set_ap_data(field, embedding, source)
1025
i=x.find("[[")+1
1026
j=x.find("]]")+1
1027
x=x[i:j]
1028
n=0
1029
while x.find("[") != -1:
1030
i=x.find("[")
1031
j=x.find("]")+1
1032
p=constants.PRIMES[n]
1033
ap = x[i:j]
1034
self.set_ap(p,ap)
1035
x=x[j+1:]
1036
n=n+1
1037
1038
def remove_aplist(self):
1039
query = "DELETE FROM aplist WHERE mod_id = %s"%self.id
1040
db.query(query)
1041
1042
def ap_trace_using_traces(self):
1043
t = self.traces()
1044
if t == UNKNOWN:
1045
return
1046
for n in range(len(t)):
1047
p = constants.PRIMES[n]
1048
self.set_trace_ap(p, t[n])
1049
1050
def remove_traces(self):
1051
query = "DELETE FROM traces WHERE mod_id = %s"%self.id
1052
db.query(query)
1053
1054
def move_aplist_and_trace_for_fullspace(self, logfile=""):
1055
if type(logfile) != type(""):
1056
logfile.write("%s (%s)\n"%(self.code(), self.id))
1057
logfile.flush()
1058
1059
if self.iso_class != 0:
1060
print "Moving %s"%self.code()
1061
self.ap_set_using_aplist()
1062
self.ap_trace_using_traces()
1063
self.aplist_delete()
1064
self.remove_traces()
1065
return
1066
1067
print "** FULLSPACE %s ** "%self.code()
1068
for f in self.get_iso_classes():
1069
if f.aplist_is_deleted():
1070
continue
1071
print "Moving %s"%f.code()
1072
f.ap_set_using_aplist()
1073
f.ap_trace_using_traces()
1074
f.aplist_delete()
1075
f.remove_traces()
1076
1077
########## END: ap table: ap, traces, charpolys #########################
1078
1079
1080
1081
# The aplist is stored in a bzip2'd file. That file contains a MAGMA-readable
1082
# 3-tuple. The first entry defines the field generated by the a_p. The second
1083
# entry is a sequence of sequences that give each a_p on a basis for the field,
1084
# the third entry embeds that basis in the field defined by the first entry.
1085
def aplist_is_deleted(self):
1086
query = "SELECT deleted FROM aplist WHERE mod_id=%s AND deleted=1"%self.id
1087
return len(db.query(query).dictresult()) > 0
1088
def aplist_delete(self, val=1):
1089
query = "SELECT * FROM aplist WHERE mod_id=%s"%self.id
1090
if len(db.query(query).dictresult()) > 0:
1091
query = "UPDATE aplist SET deleted=%s WHERE mod_id=%s"%(val,self.id)
1092
db.query(query)
1093
1094
def aplist(self, maxp=0):
1095
if maxp == 0:
1096
maxp = self.aplist_maxp()
1097
if maxp > self.aplist_maxp():
1098
terminal_error("ModSym.aplist", "maxp (=%s) larger than known (=%s)"%(maxp, self.aplist_maxp()))
1099
if self.number > 1:
1100
return self.number_one().aplist(maxp)
1101
if self.iso_class == 0:
1102
terminal_error("ModSym.aplist", "aplist not defined for full space!")
1103
1104
# field extension
1105
query = "SELECT field FROM ap_data WHERE mod_id = %s"%self.id
1106
field = db.query(query).dictresult()
1107
ans = "<" + field[0]['field']
1108
1109
# create the aplist from the ap table
1110
ans = ans + ", ["
1111
query = "SELECT p, value from ap WHERE mod_id=%s AND p <= %s ORDER BY p"%(self.id, maxp)
1112
x = db.query(query).dictresult()
1113
for i in range(len(x)):
1114
ans = ans + x[i]['value']
1115
if i != len(x)-1:
1116
ans = ans + ","
1117
ans = ans + "]"
1118
1119
# get the embedding
1120
# query = "SELECT embedding FROM ap_data WHERE mod_id = %s"%self.id
1121
# x = db.query(query).dictresult()
1122
# ans = ans + "," + x[0]['embedding']
1123
ans = ans + "," + mfd_compression.select_ap_embedding(self.id)
1124
1125
# get dirchar_data
1126
query = "SELECT dirchar_data FROM mod WHERE id = %s AND dirchar_data IS NOT NULL"%self.id
1127
x = db.query(query).dictresult()
1128
if len(x) > 0:
1129
ans = ans + "," + x[0]['dirchar_data']
1130
1131
ans = ans + ">"
1132
return ans
1133
1134
def aplist_known(self):
1135
query = " SELECT p FROM ap WHERE mod_id = %s"%self.id
1136
known = db.query(query).dictresult()
1137
return [k['p'] for k in known]
1138
1139
def aplist_maxp(self):
1140
# largest p such that we know a2, a3, a5, a7, a11, ..., ap *all* known.
1141
1142
# also p is at most the biggest prime in constants.PRIMES
1143
if self.number > 1:
1144
return self.number_one().aplist_maxp()
1145
if self.maxp > 0:
1146
return self.maxp
1147
known = self.aplist_known()
1148
if len(known) == 0:
1149
return 0
1150
maxp = max(known)
1151
# find first position where they differ
1152
for i in range(min(len(constants.PRIMES), len(known))):
1153
if known[i] != constants.PRIMES[i]:
1154
if i > 0:
1155
maxp = known[i-1]
1156
else:
1157
maxp = 0
1158
self.maxp = maxp
1159
return self.maxp
1160
1161
1162
def set_aplist(self, maxp, fname):
1163
lo_insert(self, 'aplist', 'aplist', fname)
1164
insert(self, 'aplist', 'maxp', maxp)
1165
1166
def aplist_hecke_field(self): # extract the hecke_field from the aplist string.
1167
if self.number > 1:
1168
return self.number_one().aplist_hecke_field()
1169
if self.aplist_maxp() == constants.not_computed:
1170
return constants.not_computed
1171
s = self.aplist()
1172
# the hecke field is stored between the opening < and the first comma.
1173
return string.replace(s[string.find(s,"<")+1:string.find(s,",")]," ","")
1174
1175
def aplist_embedding(self): # extract the embedding into the powerbasis from the aplist string.
1176
if self.number > 1:
1177
return self.number_one().aplist_embedding()
1178
if self.aplist_maxp() == constants.not_computed:
1179
return constants.not_computed
1180
s = self.aplist()
1181
# the embedding is stored as a list of polys between the last set of brackets.
1182
return string.replace(s[string.rfind(s,"["):string.rfind(s,"]")+1]," ","")
1183
1184
def aplist_dimension(self): # extract dimension from the aplist string
1185
if self.number > 1:
1186
return self.number_one().aplist_dimension()
1187
if self.aplist_maxp() == constants.not_computed:
1188
return constants.not_computed
1189
s = self.aplist_hecke_field()
1190
i = string.find(s,"^")+1
1191
if i==0: # degree 1 (no exponent)
1192
return 1
1193
j = i+1
1194
while j < len(s) and s[j] in ['0','1','2','3','4','5','6','7','8','9']:
1195
j = j+1
1196
return eval(s[i:j])
1197
1198
def aplist_compute(self, prec=1000):
1199
if self.number > 1:
1200
return self.number_one().aplist_compute(prec)
1201
if not self.is_elliptic_curve():
1202
return constants.not_computed
1203
cmd = "E = ellinit(%s); "%self.a_invariants()
1204
cmd = cmd.replace("'","")
1205
cmd = cmd + "v=[]; forprime(p=2,%s,v=concat(v,[[ellap(E,p)]])); v;"%prec
1206
ap = pari.pari(cmd)
1207
fname = misc.newtempfilename()
1208
file = open(fname,"w")
1209
file.write("<x-1, "+ap+", [1]>")
1210
file.close()
1211
os.system("bzip2 "+fname)
1212
self.set_aplist(prec, fname+".bz2")
1213
os.system("rm "+fname+".bz2")
1214
return self.aplist()
1215
1216
def q_expansion(self, prec=8):
1217
if self.number > 1:
1218
return self.number_one().q_expansion(prec)
1219
if self.aplist_maxp() == constants.not_computed:
1220
return constants.not_computed
1221
return magma.aplist_to_qexpansion(self.aplist(),self.level, self.weight,\
1222
self.dirchar, prec)
1223
1224
def q_integral_basis(self, prec=8):
1225
if self.number > 1:
1226
return self.number_one().q_integral_basis(prec)
1227
if self.aplist_maxp() == constants.not_computed:
1228
return constants.not_computed
1229
return magma.aplist_to_q_integral_basis(\
1230
self.aplist(),self.level, self.weight, self.dirchar, prec)
1231
1232
def congruence_group(self, M, prec=8):
1233
if self.number > 1:
1234
return self.number_one().congruence_group(M,prec)
1235
if self == M:
1236
raise "Can't compare form to self."
1237
if self.aplist_maxp() == constants.not_computed or M.aplist_maxp() == constants.not_computed \
1238
or self.iso_class == 0 or M.iso_class == 0:
1239
return constants.not_computed
1240
return magma.congruence_group(self.level, M.level, \
1241
self.q_integral_basis(prec), M.q_integral_basis(prec))
1242
1243
def inner_twists(self, force_compute=0):
1244
order_of_root = select(self, 'inner_twists', 'order_of_root');
1245
if order_of_root == constants.not_computed or force_compute:
1246
if force_compute and self.aplist_maxp() != constants.not_computed and self.dirchar == '1':
1247
data = magma.inner_twists_data(self.level,self.aplist())
1248
order_of_root = data[0] # order of root of unity used to write twist characters
1249
num_twists = data[1] # size of group of twists
1250
generators = data[2] # generators of group of twists
1251
fixed_field = data[3] # field fixed by the inner twist automorphisms
1252
fixed_degree= data[4] # field fixed by the inner twist automorphisms
1253
hilbert_sym = data[5] # hilbert symbol description of endomorphism algebra
1254
endo_alg = data[6] # desc. of the endomorphism algebra (evaluation of hilbert_sym)
1255
has_cm = data[7] # true <==> form has CM
1256
insert(self,'inner_twists','order_of_root',order_of_root)
1257
insert(self,'inner_twists','num_twists', num_twists)
1258
insert(self,'inner_twists','generators', generators)
1259
insert(self,'inner_twists','fixed_field', fixed_field)
1260
insert(self,'inner_twists','fixed_degree', fixed_degree)
1261
insert(self,'inner_twists','hilbert_sym', hilbert_sym)
1262
insert(self,'inner_twists','endo_alg', endo_alg)
1263
insert(self,'inner_twists','has_cm', has_cm)
1264
1265
return [select(self,'inner_twists','order_of_root'), \
1266
select(self,'inner_twists','num_twists'), \
1267
select(self,'inner_twists','generators'), \
1268
select(self,'inner_twists','fixed_field'), \
1269
select(self,'inner_twists','fixed_degree'), \
1270
select(self,'inner_twists','hilbert_sym'), \
1271
select(self,'inner_twists','endo_alg'), \
1272
select(self,'inner_twists','has_cm')]
1273
1274
#####################################################################################
1275
#
1276
# These methods are special to FULL space (with iso_class=0).
1277
#
1278
#####################################################################################
1279
def howmany_iso_classes(self):
1280
if self.iso_class != 0:
1281
raise "number_of_iso_classes: self must be a full factor (i.e., self.iso_class=0)."
1282
query = "SELECT * from mod where level=%s"%self.level + \
1283
" AND weight=%s AND iso_class>0 "%self.weight +\
1284
"AND dirchar='%s' AND base_field='%s' AND number=1"%(self.dirchar,self.base_field)
1285
return len(db.query(query).dictresult())
1286
1287
def get_iso_class(self, iso_class):
1288
if self.iso_class != 0:
1289
raise "get_newform: self must be a full factor (i.e., self.iso_class=0)."
1290
if iso_class <= 0:
1291
raise "get_newform: iso_class must be positive."
1292
if iso_class > self.howmany_iso_classes():
1293
raise "get_newform: iso_class too big; create it separately."
1294
return ModSym(self.level, self.weight, iso_class, self.dirchar, self.base_field, 1)
1295
1296
def get_iso_classes(self):
1297
if self.iso_class != 0:
1298
raise "get_iso_classes: self must be a full factor (i.e., self.iso_class=0)."
1299
classes = []
1300
for i in range(self.howmany_iso_classes()):
1301
classes.append(self.get_iso_class(i+1))
1302
return classes
1303
1304
def is_complete(self): # true if we're absolutely certain that all newforms are known
1305
if self.iso_class != 0:
1306
raise "get_newform: self must be a full factor (i.e., self.iso_class=0)."
1307
newdim = self.dimension_new()
1308
if newdim == constants.not_computed:
1309
return 0
1310
if newdim == 0:
1311
return 1
1312
d = 0
1313
c = self.get_iso_classes()
1314
for f in c:
1315
if f.dimension() == constants.not_computed:
1316
return 0
1317
d = d + f.dimension()
1318
return d == newdim
1319
1320
#############################################
1321
# #
1322
# A few useful functions #
1323
# #
1324
#############################################
1325
1326
def genusX0(N):
1327
m = ModSym(N,2)
1328
return m.dimension()
1329
1330
def charpoly(N,p):
1331
m = ModSym(N)
1332
f = m.charpoly(p)
1333
if N < 1000 and f == constants.not_computed:
1334
f = magma.charpolyGamma0(N,2,p)
1335
m.set_charpoly(p,f)
1336
return f
1337
1338
def discriminant(N,iso_class):
1339
m = ModSym(N,2,iso_class)
1340
return m.discriminant()
1341
1342
def cuspidal_subgroup(N,iso_class):
1343
m = ModSym(N,2,iso_class)
1344
return m.cuspidal_subgroup()
1345
1346
def iso_class_data(N, k, eps='1', base_field='Q'):
1347
query = "SELECT iso_class, number FROM mod WHERE "+\
1348
"level=%s AND weight=%s AND iso_class>0 "%(N,k)+\
1349
"AND dirchar='%s' AND base_field='%s' order by iso_class, number"%(eps,base_field)
1350
return db.query(query).dictresult()
1351
1352
def notes(N):
1353
m = ModSym(N,2)
1354
return m.notes()
1355
1356
def ModSymWeierstrass(invariants):
1357
query = "SELECT mod_id FROM a_invariants WHERE " + \
1358
" a_invariants[1] = CAST('%s' as numeric)"%invariants[0] + \
1359
"AND a_invariants[2] = CAST('%s' as numeric)"%invariants[1] + \
1360
"AND a_invariants[3] = CAST('%s' as numeric)"%invariants[2] + \
1361
"AND a_invariants[4] = CAST('%s' as numeric)"%invariants[3] + \
1362
"AND a_invariants[5] = CAST('%s' as numeric)"%invariants[4]
1363
1364
id = db.query(query).dictresult()
1365
if len(id) == 0:
1366
return constants.not_computed;
1367
1368
query = "SELECT level, iso_class FROM mod WHERE id=%s"%id[0]['mod_id']
1369
x = db.query(query).dictresult()
1370
if len(x) == 0:
1371
return constants.not_computed;
1372
return ModSym(x[0]['level'], 2, x[0]['iso_class'])
1373
1374
1375
def is_number(x):
1376
return x >= '0' and x <= '9'
1377
1378
def ModSym_From_ID(id):
1379
query = "SELECT * FROM mod WHERE id=%s"%id
1380
out = db.query(query).dictresult()
1381
if len(out) == 0:
1382
terminal_error("ModSym_From_ID", "No such space")
1383
x=out[0]
1384
return ModSym(x['level'], x['weight'], x['iso_class'], x['dirchar'], \
1385
x['base_field'], x['number'])
1386
1387
def ModSym_From_Code(code):
1388
level = "";
1389
i = 0;
1390
while i<len(code) and code[i] >= '0' and code[i] <= '9':
1391
level = level + code[i]
1392
i = i + 1
1393
level = int(level)
1394
if i<len(code) and code[i] == 'k':
1395
i = i + 1
1396
weight = ""
1397
while i < len(code) and code[i] >= '0' and code[i] <= '9':
1398
weight = weight + code[i]
1399
i = i + 1
1400
weight = int(weight)
1401
else:
1402
weight = 2
1403
if i>=len(code) or code[i] == '[': # the '[' is for characters
1404
iso_class = 0
1405
else:
1406
iso = "";
1407
while i < len(code) and code[i] != '[' and not is_number(code[i]):
1408
iso = iso + code[i]
1409
i = i+1
1410
iso_class = misc.IsogenyCodeToInteger(iso)
1411
if i < len(code) and code[i] == '[':
1412
j = code.find(']')
1413
dirchar=code[i:j+1]
1414
i = j+1
1415
else:
1416
dirchar='1'
1417
if i < len(code):
1418
number = int(code[i:])
1419
else:
1420
number = 1
1421
base_field='Q'
1422
return ModSym(level, weight, iso_class, dirchar, base_field, number)
1423
1424
def characters_are_known(N):
1425
query = "SELECT * FROM characters WHERE modulus = %s"%N
1426
x = db.query(query).dictresult()
1427
return len(x) > 0
1428
1429
def characters(N):
1430
query = "SELECT * FROM characters WHERE modulus = %s"%N
1431
x = db.query(query).dictresult()
1432
if len(x) == 0:
1433
chardata = magma.character_data(N)
1434
for eps in chardata:
1435
query = "insert into characters values(%s,'%s',%s,%s,%s)"%(eps[0],eps[1],eps[2],eps[3],eps[4])
1436
db.query(query)
1437
query = "SELECT * FROM characters WHERE modulus = %s ORDER BY degree"%N
1438
x = db.query(query).dictresult()
1439
if len(x) == 0:
1440
raise "Error inserting characters into database."
1441
return x
1442
1443
1444
1445
1446
1447
##############################################
1448
# #
1449
# Elliptic Curves #
1450
# #
1451
##############################################
1452
1453
class EllipticCurve(ModSym) :
1454
def __init__(self, _level, _iso_class, _number=1):
1455
self.level = _level
1456
self.iso_class = _iso_class
1457
self.weight = 2
1458
self.dirchar='1'
1459
self.base_field='Q'
1460
self.number = _number
1461
1462
f = self.ModularForm()
1463
i = db.query(("SELECT id FROM elliptic WHERE mod_id=%s AND number=%s")%\
1464
(f.id, self.number)).dictresult()
1465
if len(i) == 0: # insert new elliptic table entry
1466
db.query(("INSERT INTO elliptic(mod_id, number) " +\
1467
"VALUES(%s,%s)") % (f.id,self.number))
1468
i = db.query(("SELECT id FROM elliptic WHERE mod_id=%s AND number=%s")%\
1469
(f.id, self.number)).dictresult()
1470
self.id=i[0]['id']
1471
1472
def __repr__(self):
1473
return "The elliptic curve %s"%(self.code())
1474
1475
def ModularForm(self): # the corresponding modular form
1476
return ModSym(self.level, 2, self.iso_class)
1477
1478
def code(self):
1479
return "%s%s%s"%(self.level,misc.ToIsogenyCode(self.iso_class),self.number)
1480
1481
def change_iso_class(self, new_isoclass):
1482
raise "Don't call this."
1483
1484
def dimension(self):
1485
return 1
1486
def set_dimension(self, d):
1487
raise "Don't call this."
1488
1489
def dimension_new(self):
1490
return 1
1491
def set_dimension_new(self, d):
1492
raise "Don't call this."
1493
1494
def charpoly(self, n):
1495
raise "Don't call this yet."
1496
1497
def discriminant(self):
1498
return self.weierstrass_discriminant()
1499
1500
def set_discriminant(self):
1501
return self.set_weierstrass_discriminant()
1502
1503
def cusps(self):
1504
raise "Don't call this yet."
1505
def set_cusps(self, eqn):
1506
raise "Don't call this yet."
1507
1508
def hecke_field_discriminant(self):
1509
return 1
1510
def set_hecke_field_discriminant(self, eqn):
1511
raise "Don't call this yet."
1512
1513
def lratio(self):
1514
return [misc.parse_sqlarray(select(self, 'lratio', 'numerator'))[0], \
1515
misc.parse_sqlarray(select(self, 'lratio', 'denominator'))[0]];
1516
def set_lratio(self, numerator, denominator):
1517
insert(self, 'lratio', 'numerator', [numerator])
1518
insert(self, 'lratio', 'denominator', [denominator])
1519
1520
def lratio_odd(self):
1521
return [misc.parse_sqlarray(select(self, 'lratio_odd', 'numerator'))[0], \
1522
misc.parse_sqlarray(select(self, 'lratio_odd', 'denominator'))[0]];
1523
def set_lratio_odd(self, numerator, denominator):
1524
insert(self, 'lratio_odd', 'numerator', [numerator])
1525
insert(self, 'lratio_odd', 'denominator', [denominator])
1526
1527
1528
1529
def atkin_lehner(self):
1530
return self.ModularForm().atkin_lehner()
1531
def set_atkin_lehner(self, signs):
1532
raise "Don't call this."
1533
def traces(self):
1534
return self.ModularForm().traces()
1535
def set_traces(self, t):
1536
raise "Don't call this."
1537
def aplist(self, fname=""):
1538
return self.ModularForm().aplist(fname)
1539
def aplist_maxp(self):
1540
return self.ModularForm().aplist_maxp()
1541
def set_aplist(self, maxp, fname):
1542
return self.ModularForm().set_aplist(self,maxp,fname)
1543
def aplist_hecke_field(self):
1544
return 'x-1'
1545
def aplist_embedding(self):
1546
return '[1]'
1547
def aplist_dimension(self):
1548
return 1
1549
def q_expansion(self,prec=8):
1550
return self.ModularForm().q_expansion(prec)
1551
def q_integral_basis(self, prec=8):
1552
return self.ModularForm().q_integral_basis(8)
1553
def congruence_group(self, M, prec=8):
1554
return self.ModularForm().congruence_group(M,prec)
1555
def inner_twists(self, force_compute=0):
1556
return self.ModularForms().inner_twists(force_compute)
1557
1558
############################################
1559
1560
1561
def Get_Definition_From_Database(phrase):
1562
query = "SELECT definition FROM glossary WHERE phrase='%s'"%phrase
1563
out = db.query(query).dictresult()
1564
if len(out) == 0:
1565
return "Definition not yet written."
1566
s = out[0]["definition"]
1567
query = "SELECT source FROM glossary WHERE phrase='%s'"%phrase
1568
out = db.query(query).dictresult()
1569
if len(out) > 0:
1570
s = s + "<hr>Source of Definition: " + mfe_source.Link(out[0]["source"])
1571
return s
1572
1573
def List_Of_Words_Defined_In_Glossary():
1574
query = "SELECT phrase FROM glossary"
1575
out = db.query(query).dictresult()
1576
return [out[i]["phrase"] for i in range(len(out))]
1577