Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
/*********************************************************************
2
3
(c) Copyright 2006-2010 Salman Baig and Chris Hall
4
5
This file is part of ELLFF
6
7
ELLFF is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
11
12
ELLFF is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
16
17
You should have received a copy of the GNU General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
*********************************************************************/
21
22
#include <assert.h>
23
#include <string.h>
24
#include <fstream>
25
#include <iostream>
26
#include <sstream>
27
using std::ostringstream;
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <NTL/lzz_p.h>
31
#include <NTL/lzz_pE.h>
32
#include <NTL/lzz_pX.h>
33
#include <NTL/lzz_pEX.h>
34
#include <NTL/ZZ.h>
35
#include <NTL/ZZ_pEX.h>
36
37
#include "helper.h"
38
#include "ell.h"
39
#include "ell_surface.h"
40
#include "euler.h"
41
#include "lzz_pEExtra.h"
42
43
NTL_CLIENT
44
45
// given tau in F_q compute the 'trace of Frob_q' for the curve
46
// y^2=x^3+a4*x+a6 over the residue field F_q(tau). if D!=0, then
47
// curve is assumed to be smooth. otherwise, distinguishes between
48
// mult've and add've red'n and computes correct trace. (D=disc)
49
50
long trace_tau(zz_pE& tau, ell_surfaceInfoT::affine_model& model)
51
{
52
static zz_pE a4_tau, a6_tau, b, e;
53
54
// additive reduction
55
if (IsZero(eval(model.A, tau)))
56
return 0;
57
58
// split multiplicative reduction
59
if (IsZero(eval(model.M_sp, tau)))
60
return +1;
61
62
// non-split multiplicative reduction
63
if (IsZero(eval(model.M_ns, tau)))
64
return -1;
65
66
// good red'n
67
a4_tau = eval(model.a4, tau);
68
a6_tau = eval(model.a6, tau);
69
ell_pE::init(a4_tau, a6_tau);
70
71
long order = ell_pE::order();
72
static ZZ trace;
73
trace = zz_pE::cardinality()+1-order;
74
assert(trace.WideSinglePrecision());
75
return to_long(trace);
76
}
77
78
// compute Euler factors for range of tau in P^1(F_q)
79
//
80
// inputs:
81
// E - elliptic surface
82
// table - array of length >= max_tau-min_tau+1 to store traces of Frob
83
// min_tau..max_tau - subrange of [0..q] correspond to points in P^1(F_q)
84
//
85
// TODO:
86
// - rewrite to take advantage of (constant) field of definition for
87
// (coeffs) of E so that only need to compute one trace in each
88
// Galois orbit of taus
89
// - allow previous speed-up to be avoided so that we can test that
90
// each tau in an orbit gets the same trace
91
92
void euler_table(long *table, long min_tau, long max_tau,
93
int frob_deg)
94
{
95
static zz_pE tau, tau_0;
96
long ul_tau, ul_tau_0, q;
97
98
q = ell_surfaceInfo->q;
99
assert(min_tau >= 0 && min_tau <= max_tau && max_tau <= q);
100
assert(frob_deg == -1 || frob_deg > 0);
101
assert(frob_deg == -1 || (min_tau == 0 && max_tau == q));
102
103
// enumerate all elements of P^1(F_q) in given range
104
from_ulong(min_tau, tau);
105
for (ul_tau = 0; ul_tau <= max_tau-min_tau; ul_tau++) {
106
// finite tau use a different model than tau=infty
107
if (ul_tau + min_tau < q) {
108
if (frob_deg != -1) {
109
// test Frobenius map
110
if (false) {
111
tau_0 = tau;
112
for (int i = 0; i < zz_pE::degree(); i++)
113
zz_pEExtraInfo->frobenius(tau_0, tau_0);
114
assert(tau_0 == tau);
115
}
116
if (false && zz_pEExtraInfo->frob_map != NULL) {
117
ul_tau_0 = ul_tau;
118
for (int i = 0; i < zz_pE::degree(); i++)
119
ul_tau_0 = zz_pEExtraInfo->frobenius(ul_tau_0);
120
assert(tau_0 == tau);
121
}
122
123
if (zz_pEExtraInfo->frob_map != NULL) {
124
ul_tau_0 = ul_tau;
125
do {
126
for (int i = 0; i < frob_deg; i++)
127
ul_tau_0 =
128
zz_pEExtraInfo->frobenius(ul_tau_0);
129
} while (ul_tau_0 > ul_tau);
130
} else {
131
tau_0 = tau;
132
do {
133
for (int i = 0; i < frob_deg; i++)
134
zz_pEExtraInfo->frobenius(tau_0, tau_0);
135
ul_tau_0 = to_ulong(tau_0);
136
} while (ul_tau_0 > ul_tau);
137
}
138
if (ul_tau_0 < ul_tau)
139
table[ul_tau] = table[ul_tau_0];
140
else
141
table[ul_tau]
142
= trace_tau(tau,
143
ell_surfaceInfo->finite_model);
144
} else
145
table[ul_tau]
146
= trace_tau(tau, ell_surfaceInfo->finite_model);
147
} else {
148
assert(IsZero(tau));
149
table[ul_tau]
150
= trace_tau(tau, ell_surfaceInfo->infinite_model);
151
}
152
153
// increment to next tau for next iteration through loop
154
if (ul_tau < max_tau-min_tau)
155
inc(tau);
156
}
157
}
158
159
// compute Euler factors for current elliptic surface, regarded as a twist
160
161
void twist_table(const zz_pEX& f, long *untwisted_table, long *twisted_table,
162
long min_tau, long max_tau)
163
{
164
zz_pE tau, f_of_tau;
165
long ul_tau, q;
166
167
q = ell_surfaceInfo->q;
168
assert(min_tau >= 0 && min_tau <= max_tau && max_tau <= q);
169
170
// enumerate all elements of P^1(F_q) in given range
171
from_ulong(min_tau, tau);
172
for (ul_tau = 0; ul_tau <= max_tau-min_tau; ul_tau++) {
173
// finite tau use a different model than tau=infty
174
ell_surfaceInfoT::affine_model *model;
175
if (ul_tau + min_tau < q)
176
model = &(ell_surfaceInfo->finite_model);
177
else {
178
assert(IsZero(tau));
179
model = &(ell_surfaceInfo->infinite_model);
180
}
181
182
if (eval(model->A, tau) == 0) // additive
183
twisted_table[ul_tau] = 0;
184
else if (eval(model->M_sp, tau) == 0) // split multiplicative
185
twisted_table[ul_tau] = +1;
186
else if (eval(model->M_ns, tau) == 0) // non-split multiplicative
187
twisted_table[ul_tau] = -1;
188
else { // good
189
// determine twisting character at tau
190
// - at finite tau want chi(f(tau))
191
// - at tau=infty, want chi(g(0)) for g(u)=u^(deg(f)+e)*f(1/u)
192
// where e in {0,1} satisfies deg(f)=e (mod 2)
193
if (ul_tau + min_tau < q)
194
f_of_tau = eval(f, tau);
195
//else if (deg(f) == 0)
196
//f_of_tau = 0;
197
else
198
f_of_tau = LeadCoeff(f);
199
200
// if untwisted model has bad reduction but twisted has good
201
// reduction, need to calculate Euler factor from scratch
202
if (f_of_tau == 0)
203
twisted_table[ul_tau] = trace_tau(tau, *model);
204
else {
205
static int chi, sign;
206
207
chi = zz_pEExtraInfo->legendre_char(f_of_tau);
208
sign = (chi == 1) ? 1 : -1;
209
210
twisted_table[ul_tau] = sign * untwisted_table[ul_tau];
211
}
212
}
213
214
// increment to next tau for next iteration through loop
215
if (ul_tau < max_tau-min_tau)
216
inc(tau);
217
}
218
}
219
220
// compute Euler factors for current elliptic surface, regarded as a pullback
221
222
void pullback_table(const zz_pEX& finite_disc, const zz_pEX& infinite_disc,
223
const zz_pEratX& f, long *base_table, long *pullback_table,
224
long min_tau, long max_tau)
225
{
226
zz_pE tau, f_of_tau;
227
long ul_tau, q;
228
229
q = ell_surfaceInfo->q;
230
assert(min_tau >= 0 && min_tau <= max_tau && max_tau <= q);
231
232
// enumerate all elements of P^1(F_q) in given range
233
from_ulong(min_tau, tau);
234
for (ul_tau = 0; ul_tau <= max_tau-min_tau; ul_tau++) {
235
// finite tau use a different model than tau=infty
236
static ell_surfaceInfoT::affine_model *model;
237
static zz_pEX base_disc;
238
if (ul_tau + min_tau < q) {
239
model = &(ell_surfaceInfo->finite_model);
240
base_disc = finite_disc;
241
} else {
242
assert(IsZero(tau));
243
model = &(ell_surfaceInfo->infinite_model);
244
base_disc = infinite_disc;
245
}
246
247
int debug = -1;
248
if (eval(model->A, tau) == 0) { // additive
249
pullback_table[ul_tau] = 0;
250
debug = 0;
251
}
252
else if (eval(model->M_sp, tau) == 0) { // split multiplicative
253
pullback_table[ul_tau] = +1;
254
debug = 1;
255
}
256
else if (eval(model->M_ns, tau) == 0) { // non-split multiplicative
257
pullback_table[ul_tau] = -1;
258
debug = 2;
259
}
260
else { // good
261
// if base model has bad reduction but pullback has good
262
// reduction, need to calculate Euler factor from scratch
263
if (eval(base_disc, tau) == 0)
264
pullback_table[ul_tau] = trace_tau(tau, *model);
265
else {
266
static unsigned long ul_base;
267
static zz_pE den_of_tau;
268
den_of_tau = eval(f.den, tau);
269
if (IsZero(den_of_tau))
270
ul_base = q;
271
else {
272
f_of_tau = eval(f.num, tau) / den_of_tau;
273
ul_base = to_ulong(f_of_tau);
274
}
275
pullback_table[ul_tau] = base_table[ul_base];
276
}
277
}
278
#if 0
279
long test_trace = trace_tau(tau, *model);
280
assert(pullback_table[ul_tau] == test_trace);
281
#endif
282
283
// increment to next tau for next iteration through loop
284
if (ul_tau < max_tau-min_tau)
285
inc(tau);
286
}
287
}
288
289
void compute_c_n(ZZ **b, ZZ **c, int n)
290
{
291
c[n][0] = 0;
292
for (int m = 1; m <= n; m++)
293
c[n][0] += b[m][0] * c[n-m][0];
294
assert(c[n][0] % n == 0);
295
c[n][0] /= n;
296
}
297
298
void sum_table(ZZ& sum, long *table, long min, long max)
299
{
300
sum = 0;
301
for (long i = min; i <= max; i++)
302
sum += table[i];
303
}
304
305
void compute_b_n(ZZ& b_n)
306
{
307
// compute traces over Frobenius
308
long q = to_ulong(zz_pE::cardinality()), i;
309
310
// XXX : rewrite the following to allocate less memory and make
311
// extra invocations to euler_table
312
313
long *trace_table = (long*)malloc(sizeof(long)*(q+1));
314
euler_table(trace_table, 0, q);
315
316
b_n = 0;
317
for (i = 0; i <= q; i++)
318
b_n += trace_table[i];
319
320
free(trace_table);
321
}
322
323
#ifdef MAIN
324
int main(int argc, char **argv)
325
{
326
long p, d, s, i;
327
ofstream output;
328
329
if (argc != 4) {
330
cerr << "Usage: " << argv[0] << " s p d\n";
331
return -1;
332
}
333
334
s = atol(argv[1]);
335
p = atol(argv[2]);
336
d = atol(argv[3]);
337
338
if (s >= 8 || s < -1) {
339
cerr << "Switch parameter must be in {-1,...,7}. "
340
<< "You inputted " << s << ".\n";
341
return -1;
342
}
343
344
if (p == 3)
345
assert(s == 0 || s == 2);
346
347
#if VERBOSE
348
cout << "--------------------------\n";
349
switch(s) {
350
case -1: cout << "\tE=custom\n"; break;
351
case 0: cout << "\tE=E_Leg\n"; break;
352
case 1: cout << "\tE=X_211\n"; break;
353
case 2: cout << "\tE=X_321\n"; break;
354
case 3: cout << "\tE=X_431\n"; break;
355
case 4: cout << "\tE=E_Hes\n"; break;
356
case 5: cout << "\tE=E_Vil\n"; break;
357
case 6: cout << "\tE=E_Hal\n"; break;
358
case 7: cout << "\tE=E_j\n"; break;
359
}
360
#endif // VERBOSE
361
362
#if 1
363
int max_d = d;
364
365
// setup finite fields
366
zz_pEContext ff_contexts[d];
367
zz_pEExtraContext ff_extras_contexts[d];
368
for (d = 1; d <= max_d; d++) {
369
init_NTL_ff(p, d, 1, 1, 1);
370
ff_contexts[d-1].save();
371
ff_extras_contexts[d-1].save();
372
}
373
374
ZZ untwisted_traces[d+1], twisted_traces[d+1], pullback_traces[d+1];
375
376
untwisted_traces[0] = 0;
377
twisted_traces[0] = 0;
378
pullback_traces[0] = 0;
379
380
int untwisted_sign = 0, twisted_sign = 0, pullback_sign = 0;
381
int untwisted_deg = -1, twisted_deg = -1, pullback_deg = -1;
382
for (d = 1; d <= max_d; d++) {
383
// set current prime field to F_p
384
ff_contexts[d-1].restore();
385
ff_extras_contexts[d-1].restore();
386
387
long q = to_long(zz_pE::cardinality());
388
389
// setup elliptic surface
390
zz_pEX t;
391
zz_pEratX a4, a6;
392
t = 1; t <<= 1;
393
switch (s) {
394
case 0: a4.init(-27*t*t*((t - 1)*t + 1));
395
a6.init(27*t*t*t*(((2*t-3)*t-3)*t+2));
396
break;
397
case 1: a4.init(-27*t*t*t*t);
398
a6.init(54*t*t*t*t*t*(t-2));
399
break;
400
case 2: a4.init(108*t*t*t*(3-4*t));
401
a6.init(432*t*t*t*t*t*(8*t-9));
402
break;
403
case 3: a4.init(t*t*t*(24-27*t));
404
a6.init(t*t*t*t*((54*t-72)*t+16));
405
break;
406
case 4: a4.init(3*t*(8-9*t*t*t));
407
a6.init((54*t*t*t - 72)*t*t*t + 16);
408
break;
409
case 5: a4.init(6*t-27);
410
a6.init((t-18)*t+54);
411
break;
412
case 6: a4.init(-3*t*t*t*(t+8));
413
a6.init(-2*t*t*t*t*((t-20)*t-8));
414
break;
415
case 7: a4.init(- 27*t*(t-1728)*(t-1728)*(t-1728));
416
a6.init(54*t*(t-1728)*(t-1728)*(t-1728)*(t-1728)*(t-1728));
417
break;
418
default : assert(0);
419
}
420
ell_surface::init(a4, a6);
421
422
// compute traces over Frobenius
423
long *trace_table = (long*)malloc(sizeof(long)*(q+1));
424
euler_table(trace_table, 0, q);
425
426
// compute the sum of the traces
427
for (untwisted_traces[d] = 0, i = 0; i <= q; i++)
428
untwisted_traces[d] += trace_table[i];
429
430
// calculate sign of functional equation
431
int sign_fe;
432
sign_fe = ell_surfaceInfo->sign;
433
if (d == 1) {
434
untwisted_sign = sign_fe;
435
untwisted_deg = ell_surfaceInfo->deg_L;
436
}
437
438
#if VERBOSE
439
cout << "d = " << d << endl;
440
cout << "q = " << q << endl;
441
cout << "untwisted sum of traces = " << untwisted_traces[d] << " : ";
442
cout << "sign_fe = " << sign_fe << " : " << endl;
443
#endif
444
445
// save info for untwisted curve
446
ell_surfaceContext untwisted_curve;
447
untwisted_curve.save();
448
449
// do same for twisted curve
450
long *twist_trace_table = (long*)malloc(sizeof(long)*(q+1));
451
zz_pEX f;
452
// f = 1; f <<= 1; f -= 1; // f = t-1
453
// f = 1; f <<= 1; f -= 2; // f = t-2
454
f = 1; f <<= 1; // f = t
455
456
// calculate minimal Weierstrass model, etc. for twisted surface
457
zz_pEX twist_a4 = ell_surfaceInfo->finite_model.a4*f*f;
458
zz_pEX twist_a6 = ell_surfaceInfo->finite_model.a6*f*f*f;
459
ell_surface::init(twist_a4, twist_a6);
460
461
twist_table(f, trace_table, twist_trace_table, 0, q);
462
463
// compute the sum of the traces
464
twisted_traces[d] = 0;
465
for (i = 0; i <= q; i++)
466
twisted_traces[d] += twist_trace_table[i];
467
468
// calculate sign of functional equation
469
sign_fe = ell_surfaceInfo->sign;
470
if (d == 1) {
471
twisted_sign = sign_fe;
472
twisted_deg = ell_surfaceInfo->deg_L;
473
}
474
475
#if VERBOSE
476
cout << "twisted sum of traces = " << twisted_traces[d] << " : ";
477
cout << "sign_fe = " << sign_fe << " : " << endl;
478
#endif
479
480
// restore info for untwisted curve
481
untwisted_curve.restore();
482
483
// do same for pullback curve
484
long *pullback_trace_table = (long*)malloc(sizeof(long)*(q+1));
485
zz_pEX num, den;
486
zz_pEratX g;
487
// num = 1; den = num <<= 1; num -= 1; // (t-1)/t
488
// den = num = 1; num <<= 2; // t^2
489
// den = num = 1; num <<= 2; num += 1; // t^2+1
490
// den = num = 1; num <<= 3; // t^3
491
// den = num = 1; num <<= 3; num += 1; // t^3+1
492
// den = num = 1; num <<= 4; // t^4
493
den = num = 1; num <<= 4; num += 1; // t^4+1
494
g.init(num, den);
495
#if 0
496
if (d == 1)
497
cout << "g = " << g.num << "/" << g.den << endl;
498
#endif
499
500
// keep track of discriminant divisor for untwisted surface
501
zz_pEX finite_disc = ell_surfaceInfo->finite_model.disc;
502
zz_pEX infinite_disc = ell_surfaceInfo->infinite_model.disc;
503
504
// calculate minimal Weierstrass model, etc. for twisted surface
505
zz_pEratX pullback_a4 = eval(ell_surfaceInfo->finite_model.a4, g);
506
zz_pEratX pullback_a6 = eval(ell_surfaceInfo->finite_model.a6, g);
507
ell_surface::init(pullback_a4, pullback_a6);
508
509
#if 0
510
for (i = 0; d == 1 && i < 2; i++) {
511
ell_surfaceInfoT::affine_model *model;
512
513
model = (i == 0) ? &(ell_surfaceInfo->finite_model)
514
: &(ell_surfaceInfo->infinite_model);
515
//if (i == 0)
516
//cerr << "j = " << model->j.num << "/"
517
//<< model->j.den << endl;
518
cerr << "M = " << model->M_sp*model->M_ns << endl;
519
cerr << "A = " << model->A << endl;
520
cerr << endl;
521
//cerr << endl;
522
//cerr << "I_star = " << model->I_star << endl;
523
//cerr << "II = " << model->II << endl;
524
//cerr << "II_star = " << model->II_star << endl;
525
//cerr << "III = " << model->III << endl;
526
//cerr << "III_star = " << model->III_star << endl;
527
//cerr << "IV = " << model->IV << endl;
528
//cerr << "IV_star = " << model->IV_star << endl;
529
}
530
#endif
531
532
pullback_table(finite_disc, infinite_disc, g, trace_table,
533
pullback_trace_table, 0, q);
534
535
// compute the sum of the traces
536
pullback_traces[d] = 0;
537
for (i = 0; i <= q; i++)
538
pullback_traces[d] += pullback_trace_table[i];
539
540
// calculate sign of functional equation
541
sign_fe = ell_surfaceInfo->sign;
542
if (d == 1) {
543
pullback_sign = sign_fe;
544
pullback_deg = ell_surfaceInfo->deg_L;
545
}
546
547
untwisted_curve.restore();
548
549
#if VERBOSE
550
cout << "pullback sum of traces = " << pullback_traces[d] << " : ";
551
cout << "sign_fe = " << sign_fe << " : " << endl;
552
#endif
553
}
554
assert(untwisted_sign != 0 && twisted_sign != 0);
555
556
// convert traces to L-functions
557
cout << "signs = " << untwisted_sign << ", " << twisted_sign
558
<< ", " << pullback_sign;
559
cout << "; degrees = " << untwisted_deg << ", " << twisted_deg
560
<< ", " << pullback_deg << endl;
561
for (i = 0; i < 3; i++) {
562
ZZ *b;
563
int deg_L, sign;
564
565
switch (i) {
566
case 0 : b = untwisted_traces;
567
deg_L = untwisted_deg;
568
sign = untwisted_sign;
569
break;
570
case 1 : b = twisted_traces;
571
deg_L = twisted_deg;
572
sign = twisted_sign;
573
break;
574
case 2 : b = pullback_traces;
575
deg_L = pullback_deg;
576
sign = pullback_sign;
577
break;
578
default : assert(0);
579
}
580
581
ZZ c[max_d+1];
582
c[0] = 1;
583
584
int n, N = max_d;
585
for (n = 1; n <= N; n++)
586
compute_c_n(b, c, n);
587
588
ZZX L_fcn;
589
for (n = 0; n <= N; n++)
590
SetCoeff(L_fcn, n, c[n]);
591
592
// use rest of functional equation to determine remainder of L-fcn
593
if (2*N >= deg_L) {
594
ZZ q;
595
ff_contexts[0].restore();
596
q = zz_pE::cardinality();
597
598
ZZ m;
599
if (deg_L % 2 == 1)
600
m = q;
601
else
602
m = 1;
603
m *= sign;
604
for (d = (deg_L+1)/2; d <= deg_L; d++, m *= q*q) {
605
ZZ actual_c = coeff(L_fcn, d);
606
SetCoeff(L_fcn, d, coeff(L_fcn, deg_L-d)*m);
607
assert(d > N || actual_c == coeff(L_fcn, d));
608
}
609
}
610
611
switch (i) {
612
case 0 : cout << "untwisted "; break;
613
case 1 : cout << "twisted "; break;
614
case 2 : cout << "pullback "; break;
615
default : assert(0);
616
}
617
cout << "L-function : " << L_fcn << endl;
618
}
619
620
#else
621
init_NTL_ff(p, d);
622
623
for (q = 1, i = 0; i < d; i++)
624
q *= p;
625
626
//cout << "pi = " << pi << "\n";
627
628
zz_pE tau;
629
long e_infty;
630
zz_pX a4_tau, a6_tau, D_tau;
631
632
// precompute a4, a6 of model y^2 = x^3 + a4*x + a6
633
static zz_pX t;
634
t = 1; t <<= 1;
635
636
switch (s) {
637
case 0:
638
if(p != 3) {
639
a4_tau = -27*t*t*((t - 1)*t + 1);
640
a6_tau = 27*t*t*t*(((2*t-3)*t-3)*t+2);
641
e_infty = 1; break;
642
}
643
else { // not correct model yet
644
a4_tau = - 27*t*t*((t-1)*t+1)/81;
645
a6_tau = 27*t*t*t*(((2*t-3)*t-3)*t+2)/729;
646
e_infty = 1; break;
647
}
648
case 1: a4_tau = -27*t*t*t*t;
649
a6_tau = 54*t*t*t*t*t*(t-2);
650
e_infty = 1; break;
651
case 2: a4_tau = 108*t*t*t*(3-4*t);
652
a6_tau = 432*t*t*t*t*t*(8*t-9);
653
e_infty = 1; break;
654
case 3: a4_tau = t*t*t*(24-27*t);
655
a6_tau = t*t*t*t*((54*t-72)*t+16);
656
e_infty = 1; break;
657
case 4: a4_tau = 3*t*(8-9*t*t*t);
658
a6_tau = (54*t*t*t - 72)*t*t*t + 16;
659
e_infty = 1; break;
660
case 5: a4_tau = 6*t-27;
661
a6_tau = (t-18)*t+54;
662
e_infty = 0; break;
663
case 6: a4_tau = -3*t*t*t*(t+8);
664
a6_tau = -2*t*t*t*t*((t-20)*t-8);
665
e_infty = -3; break;
666
case 7: a4_tau = - 27*t*(t-1728)*(t-1728)*(t-1728);
667
a6_tau = 54*t*(t-1728)*(t-1728)*(t-1728)*(t-1728)*(t-1728);
668
e_infty = 1; break;
669
case -1: cout << "a4 = "; cin >> a4_tau;
670
cout << "a6 = "; cin >> a6_tau;
671
cout << "e_infty = "; cin >> e_infty; break;
672
}
673
674
char filename[35]; // 35 max characters in filename 's-p-d.txt'
675
sprintf(filename, "%ld-%ld-%ld.txt", s, p, d);
676
677
/* for(long ctr=0; ctr<=deg(a4_tau); ctr++) {
678
if(ctr==0) sprintf(filename, "[");
679
strcat(filename, ltoa(coeff(a4_tau, ctr)._zz_p__rep));
680
if(ctr < deg(a4_tau)) strcat(filename, "-");
681
else if(ctr == deg(a4_tau)) strcat(filename, "]-");
682
}
683
for(long ctr=0; ctr<=deg(a6_tau); ctr++) {
684
if(ctr==0) sprintf(filename, "[");
685
strcat(filename, ltoa(coeff(a6_tau, ctr)._zz_p__rep));
686
if(ctr < deg(a6_tau)) strcat(filename, "-");
687
else if(ctr == deg(a4_tau)) strcat(filename, "]");
688
}
689
char fend[10];
690
sprintf(fend, "-%d-%d.txt", p, d);
691
strcat(filename, fend); */
692
693
output.open(filename);
694
695
// compute discriminant. note, we tacitly assume we have a minimal
696
// Weierstrass model over A^1/F_q.
697
D_tau = 4*a4_tau*a4_tau*a4_tau + 27*a6_tau*a6_tau;
698
699
long a_q = 0, a_tau_q;
700
701
// compute traces for each finite tau in P^1(F_q)
702
tau = 0;
703
do {
704
a_tau_q = trace_tau(tau, a4_tau, a6_tau, D_tau);
705
output << a_tau_q << endl;
706
a_q += a_tau_q;
707
} while(inc(tau) == NO_CARRY);
708
709
// trace at tau=infty is Legendre character of e_infty
710
if (e_infty == 1)
711
a_tau_q = 1;
712
else if (e_infty != 0) {
713
static zz_pE x;
714
x = e_infty;
715
a_tau_q = IsOne(x^((q-1)/2)) ? 1 : -1;
716
} else
717
a_tau_q = 0;
718
output << a_tau_q << endl;
719
a_q += a_tau_q;
720
721
#if VERBOSE
722
printf("a_q = %ld\n", a_q);
723
if(s!=-1 && s!= 7) assert(a_q == 0);
724
else cout << a_q << endl;
725
#endif // VERBOSE
726
#endif
727
728
return 0;
729
}
730
731
#endif
732
733