Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241782 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
//
23
// C++ elliptic surface class
24
//
25
// this code offers basic routines for elliptic curves over a function
26
// field F_q(t), where F_q is a finite field. currently it is limited to
27
// curves with a model of the form y^2=x^3+a4*x+a6, which excludes
28
// characteristic two and some curves in characteristic three. because the
29
// latter two characteristics present other difficulties for the L-function
30
// code, we felt it was ok to make this exclusion.
31
//
32
33
#include <assert.h>
34
#include <string.h>
35
#include <NTL/ZZ_pEX.h>
36
#include <NTL/lzz_p.h>
37
#include <NTL/lzz_pE.h>
38
#include <NTL/lzz_pX.h>
39
#include <NTL/lzz_pEX.h>
40
#include <NTL/lzz_pEXFactoring.h>
41
42
NTL_CLIENT
43
44
#include "ell_surface.h"
45
#include "helper.h"
46
47
///////////////////////////////////////////////////////////////////////////
48
// minimal Weierstrass model over affine ring
49
// - can be used for F_q[t] or local ring O_pi
50
51
ell_surfaceInfoT::affine_model::affine_model()
52
{
53
init();
54
}
55
56
// determine kodaira type and other info of singular fiber over pi
57
//
58
// - should be called exactly *once* because changes epsilon and various
59
// divisors describing bad reduction
60
61
void ell_surfaceInfoT::affine_model::kodaira(const zz_pEX& pi)
62
{
63
zz_pEX r;
64
65
// good reduction
66
rem(r, disc, pi);
67
if (!IsZero(r))
68
return;
69
70
// j = 0 (mod pi): I_0*,II,IV,IV*,II*
71
rem(r, j.num, pi);
72
if (IsZero(r)) {
73
static zz_pEX t;
74
int ord_pi = 0, local_epsilon = 0;
75
76
// determine ord_pi(disc)
77
A *= pi;
78
t = disc;
79
do {
80
t /= pi;
81
ord_pi++;
82
rem(r, t, pi);
83
} while (IsZero(r));
84
85
// explicit Kodaira type
86
assert(ord_pi > 0 && ord_pi < 12 && ord_pi % 2 == 0);
87
switch (ord_pi) {
88
case 2 : II *= pi; local_epsilon = -1; break;
89
case 10 : II_star *= pi; local_epsilon = -1; break;
90
case 4 : IV *= pi; local_epsilon = -3; break;
91
case 8 : IV_star *= pi; local_epsilon = -3; break;
92
case 6 : I_star *= pi; local_epsilon = -1; break;
93
default : assert(0);
94
}
95
96
// determine contribution to sign of functional equation
97
switch (local_epsilon) {
98
case -1 : epsilon *= (q%4==1 || deg(pi)%2==0) ? +1 : -1; break;
99
case -3 : epsilon *= (q%3==1 || deg(pi)%2==0) ? +1 : -1; break;
100
default : assert(0);
101
}
102
103
return;
104
}
105
106
// j = 1728 (mod pi): I_0*,III,III*
107
rem(r, j.num-1728*j.den, pi);
108
if (IsZero(r)) {
109
static zz_pEX t;
110
int ord_pi = 0, local_epsilon = 0;
111
112
// determine ord_pi(disc)
113
A *= pi;
114
t = disc;
115
do {
116
t /= pi;
117
ord_pi++;
118
rem(r, t, pi);
119
} while (IsZero(r));
120
121
// explicit Kodaira type
122
assert(ord_pi > 0 && ord_pi < 12 && ord_pi % 3 == 0);
123
switch (ord_pi) {
124
case 3 : III_star *= pi; local_epsilon = -2; break;
125
case 9 : III *= pi; local_epsilon = -2; break;
126
case 6 : I_star *= pi; local_epsilon = -1; break;
127
default : assert(0);
128
}
129
130
// contribution to sign of functional equation
131
switch (local_epsilon) {
132
case -1 : epsilon *= (q%4==1 || deg(pi)%2==0) ? +1 : -1; break;
133
case -2 : epsilon *= (q%8<=3 || deg(pi)%2==0) ? +1 : -1; break;
134
default : assert(0);
135
}
136
137
return;
138
}
139
140
// j = infty (mod pi): I_n,I_n^*
141
rem(r, j.den, pi);
142
if (IsZero(r)) {
143
// determine if multiplicate or additive
144
rem(r, a6, pi);
145
if (IsZero(r)) { // add've
146
A *= pi;
147
I_star *= pi;
148
if (q % 4 == 3 && deg(pi) % 2 == 1)
149
epsilon *= -1;
150
} else { // mult've
151
// determine if split or non-split
152
// - split <==> 6*a6 (mod pi) is a square
153
154
ZZ q_to_d, e;
155
q_to_d = 1;
156
for (int j = deg(pi); j > 0; j--)
157
q_to_d *= q;
158
e = (q_to_d - 1) / 2;
159
160
zz_pEXModulus mod_pi(pi);
161
zz_pEX tmp;
162
rem(tmp, 6*a6, mod_pi);
163
PowerMod(r, tmp, e, mod_pi);
164
assert(r == 1 || r == -1);
165
166
if (r == 1) {
167
M_sp *= pi;
168
epsilon *= -1;
169
} else
170
M_ns *= pi;
171
}
172
173
return;
174
}
175
176
// I_0^* : ord_pi(j) = ord_pi(j-1728) = 0
177
A *= pi;
178
I_star *= pi;
179
if (q%4==3 && deg(pi)%2==1)
180
epsilon *= -1;
181
}
182
183
// initialize
184
185
void ell_surfaceInfoT::affine_model::init()
186
{
187
q = to_long(zz_pE::cardinality());
188
189
I_star = 1; // I_n^*
190
II = 1; // II
191
II_star = 1; // II*
192
III = 1; // III
193
III_star = 1; // III*
194
IV = 1; // IV
195
IV_star = 1; // IV*
196
197
M_sp = 1; // split multiplicative reduction
198
M_ns = 1; // non-split multiplicative reduction
199
A = 1; // additive reduction
200
201
epsilon = 1; // epsilon factor
202
203
disc = 0;
204
}
205
206
void ell_surfaceInfoT::affine_model::init(const zz_pEratX& rat_a4, const zz_pEratX& rat_a6)
207
{
208
init();
209
210
// step 1: clear denominators by map (a4,a6)-->(a4*d^4,a6*d^6) to get a
211
// (not necessarily minimal) Weierstrass over F_q[t]
212
static zz_pEX d;
213
d = rat_a4.den * rat_a6.den / GCD(rat_a4.den, rat_a6.den);
214
215
a4 = rat_a4.num * (d^4) / rat_a4.den;
216
a6 = rat_a6.num * (d^6) / rat_a6.den;
217
assert(!IsZero(a4) && !IsZero(a6));
218
219
// step 2: calculate j-invariant for current Weierstrass model
220
disc = 4*a4*a4*a4 + 27*a6*a6;
221
j.init(6912*a4*a4*a4, disc);
222
223
// step 3: divide a4,a6 by max'l degree polynomial d so d^4|a4 and d^6|a6
224
// - for each prime pi|a4, keep dividing a4,a6 by pi^4,pi^6 until
225
// one or both are not divisible
226
// - result is minimal Weierstrass model over F_q[t]
227
vec_pair_zz_pEX_long factors;
228
CanZass(factors, a4 / LeadCoeff(a4));
229
for (int i = 0; i < factors.length(); i++) {
230
static zz_pEX pi, pi_to_4, pi_to_6;
231
232
pi = factors[i].a;
233
pi_to_4 = pi^4;
234
pi_to_6 = pi^6;
235
while (1) {
236
static zz_pEX r_a4, r_a6;
237
238
rem(r_a4, a4, pi_to_4);
239
rem(r_a6, a6, pi_to_6);
240
if (!IsZero(r_a4) || !IsZero(r_a6))
241
break;
242
a4 /= pi_to_4;
243
a6 /= pi_to_6;
244
}
245
}
246
247
// recalculate discriminant for new model
248
disc = 4*a4*a4*a4 + 27*a6*a6;
249
constant_f = (deg(a4) == 0 && deg(a6) == 0);
250
}
251
252
void ell_surfaceInfoT::affine_model::init(const zz_pEX& a4, const zz_pEX& a6)
253
{
254
zz_pEratX rat_a4(a4), rat_a6(a6);
255
init(rat_a4, rat_a6);
256
}
257
258
///////////////////////////////////////////////////////////////////////////
259
// elliptic surface parameter class
260
// - we keep track of the coeffs for a Weierstrass model over F_q[t],
261
// the coeffs for a minimal Weierstrass model over F_q[u] for u=1/t,
262
// and finer information about the type of bad reduction, e.g. split vs
263
// non-split mult've, and Kodaira type in the case of add've reduction
264
///////////////////////////////////////////////////////////////////////////
265
266
// constructor
267
268
ell_surfaceInfoT::ell_surfaceInfoT(const zz_pEratX& a4, const zz_pEratX& a6)
269
{
270
static zz_pEX pi;
271
272
ref_count = 1;
273
274
q = to_long(zz_pE::cardinality());
275
276
// compute minimal Weierstrass model over F_q[t]
277
finite_model.init(a4, a6);
278
279
// determine Kodaira type of bad reduction for minimal Weierstrass model
280
vec_pair_zz_pEX_long factors;
281
CanZass(factors, finite_model.disc / LeadCoeff(finite_model.disc));
282
for (int i = 0; i < factors.length(); i++) {
283
pi = factors[i].a;
284
finite_model.kodaira(pi);
285
}
286
287
// compute minimal Weierstrass model about t=infty
288
zz_pEratX a4_of_u = a4, a6_of_u = a6;
289
a4_of_u.inv_t();
290
a6_of_u.inv_t();
291
infinite_model.init(a4_of_u, a6_of_u);
292
293
// determine Kodaira type of bad reduction
294
pi = 1;
295
pi <<= 1;
296
infinite_model.kodaira(pi);
297
298
// check whether have constant curve
299
assert(finite_model.constant_f == infinite_model.constant_f);
300
constant_f = finite_model.constant_f;
301
302
// compute invariants for L-function
303
sign = finite_model.epsilon * infinite_model.epsilon;
304
deg_L = 2*(deg(finite_model.A) + deg(infinite_model.A))
305
+ deg(finite_model.M_sp) + deg(infinite_model.M_sp)
306
+ deg(finite_model.M_ns) + deg(infinite_model.M_ns) - 4;
307
}
308
309
// destructor
310
311
ell_surfaceInfoT::~ell_surfaceInfoT()
312
{
313
}
314
315
zz_pEX ell_surfaceInfoT::finite_A()
316
{
317
return finite_model.A;
318
}
319
320
int ell_surfaceInfoT::infinite_A()
321
{
322
if (deg(infinite_model.A) > 0 && IsZero(coeff(infinite_model.A, 0)))
323
return 1;
324
return 0;
325
}
326
327
zz_pEX ell_surfaceInfoT::finite_M()
328
{
329
return finite_model.M_sp * finite_model.M_ns;
330
}
331
332
int ell_surfaceInfoT::infinite_M()
333
{
334
if (deg(infinite_model.M_sp) > 0 && IsZero(coeff(infinite_model.M_sp, 0)))
335
return 1;
336
if (deg(infinite_model.M_ns) > 0 && IsZero(coeff(infinite_model.M_ns, 0)))
337
return 1;
338
return 0;
339
}
340
341
// copied from NTL
342
343
static void CopyPointer(ell_surfaceInfoPtr& dst, ell_surfaceInfoPtr src)
344
{
345
if (src == dst) return;
346
347
if (dst) {
348
dst->ref_count--;
349
350
if (dst->ref_count < 0)
351
Error("internal error: negative ell_surfaceContext ref_count");
352
353
if (dst->ref_count == 0) delete dst;
354
}
355
356
if (src) {
357
if (src->ref_count == NTL_MAX_LONG)
358
Error("internal error: ell_surfaceContext ref_count overflow");
359
360
src->ref_count++;
361
}
362
363
dst = src;
364
}
365
366
////////////////////////////////////////////////////////////
367
// context switching class, shamelessly copied from NTL
368
////////////////////////////////////////////////////////////
369
370
// info for current elliptic surface
371
ell_surfaceInfoPtr ell_surfaceInfo = NULL;
372
373
ell_surfaceContext::ell_surfaceContext(const zz_pEratX& a4, const zz_pEratX& a6)
374
{
375
ptr = new ell_surfaceInfoT(a4, a6);
376
}
377
378
ell_surfaceContext::ell_surfaceContext(const ell_surfaceContext& a)
379
{
380
ptr = NULL;
381
CopyPointer(ptr, a.ptr);
382
}
383
384
ell_surfaceContext& ell_surfaceContext::operator=(const ell_surfaceContext& a)
385
{
386
CopyPointer(ptr, a.ptr);
387
return *this;
388
}
389
390
ell_surfaceContext::~ell_surfaceContext()
391
{
392
CopyPointer(ptr, NULL);
393
}
394
395
void ell_surfaceContext::save()
396
{
397
CopyPointer(ptr, ell_surfaceInfo);
398
}
399
400
void ell_surfaceContext::restore() const
401
{
402
CopyPointer(ell_surfaceInfo, ptr);
403
}
404
405
///////////////////////////////////////////////////////////////////////////
406
407
void ell_surface::init(const zz_pEratX& a4, const zz_pEratX& a6)
408
{
409
ell_surfaceContext c(a4, a6);
410
411
c.restore();
412
}
413
414
void ell_surface::init(const zz_pEX& a4, const zz_pEX& a6)
415
{
416
zz_pEX one;
417
one = 1;
418
zz_pEratX rat_a4(a4, one), rat_a6(a6, one);
419
init(rat_a4, rat_a6);
420
}
421
422
void ell_surface::init(const zz_pEratX& a1, const zz_pEratX& a2,
423
const zz_pEratX& a3, const zz_pEratX& a4, const zz_pEratX& a6)
424
{
425
zz_pEratX new_a4, new_a6;
426
zz_pEX d;
427
d = 48;
428
new_a4 = (48*a4 - (a1^4) - 8*(a1^2)*a2 + 24*a1*a3 - 16*(a2^2)) / d;
429
d = 864;
430
new_a6 = (-72*a4*(a1^2) - 288*a4*a2 + 864*a6 + (a1^6)
431
+ 12*a2*(a1^4) - 36*a3*(a1^3) + 48*(a2^2)*(a1^2)
432
- 144*a3*a2*a1 + 64*(a2^3) + 216*(a3^2)) / d;
433
init(new_a4, new_a6);
434
}
435
436
//////////////////////////////
437
438
void to_ZZ_pX(const zz_pX& src, ZZ_pX& dst)
439
{
440
ZZ_p c_;
441
442
//cout << "to_ZZ_px: src = " << src << endl;
443
clear(dst);
444
for (int i = 0; i <= deg(src); i++) {
445
long c = rep(coeff(src, i));
446
c_ = to_ZZ_p(c);
447
//cout << "c = " << c << ", c_ = " << c_ << ", modulus(c_) = " << c_.modulus() << endl;
448
SetCoeff(dst, i, c_);
449
}
450
//cout << "to_ZZ_px: dst = " << dst << endl;
451
}
452
453
void to_ZZ_pEX(const zz_pEX& src, ZZ_pEX& dst)
454
{
455
ZZ p;
456
p = zz_p::modulus();
457
ZZ_p::init(p);
458
459
// cout << "src = " << src << endl;
460
clear(dst);
461
for (int i = 0; i <= deg(src); i++) {
462
zz_pE c = coeff(src, i);
463
464
if (i == 0) {
465
zz_pX m = c.modulus();
466
ZZ_pX M;
467
to_ZZ_pX(m, M);
468
ZZ_pE::init(M);
469
}
470
471
ZZ_pE C;
472
to_ZZ_pX(rep(c), C.LoopHole());
473
SetCoeff(dst, i, C);
474
}
475
// cout << "dst = " << dst << endl;
476
}
477
478
void get_an(ZZ_pEX& a4, ZZ_pEX& a6)
479
{
480
ell_surfaceInfoT *info = ell_surface::getSurfaceInfo();
481
482
to_ZZ_pEX(info->finite_model.a4, a4);
483
to_ZZ_pEX(info->finite_model.a6, a6);
484
}
485
486
void get_reduction(ZZ_pEX **divisors, int finite)
487
{
488
ell_surfaceInfoT *info = ell_surface::getSurfaceInfo();
489
490
if (finite) {
491
to_ZZ_pEX(info->finite_model.M_sp, *(divisors[0]));
492
to_ZZ_pEX(info->finite_model.M_ns, *(divisors[1]));
493
to_ZZ_pEX(info->finite_model.I_star, *(divisors[2]));
494
to_ZZ_pEX(info->finite_model.II, *(divisors[3]));
495
to_ZZ_pEX(info->finite_model.II_star, *(divisors[4]));
496
to_ZZ_pEX(info->finite_model.III, *(divisors[5]));
497
to_ZZ_pEX(info->finite_model.III_star, *(divisors[6]));
498
to_ZZ_pEX(info->finite_model.IV, *(divisors[7]));
499
to_ZZ_pEX(info->finite_model.IV_star, *(divisors[8]));
500
} else {
501
to_ZZ_pEX(info->infinite_model.M_sp, *(divisors[0]));
502
to_ZZ_pEX(info->infinite_model.M_ns, *(divisors[1]));
503
to_ZZ_pEX(info->infinite_model.I_star, *(divisors[2]));
504
to_ZZ_pEX(info->infinite_model.II, *(divisors[3]));
505
to_ZZ_pEX(info->infinite_model.II_star, *(divisors[4]));
506
to_ZZ_pEX(info->infinite_model.III, *(divisors[5]));
507
to_ZZ_pEX(info->infinite_model.III_star, *(divisors[6]));
508
to_ZZ_pEX(info->infinite_model.IV, *(divisors[7]));
509
to_ZZ_pEX(info->infinite_model.IV_star, *(divisors[8]));
510
}
511
}
512
513
void get_disc(ZZ_pEX& disc, int finite)
514
{
515
ell_surfaceInfoT *info = ell_surface::getSurfaceInfo();
516
517
if (finite)
518
to_ZZ_pEX(info->finite_model.disc, disc);
519
else
520
to_ZZ_pEX(info->infinite_model.disc, disc);
521
}
522
523
void get_j_invariant(ZZ_pEX& j_num, ZZ_pEX& j_den)
524
{
525
ell_surfaceInfoT *info = ell_surface::getSurfaceInfo();
526
527
to_ZZ_pEX(info->finite_model.j.num, j_num);
528
to_ZZ_pEX(info->finite_model.j.den, j_den);
529
}
530
531
#if 0
532
void get_finite_M(ell_surfaceInfoT *info, ZZ_pEX& M_sp, ZZ_pEX& M_ns)
533
{
534
to_ZZ_pEX(info->finite_model.M_sp, M_sp);
535
to_ZZ_pEX(info->finite_model.M_ns, M_ns);
536
}
537
538
void get_finite_A(ell_surfaceInfoT *info, ZZ_pEX& A, ZZ_pEX& I_star, ZZ_pEX& II, ZZ_pEX& II_star, ZZ_pEX& III, ZZ_pEX& III_star, ZZ_pEX& IV, ZZ_pEX& IV_star)
539
{
540
to_ZZ_pEX(info->finite_model.A, A);
541
to_ZZ_pEX(info->finite_model.I_star, I_star);
542
to_ZZ_pEX(info->finite_model.II, II);
543
to_ZZ_pEX(info->finite_model.II_star, II_star);
544
to_ZZ_pEX(info->finite_model.III, III);
545
to_ZZ_pEX(info->finite_model.III_star, III_star);
546
to_ZZ_pEX(info->finite_model.IV, IV);
547
to_ZZ_pEX(info->finite_model.IV_star, IV_star);
548
}
549
#endif
550
551
#if 0
552
void get_infinite_an(ell_surfaceInfoT *info, ZZ_pEX& a4, ZZ_pEX& a6)
553
{
554
to_ZZ_pEX(info->infinite_model.a4, a4);
555
to_ZZ_pEX(info->infinite_model.a6, a6);
556
}
557
#endif
558
559
#if 0
560
void get_infinite_M(ell_surfaceInfoT *info, ZZ_pEX& M_sp, ZZ_pEX& M_ns)
561
{
562
to_ZZ_pEX(info->infinite_model.M_sp, M_sp);
563
to_ZZ_pEX(info->infinite_model.M_ns, M_ns);
564
}
565
566
void get_infinite_A(ell_surfaceInfoT *info, ZZ_pEX& A, ZZ_pEX& I_star, ZZ_pEX& II, ZZ_pEX& II_star, ZZ_pEX& III, ZZ_pEX& III_star, ZZ_pEX& IV, ZZ_pEX& IV_star)
567
{
568
to_ZZ_pEX(info->infinite_model.A, A);
569
to_ZZ_pEX(info->infinite_model.I_star, I_star);
570
to_ZZ_pEX(info->infinite_model.II, II);
571
to_ZZ_pEX(info->infinite_model.II_star, II_star);
572
to_ZZ_pEX(info->infinite_model.III, III);
573
to_ZZ_pEX(info->infinite_model.III_star, III_star);
574
to_ZZ_pEX(info->infinite_model.IV, IV);
575
to_ZZ_pEX(info->infinite_model.IV_star, IV_star);
576
}
577
#endif
578
579
#if 0
580
void get_infinite_disc(ell_surfaceInfoT *info, ZZ_pEX& disc)
581
{
582
to_ZZ_pEX(info->infinite_model.disc, disc);
583
}
584
#endif
585
586
//////////////////////////////
587
588
#ifdef MAIN
589
int main(int argc, char **argv)
590
{
591
long f = 0, p = 5, d = 1;
592
593
if (argc < 2 || argc > 4) {
594
fprintf(stderr, "usage: %s f [p [d]]\n", argv[0]);
595
return -1;
596
}
597
f = atoi(argv[1]);
598
if (argc > 2)
599
p = atoi(argv[2]);
600
if (argc > 3)
601
d = atoi(argv[3]);
602
603
if (p < 4) {
604
fprintf(stderr, "only characteristic >= 5 supported\n");
605
return -1;
606
}
607
608
// set current prime field to F_p
609
init_NTL_ff(p, d);
610
611
zz_pEX t, one;
612
zz_pEratX a4, a6;
613
t = 1; t <<= 1;
614
one = 1;
615
switch (f) {
616
case 0: a4.init(-27*t*t*((t - 1)*t + 1), one);
617
a6.init(27*t*t*t*(((2*t-3)*t-3)*t+2), one);
618
break;
619
case 1: a4.init(-27*t*t*t*t, one);
620
a6.init(54*t*t*t*t*t*(t-2), one);
621
break;
622
case 2: a4.init(108*t*t*t*(3-4*t), one);
623
a6.init(432*t*t*t*t*t*(8*t-9), one);
624
break;
625
case 3: a4.init(t*t*t*(24-27*t), one);
626
a6.init(t*t*t*t*((54*t-72)*t+16), one);
627
break;
628
case 4: a4.init(3*t*(8-9*t*t*t), one);
629
a6.init((54*t*t*t - 72)*t*t*t + 16, one);
630
break;
631
case 5: a4.init(6*t-27, one);
632
a6.init((t-18)*t+54, one);
633
break;
634
case 6: a4.init(-3*t*t*t*(t+8), one);
635
a6.init(-2*t*t*t*t*((t-20)*t-8), one);
636
break;
637
case 7: a4.init(- 27*t*(t-1728)*(t-1728)*(t-1728), one);
638
a6.init(54*t*(t-1728)*(t-1728)*(t-1728)*(t-1728)*(t-1728), one);
639
break;
640
default : assert(0);
641
}
642
643
ell_surface::init(a4, a6);
644
645
int epsilon = 1;
646
for (int i = 0; i < 2; i++) {
647
ell_surfaceInfoT::affine_model *model;
648
649
model = (i == 0) ? &(ell_surfaceInfo->finite_model)
650
: &(ell_surfaceInfo->infinite_model);
651
if (i == 0)
652
cerr << "j = " << model->j.num << "/"
653
<< model->j.den << endl;
654
cerr << "epsilon = " << model->epsilon << endl;
655
cerr << endl;
656
cerr << "M_sp = " << model->M_sp << endl;
657
cerr << "M_ns = " << model->M_ns << endl;
658
cerr << endl;
659
cerr << "A = " << model->A << endl;
660
cerr << endl;
661
cerr << "I_star = " << model->I_star << endl;
662
cerr << "II = " << model->II << endl;
663
cerr << "II_star = " << model->II_star << endl;
664
cerr << "III = " << model->III << endl;
665
cerr << "III_star = " << model->III_star << endl;
666
cerr << "IV = " << model->IV << endl;
667
cerr << "IV_star = " << model->IV_star << endl;
668
cerr << endl;
669
epsilon *= model->epsilon;
670
}
671
cerr << "global epsilon = " << epsilon << endl;
672
cerr << "deg(L) = " << ell_surfaceInfo->deg_L << endl;
673
674
return 0;
675
}
676
#endif // MAIN
677
678