Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 184606
1
from psage.number_fields.sqrt5.misc import *
2
from psage.lseries.eulerprod import LSeriesEllipticCurve, LSeriesEllipticCurveSqrt5, LSeriesTwist
3
4
def _iter__OK_mod_p(OK,P):
5
M = P.pari_hnf().sage().diagonal()
6
from itertools import product
7
reps = product(*map(range,M))
8
B = OK.basis()
9
return [sum(i*j for i,j in zip(r,B)) for r in reps]
10
11
def totally_positive_generator(p):
12
K = p.ring()
13
units = K.unit_group().gens()
14
x = p.gens_reduced()
15
assert len(x)==1, "p not pricipally generated!"
16
x = x[0]
17
M = Matrix(GF(2),[[phi(g)<0 for phi in K.real_embeddings()] for g in units])
18
v = vector(GF(2),[phi(x)<0 for phi in K.real_embeddings()])
19
x *= prod(g for g,e in zip(units,M.solve_left(v)) if e)
20
assert x.is_totally_positive(), "Totally positive generator does not exist!"
21
return x
22
23
# Given an element of a number field and a modulus prod primes returns
24
def rep(alpha, primes):
25
return [p.ideallog(alpha)[0] for p in primes]
26
27
# Hecke characters of number fields
28
class NFChar():
29
# Initialise a new Hecke character of order order, factored conductor should be a list of primes,
30
# rootlist a list of integers of the same length that describe the power of zeta that the gene
31
def __init__(self, factored_conductor, rootlist, order, zeta = None, prec = None):
32
assert all(p.is_prime() for p in factored_conductor), "factored_conductor contains an element that is not prime"
33
assert len(set(factored_conductor)) == len(factored_conductor), "factored_conductor contains duplicate elements"
34
assert len(rootlist) == len(factored_conductor), "rootlist and factored_conductor should be the same length"
35
self._factored_conductor = factored_conductor
36
self._primes_conductor = [p.smallest_integer() for p in factored_conductor]
37
self._conductor = prod(factored_conductor)
38
self._m = totally_positive_generator(self._conductor)
39
self._rootlist = rootlist
40
assert gcd(rootlist+[order])==1, "the order of the character is not %s"%(order)
41
self._field = factored_conductor[0].number_field()
42
self._ring = self._field.maximal_order()
43
self._degree = self._field.absolute_degree()
44
self._order = order
45
if prec == None:
46
self._CC = CC
47
else:
48
self._CC = ComplexField(prec)
49
if zeta is None:
50
self._zeta = self._CC.zeta(order)
51
else:
52
#assert zeta**d==1,"order of zeta does not appear to be %s"%order
53
self._zeta = zeta
54
55
assert self._field.class_number()==1,"Class number of base field is not 1"
56
57
for p in factored_conductor:
58
assert ZZ(order).divides(p.norm() - 1), "order %s does not divide order of (O/%s)^*, which is %s"%(order,p,p.norm()-1)
59
60
self._pows = [self._zeta**d for d in range(order)]
61
62
if False:
63
self._logs = dict()
64
for p in self._factored_conductor:
65
self._logs[p] = dict()
66
kp = p.residue_field()
67
for x in kp:
68
if x == 0:
69
continue
70
self._logs[p][x] = p.ideallog(kp.lift(x))[0]
71
72
for g in self._field.unit_group().gens():
73
assert self._call_nf_elt(self._field(g)) == 1, " character is not 1 on units"
74
75
76
def __call__(self, p):
77
p = self._field.ideal(p)
78
x = p.gens_reduced()
79
assert len(x)==1, "Do not know how to evaluate on a non principal ideal!"
80
return self._call_nf_elt(p.gens_reduced()[0])
81
82
@cached_method
83
def _iter_rep_mod_m(self):
84
return _iter__OK_mod_p(self._ring,self._conductor)
85
86
87
def _call_nf_elt(self, alpha):
88
fact = self._factored_conductor
89
rootlist = self._rootlist
90
91
for p,q in zip(self._primes_conductor,fact):
92
if p.divides(alpha.norm()) and alpha in q:
93
return 0
94
#return m.ideallog(p.gens_reduced()[0])
95
if False: # new
96
reps = [self._logs[p][p.residue_field()(alpha)] for p in fact]
97
reps = rep(alpha, [prime for prime in fact])
98
99
return self._pows[sum([rootlist[i]*reps[i] for i in range(len(rootlist))]) % self._order]
100
101
def gauss_sum(self):
102
assert self._ring.discriminant()==5, "only implemented for sqrt5"
103
tau = 0
104
sqrt5 = (self._field*5).factor()[0][0].gens_reduced()[0]
105
#print sqrt5
106
for alpha in self._iter_rep_mod_m():
107
#print tau
108
a = alpha/self._m#*sqrt5
109
a = a.trace()
110
den = a.denominator()
111
num = a.numerator()
112
tau += self._call_nf_elt(alpha)*self._CC.zeta(den)^(num%den)
113
return tau
114
115
def conjugate(self):
116
return NFChar(self._factored_conductor, [-d for d in self._rootlist], self._order, self._zeta, self._CC.prec())
117
118
def is_primitive(self):
119
return all(i%self._order != 0 for i in self._rootlist)
120
121
def conductor(self):
122
K = self._factored_conductor[0].number_field()
123
return ZZ(prod(self._factored_conductor).norm())#*K.discriminant())
124
125
def order(self):
126
return self._order
127
128
def __repr__(self):
129
return "Hecke character of modulus %s and order %s"%(self._conductor,self._order)
130
131
# Search for all characters of the base field of E (which for now must be Qsqrt5) that are
132
# of order D and have conductor norm less than bound, for each pair of complex conjugate characters, only 1 is used.
133
# When a character is found the twist is computed (and optionally the functional equation checked)
134
# then the twist is evaluated at 1 and the result is printed and added to a list, which is returned.
135
def value_search(E, D, bound, checkfe=False, lower=0, prec=None):
136
LE = LSeriesEllipticCurveSqrt5(E)
137
omega = prod([E.period_lattice(phi).basis(prec=1000)[0] for phi in F.embeddings(RR)])
138
ideals = E.base_field().ideals_of_bdd_norm(bound)
139
chis = []
140
#print len(ideals),ideals
141
if prec is None:
142
one = CC(1)
143
else:
144
one = ComplexField(prec)(1)
145
# we could also use for m in E.base_field().primes_of_bounded_norm_iter(bound):
146
for nm in ideals:
147
if nm < lower:
148
continue
149
if nm % 5 == 0 or nm % 31 == 0:
150
continue
151
for m in ideals[nm]:
152
if nm == 1:
153
continue
154
fact = [prime for (prime, i) in m.factor()]
155
if max([i for (prime, i) in m.factor()]) > 1:
156
continue
157
for t in Integers(D)^len(fact):
158
try:
159
if 0 in list(t):
160
continue
161
if t[0].lift() > D/2: # Only take one character in each conjugacy class
162
continue
163
rootlist = list(t.lift())
164
chi = NFChar(fact,rootlist,D, CC.zeta(D))
165
print m,m.norm(),m.factor(), rootlist
166
chis += [chi]
167
168
except AssertionError: # Character didn't work, try the next
169
pass
170
except RuntimeError:
171
print "Error, maybe conductor was wrong?!"
172
173
print len(chis),"characters to be evaluated"
174
# "prime" the base L-series by computing the biggest character so as much as possible is cached at the start
175
try_chi(LE,chis[-1],omega,checkfe=checkfe,one=one)
176
# TODO don't recompute this in the parallel computation!
177
out = [(inp[0][1],)+out for inp,out in try_chi([((LE,chi,omega),{"checkfe":checkfe,"one":one}) for chi in chis])]
178
# parallel might have reordered chis so we need outchis too
179
outchis, values, n_values = zip(*out)
180
return (values, n_values, outchis)
181
182
@parallel#(p_iter="reference")
183
def try_chi(LE, chi, omega, one=None,checkfe=False):
184
LEchi = LE.twist(chi,epsilon='solve')
185
if one == None:
186
one = CC(1)
187
if checkfe:
188
LEchi.check_functional_equation(1.2)
189
LEchi.check_functional_equation(1.1)
190
val = LEchi(one)
191
print "raw value",val
192
normalised = val*chi.conjugate().gauss_sum()*CC(sqrt(5))/omega
193
print "normalised",normalised
194
print "algdeprts",algdep(normalised, 2, known_bits=53).roots(CC)
195
return (val, normalised)
196