Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
AndrewVSutherland
GitHub Repository: AndrewVSutherland/lmfdb
Path: blob/main/scripts/abvar/g1.m
1128 views
1
/*
2
Lists all labels of isogeny classes for genus 1 and Fq, where q is a prime
3
power ranging from 2 to 499, or q is in [512, 625, 729, 1024], except
4
for when q is divisible by 2 or 3, it only lists labels for abvars with j-invariants not 0.
5
6
For each label, and for each field of characteristic not 2 or 3,
7
it lists a canonical representative for each isomorphism class in the isogeny class.
8
9
For each label, and for each field of characteristic 2 or 3 and j-invariant not 0, 1728
10
it lists a representative for each isomorphism class in the isogeny class.
11
12
For characteristics 2 or 3 and j-invariant equal to 0 or 1728, we use
13
John Cremona's sage package to pick a favourite curve of each isomorphism class.
14
See g1_char23_j_0.sage.
15
*/
16
17
18
// returns the LMFDB label of the isogeny class determined by the l-poly f.
19
IsogenyLabel := function(E)
20
f := LPolynomial(E);
21
q := #BaseField(E);
22
23
g := Degree(f) div 2;
24
str1 := Reverse(Prune(Coefficients(f)))[1..g];
25
str2 := "";
26
for a in str1 do
27
if a lt 0 then
28
str2 := str2 cat "a" cat Base26Encode(-a) cat "_";
29
else
30
str2 := str2 cat Base26Encode(a) cat "_";
31
end if;
32
end for;
33
str2 := Prune(str2);
34
isog_label := Sprintf("%o.%o.",g,q) cat str2;
35
return isog_label;
36
end function;
37
38
39
EllCurveToString := function(E)
40
q := #BaseField(E);
41
k<a> := GF(q);
42
R<x> := PolynomialRing(k);
43
44
f, yCoeff := HyperellipticPolynomials(E);
45
46
if not (q mod 2 eq 0 or q mod 3 eq 0) then
47
// We assume that E is in magma's Weierstrass model. Hence the xy and y terms are 0.
48
assert IsWeierstrassModel(E);
49
assert yCoeff eq 0;
50
return "y^2 = " cat Sprint(f);
51
else
52
if yCoeff eq 0 then
53
return "y^2 = " cat Sprint(f);
54
elif yCoeff eq x then
55
return &cat["y^2 + x*y = ", Sprint(f)];
56
else
57
return &cat["y^2 + (", Sprint(yCoeff) ,")*y = ", Sprint(f)];
58
end if;
59
end if;
60
61
end function;
62
63
64
// A helper function to the first nonsquare c in the field
65
// where the order is determined by magma's default enumeration
66
Pickc := function(F)
67
for x in F do
68
if not x eq 0 and not IsSquare(x) then
69
return x;
70
end if;
71
end for;
72
return 0;
73
end function;
74
75
// For char not 2 or 3, j-invariant not 0 or 1728
76
// the following function returns an isomorphic model of the form
77
78
// y^2 = x^3 + Mx + M (if B/A is square)
79
// or
80
// y^2 = x^3 + Mx + cM (if B/A is non-square)
81
82
// by replacing (A,B) with (lambda^4*A, lambda^6*B)
83
// where lambda = (Sqrt(B/A)^(-1)) if (B/A) is square,
84
// (Sqrt((B/A)*c)^(-1)) otherwise
85
// c is a non-square nonzero field element determined by function Pickc
86
87
// For char not 2 or 3, j-invariant equals 0 or 1728,
88
// since those curves form a one-parameter family
89
// of the form y^2=x^3+Ax or y^2=x^3+B,
90
// the isomorphic curves are parametrized by lambda^4*A or lambda^6*B.
91
// We pick the smallest number in this parametrization as representative.
92
93
findIsomorphicRepresentative := function(E)
94
k := BaseField(E);
95
q := #BaseField(E);
96
if ((q mod 2) eq 0) or ((q mod 3) eq 0) then
97
// In this case, we don't find a canonical
98
// representative for its isomorphism class
99
100
newE := E;
101
elif jInvariant(E) eq (k!0) then
102
E := WeierstrassModel(E);
103
B:=Coefficients(E)[5];
104
// pick smallest [lambda^6 * B] where we cycle all lambda in k
105
repB := Min([lambda^6 * B : lambda in k| lambda ne 0]);
106
newE := EllipticCurve([0,0,0,0,repB]);
107
elif jInvariant(E) eq (k!1728) then
108
E := WeierstrassModel(E);
109
A:=Coefficients(E)[4];
110
// pick smallest [lambda^4 * A] where we cycle all lambda in k
111
repA := Min([lambda^4 * A : lambda in k| lambda ne 0]);
112
newE := EllipticCurve([0,0,0,repA,0]);
113
else
114
E := WeierstrassModel(E);
115
A := Coefficients(E)[4];
116
B := Coefficients(E)[5];
117
118
assert not (A eq 0) and not (B eq 0);
119
BoverA := B/A;
120
Lambda := 1;
121
122
c := Pickc(k);
123
124
if IsSquare(BoverA) then
125
Lambda := (Sqrt(BoverA))^(-1);
126
else
127
Lambda := Sqrt((BoverA)^(-1)*(c));
128
end if;
129
130
newE := EllipticCurve([0,0,0,Lambda^4*A, Lambda^6*B]);
131
end if;
132
133
// validity check
134
assert IsogenyLabel(E) eq IsogenyLabel(newE);
135
return newE;
136
end function;
137
138
139
EnumerateIsogenyClassesG1 := function(q)
140
// generate one representative for each j-invariant,
141
// and for each representative, generate all its twists.
142
k := GF(q);
143
if (q mod 2 eq 0) or (q mod 3 eq 0) then
144
jInvReps := [EllipticCurveFromjInvariant(j) : j in k | not j in [k!0, k!1728]];
145
else
146
jInvReps := [EllipticCurveFromjInvariant(j) : j in k];
147
end if;
148
allEllCurves := &cat[Twists(E): E in jInvReps];
149
150
/*
151
In the case that char is 2 or 3, we don't have a canonical class,
152
so it's always good to check that it is not isomorphic to any existing curves
153
*/
154
if (q mod 2 eq 0) or (q mod 3 eq 0) then
155
nonIsoCurves := [];
156
for E in allEllCurves do
157
if &or[IsIsomorphic(E,existingCurve) : existingCurve in nonIsoCurves] then
158
break;
159
end if;
160
Append(~nonIsoCurves, E);
161
end for;
162
allEllCurves := nonIsoCurves;
163
end if;
164
165
labelToCurves := AssociativeArray();
166
for E in allEllCurves do
167
label := IsogenyLabel(E);
168
if not label in Keys(labelToCurves) then
169
labelToCurves[label] := Set([]);
170
end if;
171
Include(~labelToCurves[label], EllCurveToString(findIsomorphicRepresentative(E)));
172
end for;
173
return labelToCurves;
174
end function;
175
176
// Now, generate the data for prime powers 2 <= q <= 499, and q in {512, 625, 729, 1024},
177
DictionaryToFile := procedure(g, q, ~D, filename)
178
Write(filename, "\n");
179
Write(filename, &cat["(g, q)= (", Sprint(g),",",Sprint(q),")"]);
180
for key in Keys(D) do
181
output := key cat "|" cat Sprint(D[key]);
182
output := StripWhiteSpace(output);
183
Write(filename, output);
184
end for;
185
end procedure;
186
187
PrimePowers:=[2..499] cat [512, 625, 729, 1024];
188
189
// It outputs data into two files:
190
// {label|isomorphism classes} -> outputFilename, this is the actual data
191
// {q, # of labels for each q} -> countsFilename, this is used for checking the consistency with lmfdb
192
OutputAllData := procedure(qs, outputFilename, countsFilename)
193
QLabelPairs := [];
194
Write(outputFilename, "\n" : Overwrite:=true);
195
Write(countsFilename, "\n" : Overwrite:=true);
196
for q in qs do
197
if IsPrimePower(q) then
198
results := EnumerateIsogenyClassesG1(q);
199
DictionaryToFile(1,q,~results,outputFilename);
200
Append(~QLabelPairs, [q, #Keys(results)]);
201
end if;
202
end for;
203
204
Write(countsFilename, "The following are (q, #of labels produced) pairs");
205
Write(countsFilename, "WARNING: for char 2 or 3, j = 0 or 1728, labels are not presented here.");
206
for qLabelPair in QLabelPairs do
207
Write(countsFilename, &cat[Sprint(qLabelPair[1]), ",", Sprint(qLabelPair[2])]);
208
end for;
209
end procedure;
210
211
OutputAllData(PrimePowers, "output.txt", "counts.txt");
212
213