1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
from sage.schemes.elliptic_curves.ell_generic import is_EllipticCurve
# Pre-tests on E and P
def suitable( E, P, ell ):
if not is_EllipticCurve(E):
print "E is not an elliptic curve"
return False
if E.base_field() != QQ:
print "E is not defined over Q"
return False
if not P in E:
print "P is not in E"
return False
if P.has_finite_order():
print "P has finite order"
return False
if not is_prime(ell):
print "ell is not prime"
return False
return True
# Stupid auxiliary function. Returns higest power of n dividing m.
def val( n, m ):
ret = 0
while m % (n^(ret+1)) == 0:
ret += 1
return ret
# Valuation of l-divisibility of the point P
# The parameters h and k describe the ell-part of E(F) (k>=h)
def divisibility( P, ell, k, h ):
v = 0
while v != k-1 and P.is_divisible_by(ell^(v+1)):
v += 1
return v
# label is the Cremona label of an elliptic curve over Q of rank >= 1.
# ell is a rational prime.
def test_label( label, ell ):
E = EllipticCurve(label)
if E.rank() < 1:
print "E has rank 0"
return
P = E.gens()[0]
test( E, P, ell )
# E is an elliptic curve over Q and P a point of infinite order on E.
# ell is a rational prime.
def test( E, P, ell ):
if not suitable( E, P, ell ):
return
# Setting up for small primes cases
print "Computations for small primes starting..."
small_primes = []
vl = []
lpart = []
for p in Primes():
if p > 100:
break
if p == ell:
print "Skipping", p, "because = ell"
continue
if E.discriminant() % p == 0:
print "Skipping", p, "because E has bad reduction"
continue
if P.reduction(p).order() % ell != 0:
print "Skipping", p, "because red of P is infinitely ell-divisible"
continue
small_primes.append(p)
print "Working with prime p =", p
# "torsion level"
F = FiniteField(p)
vlj = []
lpj = []
for i in range(3): ### I WOULD LIKE TO CHANGE THIS TO SOMETHING BIGGER
print "Torsion level", i, "..."
# We can build the division fields for increasing powers of l
# incrementally. To get a division field, we first compute the
# splitting field of the division polynomial. We may be off by
# a degree 2 extension. If so, by finite field magic we know
# exactly which degree 2 extension we need: the unique one!
R.<x> = PolynomialRing(F)
F.<a> = E.reduction(p).division_polynomial(ell^i).splitting_field()
E_red = E.reduction(p).base_extend(F)
# extend if necessary
k = val(ell,E_red.gens()[0].order())
h = val(ell,E_red.order()) - k
if k < i or h < i:
F.<a> = F.extension(2)
E_red = E_red.base_extend(F)
P_red = E_red.point(P.reduction(p))
print "[Torsion field computed]"
# l-part of the abelian group E(F_i)
#gg = E_red.abelian_group().gens()
#if len( gg ) == 1:
# lpj.append( ( val(ell,gg[0].order()), 0 ) )
#else:
# lpj.append( (val(ell,gg[0].order()), val(ell,gg[1].order())) )
k = val(ell,E_red.gens()[0].order())
h = val(ell,E_red.order()) - k
lpj.append( ( k, h ) )
vlj.append(divisibility(P_red,ell,k,h))
vl.append(vlj)
lpart.append(lpj)
# Output
print "Done!"
for i in range(3):
print ""
print "******************************************************"
print "Torsion Level:", i
print ""
rows = [small_primes, [vl[j][i] for j in range(len(small_primes))],
[lpart[j][i] for j in range(len(small_primes))] ]
print table(rows)
print ""
# Wrapper for densities(E,P,ell)
def densities_label( label, ell ):
E = EllipticCurve(label)
if E.rank() < 1:
print "E has rank 0"
return
P = E.gens()[0]
densities( E, P, ell )
def ratio( h, k, d, ell ):
x1 = max(k-d,0)
y1 = max(h-d,0)
x2 = max(k-d-1,0)
y2 = max(h-d-1,0)
up = ell^(x1+y1)-ell^(x2+y2)
down = ell^(h+k)
if d == 0:
return RDF((up+1)/down)
return RDF(up/down)
# Computes the densities dens[n] of primes such that P is ell^n-divisible mod p
def densities( E, P, ell ):
if not suitable( E, P, ell ):
return
n_primes = 0
divisible = []
inf_divisible = 0
# Array for counting divisibility with specified l-part
div_part = [[[0 for i in range(10)] for j in range(10)] for k in range(10)]
# total number of elements in the reductions that (do not) form the l-parts
tot_l_part = 0
tot_non_l_part = 0
for p in Primes():
if p > 10^2:
break
if p == ell or E.discriminant() % p == 0:
continue
n_primes +=1
#print "Working with prime", p
E_red = E.reduction(p)
N = E_red.order()
k = val(ell,E_red.gens()[0].order())
h = val(ell,N) - k
temp_non_l_part = (N / (ell^(h+k)))-1
tot_non_l_part += temp_non_l_part
temp_l_part = N - temp_non_l_part
tot_l_part += temp_l_part
# Debug
# print "Group structure at", p, ":"
# print E_red.abelian_group()
# print "Our result:", N, (k,h), temp_l_part, temp_non_l_part
if P.reduction(p).order() % ell != 0:
inf_divisible += 1
continue
n = divisibility( P.reduction(p), ell, \
val(ell,E.reduction(p).gens()[0].order()), 0 ) # Wrong parameters but ok
while len(divisible) < n+1:
divisible.append(0)
divisible[n] += 1
div_part[k][h][n] += 1
N = len(divisible)
divtotal = [0]*N
divtotal[N-1] = divisible[N-1] + inf_divisible
for i in range(2,N):
divtotal[N-i] = divisible[N-i] + divtotal[N-i+1]
print "Tested primes:", n_primes
for i in range(10):
for j in range(10):
s = 0
for l in range(10):
s += div_part[i][j][l]
if s != 0:
print "l-part (%d,%d):"%(i,j)
for l in range(10):
if div_part[i][j][l] != 0:
print "Exactly %d^%d-divisible: %d, expected %0.3f"%\
(ell,l,div_part[i][j][l],ratio(i,j,l,ell))
for n in range(1,N):
print "At least %d^%d-divisble: %0.3f density (%d times)"%(ell,n,\
RDF(divtotal[n]/n_primes),divtotal[n])
print "Infinitely-divisble: %0.3f density (%d times), expected %0.3f"%\
(RDF(inf_divisible/n_primes),inf_divisible,\
RDF(tot_non_l_part/(tot_l_part+tot_non_l_part)))
|