Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
241818 views
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <ctype.h>
4
#include <string.h>
5
#include <limits.h>
6
#include "gmp.h"
7
#include "mpzutil.h"
8
#include "ffwrapper.h"
9
#include "polydisc.h"
10
#include "ffext.h"
11
#include "ffpoly.h"
12
#include "cstd.h"
13
14
/*
15
Copyright 2007-2008 Andrew V. Sutherland
16
17
This file is part of smalljac.
18
19
smalljac is free software: you can redistribute it and/or modify
20
it under the terms of the GNU General Public License as published by
21
the Free Software Foundation, either version 2 of the License, or
22
(at your option) any later version.
23
24
smalljac is distributed in the hope that it will be useful,
25
but WITHOUT ANY WARRANTY; without even the implied warranty of
26
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
GNU General Public License for more details.
28
29
You should have received a copy of the GNU General Public License
30
along with smalljac. If not, see <http://www.gnu.org/licenses/>.
31
*/
32
33
// This module consists mostly of standard polynomial arithmetic functions that are better implemented in NTL
34
// but are handy for a standalone C implementation.
35
36
// The discriminant code is woefully incomplete and resultants aren't implemented.
37
38
int mpq_poly_jinv_i (mpq_t j, long a[5])
39
{
40
static mpz_t t1, t2, a0, a1, a2, a3, a4, a6, b2, b4, b6, b8, c4, D; // more variables than is really necessary
41
static mpq_t d;
42
static int init;
43
44
if ( ! init ) {
45
mpz_init (a0); mpz_init (a1); mpz_init (a2); mpz_init (a3); mpz_init (a4); mpz_init (a6);
46
mpz_init (b2); mpz_init (b4); mpz_init (b6); mpz_init (b8); mpz_init (c4); mpz_init (D);
47
mpz_init (t1); mpz_init (t2); mpq_init(d); init = 1;
48
}
49
mpz_set_i (a1, a[0]); mpz_set_i (a2, a[1]); mpz_set_i (a3, a[2]); mpz_set_i (a4, a[3]); mpz_set_i (a6, a[4]);
50
51
// compute b2 = a1^2+4a2
52
mpz_mul(t2,a1,a1); // save t2 = a1^2
53
mpz_mul_2exp (t1,a2,2);
54
mpz_add(b2,t2,t1);
55
// compute b4 = 2a4+a1a3
56
mpz_mul_2exp (b4,a4,1);
57
mpz_mul (t1,a1,a3);
58
mpz_add (b4,b4,t1);
59
// compute b6 = a3^2+4a6
60
mpz_mul (b6,a3,a3);
61
mpz_mul_2exp (t1,a6,2);
62
mpz_add (b6, b6, t1);
63
// compute b8 = (a1^2+4a2)a6 + (a2a3-a1a4)a3 - a4^2
64
mpz_mul_2exp (b8,a2,2);
65
mpz_add (b8,b8,t2); // t2 = a1^2 from above
66
mpz_mul (b8,b8,a6);
67
mpz_mul (t1,a2,a3);
68
mpz_mul (t2,a1,a4);
69
mpz_sub (t1,t1,t2);
70
mpz_mul (t1,t1,a3);
71
mpz_add (b8,b8,t1);
72
mpz_mul (t1,a4,a4);
73
mpz_sub (b8,b8,t1);
74
// compute D = (9b4b6-b2b8)b2 - 8b4^3 - 27b6^2
75
mpz_mul (D,b4,b6);
76
mpz_mul_ui (D,D,9);
77
mpz_mul (t1,b2,b8);
78
mpz_sub (D,D,t1);
79
mpz_mul (D,D,b2);
80
mpz_mul (t1,b4,b4);
81
mpz_mul (t1,t1,b4);
82
mpz_mul_2exp (t1,t1,3);
83
mpz_sub (D,D,t1);
84
mpz_mul (t1,b6,b6);
85
mpz_mul_ui (t1,t1,27);
86
mpz_sub (D,D,t1);
87
if ( ! mpz_sgn(D) ) return 0;
88
// compute t1 = numerator of j = c4^3 = (b2^2 - 24b4)^3
89
mpz_mul (t1,b2,b2);
90
mpz_mul_ui (t2,b4,24);
91
mpz_sub (t1,t1,t2);
92
mpz_mul (t2, t1, t1);
93
mpz_mul (t1,t1,t2);
94
mpq_set_z (j, t1);
95
mpq_set_z (d,D);
96
mpq_div (j,j,d);
97
return 1;
98
}
99
100
101
/*
102
For monic f, substitute x <- (x - f_{d-1}/[d*f_d]) to make f_{d-1} term zero if necessary
103
Returns 1 if poly modified, 0 if not
104
*/
105
int mpq_poly_standardize (mpq_t f[], int d)
106
{
107
static mpq_t e[POLY_MAX_DEGREE+1], g[POLY_MAX_DEGREE+1], h[POLY_MAX_DEGREE+1], c;
108
static int init;
109
int i, j, d_e;
110
111
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { mpq_init (e[i]); mpq_init (g[i]); mpq_init (h[i]); } mpq_init (c); init = 1; }
112
if ( d < 1 ) return 0;
113
if ( mpz_cmp_ui (mpq_numref(f[d]),1) != 0 || mpz_cmp_ui(mpq_denref(f[d]),1) != 0 ) return 0;
114
if ( ! mpq_sgn(f[d-1]) ) return 0;
115
mpq_set_ui (c, 1, d);
116
mpq_div (c, c, f[d]);
117
mpq_mul (c, c, f[d-1]);
118
mpq_neg (c, c); // c = -f_{d-1}/(d*f_d)
119
for ( i = 0 ; i <= d ; i++ ) { mpq_set_ui (e[i], 0, 1); mpq_set_ui (g[i], 0, 1); mpq_set_ui (h[i], 0, 1); }
120
mpq_set_ui (e[0], 1, 1); d_e = 0; // e = 1
121
mpq_set (g[0], f[0]); // g = f0
122
for ( j = 1 ; j <= d ; j++ ) {
123
for ( i = 0 ; i <= d_e ; i++ ) mpq_mul (h[i], c, e[i]); // h = c*e
124
for ( i = d_e ; i >= 0 ; i-- ) mpq_set (e[i+1], e[i]); // e *= x
125
mpq_set (e[0], h[0]);
126
for ( i = 1 ; i <= d_e ; i++ ) mpq_add (e[i], e[i], h[i]); // e += h
127
d_e++; // e is now e*(x+c)
128
for ( i = 0 ; i <= d_e ; i++ ) mpq_mul (h[i], f[j], e[i]); // h = f[j]*e
129
for ( i = 0 ; i <= d_e ; i++ ) mpq_add (g[i], g[i], h[i]); // g += h
130
}
131
for ( i = 0 ; i <= d ; i++ ) mpq_set (f[i], g[i]); // copy g into f
132
if ( mpq_sgn(f[d-1]) ) { err_printf ("mpq_poly_standardize failed! f[d-1] = %Qd \n", f[d-1]); exit (0); } // should be impossible
133
return 1;
134
}
135
136
137
/*
138
Convert long weierstrass form [a1,a2,a3,a4,a6] to short form x^3+f1*x + f0
139
Weierstrass coefficients are specified by W[0] = a1, ..., W[3] = a4, w[4] = a6
140
141
This is done by first applying the substitution y -> y - a1/2*x - a3/2 which kills a1 and a3
142
and sends a2 -> a2+ a1^2/4, a4 -> a4 + a1a3/2 and a6 -> a6 + a3^2/4.
143
144
Then apply the substitution x -> x - a2/3 to the resulting curve, which kills a2, keeps
145
a1 and a3 zero if they have already been killed, and sends a4 -> a4 - a2^2/3 and
146
a6 -> a6 + 2/27a2^3 - a2a4/3
147
*/
148
void mpq_poly_weierstrass (mpq_t f[4], mpz_t W[5])
149
{
150
static mpq_t t1, t2, c2, c4, c6, three;
151
static int init;
152
153
if ( ! init ) { mpq_init(t1); mpq_init(t2); mpq_init(c2); mpq_init(c4); mpq_init (c6); mpq_init(three); init = 1; }
154
155
mpq_set_ui (f[3], 1, 1);
156
mpq_set_ui (f[2], 0, 1);
157
158
// set c2 = a2 + a1^2/4
159
mpq_set_z (t2, W[0]);
160
mpq_div_2exp (t1, t2, 1); // t1 = a1/2
161
mpq_mul (c2, t1, t1); // c2 = a1^2/4
162
mpq_set_z (t2, W[1]);
163
mpq_add (c2, c2, t2); // c2 = a2+a1^2/4 is the new a2
164
165
// set c4 = a4 + a1a3/2
166
mpq_set_z (t2, W[2]);
167
mpq_mul (c4, t1, t2); // c4 = a1a3/2
168
mpq_set_z (t2, W[3]);
169
mpq_add (c4, c4, t2); // c4 = a4 + a1a3/2 is the new a4
170
171
// set c6 = a6 + a3^2/4 this is rolled in below
172
mpq_set_z (t2, W[2]);
173
mpq_div_2exp (c6, t2, 1);
174
mpq_mul (c6, c6, c6); // c6 = a3^2/4
175
mpq_set_z (t2, W[4]);
176
mpq_add (c6, c6, t2); // c6 = a6 + a3^2/4 is the new a6
177
178
// set f[1] = a4' = c4 - c2^2/3
179
mpq_set_ui (three, 3, 1);
180
mpq_div (c2, c2, three);
181
mpq_mul (t1, c2, c2); // t1 = c2^2/9
182
mpq_mul (t2, t1, three); // t2 = c2^2/3
183
mpq_sub (f[1], c4, t2); // f[1] = c4 - c2^2/3
184
185
// set f[0] = a6' = a6 + a3^2/4 + 2(c2/3)^3 - c2c4/3
186
mpq_mul (t2, t1, c2); // t2 = c2^3/27
187
mpq_mul_2exp (t2, t2, 1); // t2 = 2/27*c2^3
188
mpq_mul (t1, c4, c2); // t1 = c2c4/3
189
mpq_sub (t2, t2, t1); // t2 = 2/27*c2^3 - c2c4/3
190
mpq_add (f[0], c6, t2); // f[0] = c6 + 2/27*c2^3 - c2c4/3
191
192
return;
193
}
194
195
void mpq_poly_weierstrass_mpq (mpq_t f[4], mpq_t a1, mpq_t a2, mpq_t a3, mpq_t a4, mpq_t a6)
196
{
197
static mpq_t t1, t2, c2, c4, c6, three;
198
static int init;
199
200
if ( ! init ) { mpq_init(t1); mpq_init(t2); mpq_init(c2); mpq_init(c4); mpq_init (c6); mpq_init(three); init = 1; }
201
202
mpq_set_ui (f[3], 1, 1);
203
mpq_set_ui (f[2], 0, 1);
204
205
// set c2 = a2 + a1^2/4
206
mpq_div_2exp (t1, a1, 1); // t1 = a1/2
207
mpq_mul (c2, t1, t1); // c2 = a1^2/4
208
mpq_add (c2, c2, a2); // c2 = a2+a1^2/4 is the new a2
209
210
// set c4 = a4 + a1a3/2
211
mpq_mul (c4, t1, a3); // c4 = a1a3/2
212
mpq_add (c4, c4, a4); // c4 = a4 + a1a3/2 is the new a4
213
214
// set c6 = a6 + a3^2/4 this is rolled in below
215
mpq_div_2exp (c6, a3, 1);
216
mpq_mul (c6, c6, c6); // c6 = a3^2/4
217
mpq_add (c6, c6, a6); // c6 = a6 + a3^2/4 is the new a6
218
219
// set f[1] = a4' = c4 - c2^2/3
220
mpq_set_ui (three, 3, 1);
221
mpq_div (c2, c2, three);
222
mpq_mul (t1, c2, c2); // t1 = c2^2/9
223
mpq_mul (t2, t1, three); // t2 = c2^2/3
224
mpq_sub (f[1], c4, t2); // f[1] = c4 - c2^2/3
225
226
// set f[0] = a6' = a6 + a3^2/4 + 2(c2/3)^3 - c2c4/3
227
mpq_mul (t2, t1, c2); // t2 = c2^3/27
228
mpq_mul_2exp (t2, t2, 1); // t2 = 2/27*c2^3
229
mpq_mul (t1, c4, c2); // t1 = c2c4/3
230
mpq_sub (t2, t2, t1); // t2 = 2/27*c2^3 - c2c4/3
231
mpq_add (f[0], c6, t2); // f[0] = c6 + 2/27*c2^3 - c2c4/3
232
return;
233
}
234
235
236
int poly_expr_degree (char *str, int *ws)
237
{
238
register char *s;
239
int d, degree;
240
241
if ( ws ) *ws = 0;
242
for ( s = str ; *s && *s != 'x' && *s != ',' ; s++ );
243
if ( *s == ',' && str[0] == '[' ) { if ( ws ) *ws = 1; return 3; }
244
if ( *s != 'x' ) return 0; // don't try to distinguish bad or zero polys from constants
245
if ( *(s+1) == '^' ) degree = atoi (s+2); else degree = 1;
246
s++;
247
for (;;) {
248
while ( *s && *s != 'x' ) s++;
249
if ( ! *s ) break;
250
if ( *(s+1) == '^' ) { d = atoi (s+2); if ( d > degree ) degree = d; }
251
s++;
252
}
253
return degree;
254
}
255
256
257
static inline int isqdigit(char c) { return (isdigit(c) || c == '/' ); }
258
259
int mpq_poly_expr (mpq_t f[], int maxd, char *expr)
260
{
261
static int init;
262
static mpq_t c;
263
static mpz_t W[5];
264
char cbuf[4096];
265
register char *s, *t;
266
int i;
267
int sign;
268
269
if ( ! init ) { mpq_init (c); for ( i = 0 ; i < 5 ; i++ ) mpz_init (W[i]); init = 1; }
270
271
s = expr;
272
// Check if expr looks like it is in weierstrass form "[a1,a2,a3,a4,a6]" and handle this seperately
273
while ( isspace(*s) ) s++;
274
if ( *s == '[' && (isdigit (*(s+1)) || *(s+1) == '-') ) {
275
for ( t = s ; *t && *t != ',' && *t != ']' ; t++ );
276
if ( *t == ',' ) {
277
if ( gmp_sscanf (s, "[%Zd,%Zd,%Zd,%Zd,%Zd]", W[0], W[1], W[2], W[3], W[4]) != 5 ) return -2;
278
mpq_poly_weierstrass (f, W);
279
return 3;
280
}
281
}
282
283
for ( i = 0 ; i <= maxd ; i++ ) mpq_set_ui(f[i], 0, 1);
284
if ( *s == '[' || *s == '(' ) s++;
285
for(;;) {
286
while ( isspace(*s) ) s++;
287
// handle signs explicitly to deal with things like '+ -3' which gmp doesn't like and we need to handle
288
sign = 1;
289
if ( *s == '-' ) {
290
sign = -1;
291
for ( s++ ; isspace(*s) ; s++);
292
} else if ( *s == '+' ) {
293
for ( s++ ; isspace(*s) ; s++);
294
if ( *s == '-' ) {
295
sign = -1;
296
for ( s++ ; isspace(*s) ; s++);
297
}
298
}
299
if ( isdigit(*s) ) {
300
for ( t = cbuf ; isqdigit(*s) ; *t++ = *s++ );
301
*t = '\0';
302
if ( mpq_set_str (c, cbuf, 0) < 0 ) return -2;
303
mpq_canonicalize (c);
304
while ( isqdigit(*s) ) s++;
305
} else if ( *s == 'x' || *s == 'X' ) {
306
mpq_set_ui (c, 1, 1);
307
} else {
308
break;
309
}
310
if ( sign < 0 ) mpq_neg(c,c);
311
if ( *s == '*' ) s++;
312
if ( *s == 'x' || *s == 'X' ) {
313
s++;
314
if ( *s == '^' ) s++;
315
if ( isdigit(*s) ) {
316
i = atoi (s);
317
while ( isdigit(*s) ) s++;
318
if ( i > maxd ) return -2;
319
} else {
320
i = 1;
321
}
322
} else {
323
i = 0;
324
}
325
mpq_add (f[i], f[i], c);
326
}
327
for ( i = maxd ; i && ! mpq_sgn(f[i]) ; i-- );
328
if ( ! i && ! mpq_sgn(f[i]) ) return -1;
329
maxd = i;
330
if ( *s == ']' && *(s+1) == '/' ) {
331
for ( t = cbuf, s+=2 ; isdigit(*s) ; *t++ = *s++ );
332
*t = '\0';
333
if ( mpq_set_str(c, cbuf, 0) < 0 ) return -2;
334
mpq_canonicalize (c);
335
for ( i = 0 ; i <= maxd ; i++ ) mpq_div (f[i], f[i], c);
336
}
337
return maxd;
338
}
339
340
341
int mpz_poly_expr (mpz_t f[], int maxd, char *expr)
342
{
343
static int init;
344
static mpz_t c;
345
char cbuf[4096];
346
char *s, *t;
347
int i;
348
int sign;
349
350
if ( ! init ) { mpz_init (c); init = 1; }
351
for ( i = 0 ; i <= maxd ; i++ ) mpz_set_ui(f[i], 0);
352
s = expr;
353
if ( *s == '[' || *s == '(' ) s++;
354
for(;;) {
355
while ( isspace(*s) ) s++;
356
// handle signs explicitly to deal with things like '+ -3' which gmp doesn't like and we need to handle
357
sign = 1;
358
if ( *s == '-' ) {
359
sign = -1;
360
for ( s++ ; isspace(*s) ; s++);
361
} else if ( *s == '+' ) {
362
for ( s++ ; isspace(*s) ; s++);
363
if ( *s == '-' ) {
364
sign = -1;
365
for ( s++ ; isspace(*s) ; s++);
366
}
367
}
368
if ( isdigit(*s) ) {
369
for ( t = cbuf ; isdigit(*s) ; *t++ = *s++ );
370
*t = '\0';
371
if ( mpz_set_str (c, cbuf, 0) < 0 ) return -2;
372
while ( isdigit(*s) ) s++;
373
} else if ( *s == 'x' || *s == 'X' ) {
374
mpz_set_ui (c, 1);
375
} else {
376
break;
377
}
378
if ( sign < 0 ) mpz_neg(c,c);
379
if ( *s == '*' ) s++;
380
if ( *s == 'x' || *s == 'X' ) {
381
s++;
382
if ( *s == '^' ) s++;
383
if ( isdigit(*s) ) {
384
i = atoi (s);
385
while ( isdigit(*s) ) s++;
386
if ( i > maxd ) return -2;
387
} else {
388
i = 1;
389
}
390
} else {
391
i = 0;
392
}
393
mpz_add (f[i], f[i], c);
394
}
395
for ( i = maxd ; i && ! mpz_sgn(f[i]) ; i-- );
396
if ( ! i && ! mpz_sgn(f[i]) ) return -1;
397
return i;
398
}
399
400
401
int ui_poly_expr (unsigned long f[], int maxd, char *expr)
402
{
403
static int init;
404
static mpz_t F[POLY_MAX_DEGREE+1];
405
int i, d;
406
407
if ( ! init ) { for ( d = 0 ; d <= POLY_MAX_DEGREE ; d++ ) mpz_init (F[d]); init = 1; }
408
d = mpz_poly_expr (F, maxd, expr);
409
if ( d < -1 ) return d;
410
for ( i = 0 ; i <= d ; i++ ) {
411
if ( mpz_sgn(F[i]) < 0 ) { err_printf("Attempt to parse poly with negative coefficients in ui_poly_expr\n"); exit (0); }
412
f[i] = mpz_get_ui(F[i]);
413
}
414
for ( ; i <= maxd ; i++ ) f[i] = 0;
415
return d;
416
}
417
418
419
int ui_poly_expr_mod_p (unsigned long f[], int maxd, char *expr, unsigned long p)
420
{
421
static int init;
422
static mpq_t F[POLY_MAX_DEGREE+1];
423
static mpz_t t;
424
unsigned long x;
425
int i, d;
426
427
if ( ! init ) { for ( d = 0 ; d <= POLY_MAX_DEGREE ; d++ ) mpq_init (F[d]); mpz_init (t); init = 1; }
428
d = mpq_poly_expr (F, maxd, expr);
429
if ( d < -1 ) return d;
430
for ( i = 0 ; i <= d ; i++ ) {
431
x = ui_inverse (mpz_fdiv_ui(mpq_denref(F[i]), p), p);
432
mpz_mul_ui (t, mpq_numref(F[i]), x);
433
f[i] = mpz_fdiv_ui (t, p);
434
}
435
for ( ; i <= maxd ; i++ ) f[i] = 0;
436
return d;
437
}
438
439
440
int i_poly_expr (long f[], int maxd, char *expr)
441
{
442
static int init;
443
static mpz_t F[POLY_MAX_DEGREE+1];
444
int i, d;
445
446
if ( ! init ) { for ( d = 0 ; d <= POLY_MAX_DEGREE ; d++ ) mpz_init (F[d]); init = 1; }
447
d = mpz_poly_expr (F, maxd, expr);
448
if ( d < -1 ) return d;
449
for ( i = 0 ; i <= d ; i++ ) f[i] = mpz_get_i(F[i]);
450
for ( ; i <= maxd ; i++ ) f[i] = 0;
451
return d;
452
}
453
454
455
int ff_poly_expr (ff_t f[], int maxd, char *expr)
456
{
457
static int init;
458
static mpz_t F[POLY_MAX_DEGREE+1];
459
int i, d;
460
461
if ( ! init ) { for ( d = 0 ; d <= POLY_MAX_DEGREE ; d++ ) mpz_init (F[d]); init = 1; }
462
d = mpz_poly_expr (F, maxd, expr);
463
if ( d < -1 ) return d;
464
for ( i = 0 ; i <= d ; i++ ) _ff_set_mpz(f[i], F[i]);
465
for ( ; i <= maxd ; i++ ) _ff_set_zero (f[i]);
466
return d;
467
}
468
469
470
void ff_poly_print (ff_t f[], int d_f)
471
{
472
char buf[4096];
473
474
ff_poly_sprint (buf, f, d_f);
475
out_printf ("%s\n", buf);
476
}
477
478
479
void ui_poly_print (unsigned long f[], int d_f)
480
{
481
char buf[4096];
482
483
ui_poly_sprint (buf, f, d_f);
484
out_printf ("%s\n", buf);
485
}
486
487
488
int ui_poly_sprint (char *s, unsigned long f[], int d_f)
489
{
490
char *t;
491
int i, n;
492
493
if ( d_f < 0 ) { strcpy (s, "[zero polynomial]"); return strlen(s); }
494
t = s;
495
if ( d_f >= 2 ) {
496
if ( f[d_f] != 1 ) t += sprintf (t, "[%lux^%d", f[d_f], d_f); else t += sprintf (t, "[x^%d", d_f);
497
} else if ( d_f == 1 ) {
498
if ( f[d_f] != 1 ) t += sprintf (t, "[%lux", f[d_f]); else t += sprintf (t, "[x");
499
} else {
500
t += sprintf (t, "[%lu", f[d_f]);
501
}
502
for ( i = d_f-1 ; i >= 0 ; i-- ) {
503
if ( f[i] ) {
504
if ( i >= 2 ) {
505
t += sprintf (t, " + %lux^%d", f[i], i);
506
} else if ( i == 1 ) {
507
t += sprintf (t, " + %lux", f[i]);
508
} else {
509
t += sprintf (t, " + %lu", f[i]);
510
}
511
}
512
}
513
*t++ = ']';
514
*t= '\0';
515
return t-s;
516
}
517
518
519
void i_poly_print (long f[], int d_f)
520
{
521
char buf[4096];
522
523
i_poly_sprint (buf, f, d_f);
524
out_printf ("%s\n", buf);
525
}
526
527
int i_poly_sprint (char *s, long f[], int d_f)
528
{
529
char *t;
530
int i, n;
531
532
if ( d_f < 0 ) { strcpy (s, "[zero polynomial]"); return strlen(s); }
533
t = s;
534
if ( d_f >= 2 ) {
535
if ( f[d_f] != 1 ) t += sprintf (t, "[%ldx^%d", f[d_f], d_f); else t += sprintf (t, "[x^%d", d_f);
536
} else if ( d_f == 1 ) {
537
if ( f[d_f] != 1 ) t += sprintf (t, "[%ldx", f[d_f]); else t += sprintf (t, "[x");
538
} else {
539
t += sprintf (t, "[%ld", f[d_f]);
540
}
541
for ( i = d_f-1 ; i >= 0 ; i-- ) {
542
if ( f[i] > 1) {
543
t += sprintf (t, " + %ld", f[i]);
544
} else if ( f[i] == 1 ) {
545
t += sprintf (t, " + ");
546
} else if ( f[i] == -1 ) {
547
t += sprintf (t, " - ");
548
} else if ( f[i] < -1 ) {
549
t += sprintf (t, " - %ld", -f[i]);
550
}
551
if ( f[i] ) {
552
if ( i >= 2 ) {
553
t += sprintf (t, "x^%d", i);
554
} else if ( i == 1 ) {
555
t += sprintf (t, "x", f[i]);
556
} else {
557
if ( f[i] == 1 || f[i] == -1 ) t += sprintf (t, "1");
558
}
559
}
560
}
561
*t++ = ']';
562
*t= '\0';
563
return t-s;
564
}
565
566
567
void mpz_poly_print (mpz_t f[], int d_f)
568
{
569
char buf[65536];
570
571
mpz_poly_sprint (buf, f, d_f);
572
out_printf ("%s\n", buf);
573
}
574
575
int mpz_poly_sprint (char *s, mpz_t f[], int d_f)
576
{
577
char *t;
578
int i, n;
579
580
if ( d_f < 0 ) { strcpy (s, "[zero polynomial]"); return strlen(s); }
581
t = s;
582
if ( d_f >= 2 ) {
583
if ( mpz_cmp_ui(f[d_f],1) != 0 ) {
584
t += gmp_sprintf (t, "[%Zdx^%d", f[d_f], d_f);
585
} else {
586
t += gmp_sprintf (t, "[x^%d", d_f);
587
}
588
} else if ( d_f == 1 ) {
589
if ( mpz_cmp_ui(f[d_f],1) != 0 ) {
590
t += gmp_sprintf (t, "[%Zdx", f[d_f]);
591
} else {
592
t += gmp_sprintf (t, "[x");
593
}
594
} else {
595
t += gmp_sprintf (t, "[%Zd", f[d_f]);
596
}
597
for ( i = d_f-1 ; i >= 0 ; i-- ) {
598
if ( mpz_sgn(f[i]) ) {
599
if ( i >= 2 ) {
600
if ( mpz_cmp_ui(f[i],1) != 0 ) {
601
t += gmp_sprintf (t, " + %Zdx^%d", f[i], i);
602
} else {
603
t += gmp_sprintf (t, " + x^%d", i);
604
}
605
} else if ( i == 1 ) {
606
if ( mpz_cmp_ui(f[i],1) != 0 ) {
607
t += gmp_sprintf (t, " + %Zdx", f[i]);
608
} else {
609
t += gmp_sprintf (t, " + x");
610
}
611
} else {
612
t += gmp_sprintf (t, " + %Zd", f[i]);
613
}
614
}
615
}
616
*t++ = ']';
617
*t= '\0';
618
return t-s;
619
}
620
621
622
int ff_poly_sprint (char *s, ff_t f[], int d_f)
623
{
624
char *t;
625
int i, n;
626
627
if ( d_f < 0 ) { strcpy (s, "[zero polynomial]"); return strlen(s); }
628
t = s;
629
if ( d_f >= 2 ) {
630
t += gmp_sprintf (t, "[%Zdx^%d", _ff_wrap_mpz(f[d_f],0), d_f);
631
} else if ( d_f == 1 ) {
632
t += gmp_sprintf (t, "[%Zdx", _ff_wrap_mpz(f[d_f],0));
633
} else {
634
t += gmp_sprintf (t, "[%Zd", _ff_wrap_mpz(f[d_f],0));
635
}
636
for ( i = d_f-1 ; i >= 0 ; i-- ) {
637
if ( _ff_nonzero(f[i]) ) {
638
if ( i >= 2 ) {
639
t += gmp_sprintf (t, " + %Zdx^%d", _ff_wrap_mpz(f[i],0), i);
640
} else if ( i == 1 ) {
641
t += gmp_sprintf (t, " + %Zdx", _ff_wrap_mpz(f[i],0));
642
} else {
643
t += gmp_sprintf (t, " + %Zd", _ff_wrap_mpz(f[i],0));
644
}
645
}
646
}
647
*t++ = ']';
648
*t= '\0';
649
return t-s;
650
}
651
652
// Converts rational coefficients to common denominator, sets f[i] to numerator of F[i] and returns common denominator
653
unsigned long i_poly_set_mpq (long f[], mpq_t F[], int d)
654
{
655
static mpz_t Q, x;
656
static int init;
657
unsigned long q;
658
int i;
659
660
if ( ! init ) { mpz_init (Q); mpz_init (x); init = 1; }
661
mpq_get_den (Q, F[0]);
662
for ( i = 1 ; i <= d ; i++ ) if ( mpq_sgn(F[i]) && mpz_cmp_ui(mpq_denref(F[i]),1) != 0 ) mpz_lcm (Q, Q, mpq_denref(F[i]));
663
q = mpz_get_ui (Q);
664
// handle integer case quickly
665
if ( q == 1 ) {
666
for ( i = 0 ; i <= d ; i++ ) {
667
if ( mpz_cmpabs_ui (mpq_numref(F[i]), LONG_MAX) > 0 ) return 0;
668
f[i] = mpz_get_i (mpq_numref(F[i]));
669
}
670
return 1;
671
}
672
for ( i = 0 ; i <= d ; i++ ) {
673
if ( mpq_sgn (F[i]) ) {
674
mpz_divexact (x, Q, mpq_denref(F[i]));
675
mpz_mul (x, x, mpq_numref(F[i]));
676
if ( mpz_cmpabs_ui (x, LONG_MAX) > 0 ) return 0;
677
f[i] = mpz_get_i (x);
678
} else {
679
f[i] = 0;
680
}
681
}
682
return q;
683
}
684
685
// Given rational poly g, computes integer poly f s.t. f/denom = F
686
void mpz_poly_set_mpq (mpz_t denom, mpz_t f[], mpq_t F[], int d)
687
{
688
int i;
689
690
mpq_get_den (denom, F[0]);
691
for ( i = 1 ; i <= d ; i++ ) if ( mpq_sgn(F[i]) && mpz_cmp_ui(mpq_denref(F[i]),1) != 0 ) mpz_lcm (denom, denom, mpq_denref(F[i]));
692
693
// handle integer case quickly
694
if ( mpz_cmp_ui(denom,1) == 0 ) {
695
for ( i = 0 ; i <= d ; i++ ) mpz_set (f[i], mpq_numref(F[i]));
696
} else {
697
for ( i = 0 ; i <= d ; i++ ) {
698
if ( mpq_sgn (F[i]) ) {
699
mpz_divexact (f[i], denom, mpq_denref(F[i]));
700
mpz_mul (f[i], f[i], mpq_numref(F[i]));
701
} else {
702
mpz_set_ui (f[i], 0);
703
}
704
}
705
}
706
return;
707
}
708
709
710
int ff_poly_set_rational_mpz (ff_t f[], mpz_t F[], int d, mpz_t denom)
711
{
712
_ff_t_declare_reg z;
713
int i;
714
#if FF_INIT_REQUIRED
715
static int init;
716
if ( ! init ) { _ff_init (z); init = 1; }
717
#endif
718
719
_ff_set_mpz (z, denom);
720
if ( _ff_zero(z) ) return 0;
721
ff_invert (z, z);
722
for ( i = 0 ; i <= d ; i++ ) {
723
_ff_set_mpz (f[i], F[i]);
724
if ( _ff_nonzero(f[i]) ) ff_mult (f[i], f[i], z);
725
}
726
return 1;
727
}
728
729
730
int ui_poly_set_rational_mpz_mod_p (unsigned long f[], mpz_t F[], int d, mpz_t denom, unsigned long p)
731
{
732
static mpz_t t;
733
static int init;
734
unsigned long z;
735
int i;
736
737
if ( ! init ) { mpz_init (t); init = 1; }
738
z = mpz_fdiv_ui (denom, p);
739
z = ui_inverse (z, p);
740
if ( ! z ) return 0;
741
for ( i = 0 ; i <= d ; i++ ) {
742
if ( mpz_sgn(F[i]) ) {
743
mpz_mul_ui (t, F[i], z);
744
f[i] = mpz_fdiv_ui (t, p);
745
} else {
746
f[i] = 0;
747
}
748
}
749
return 1;
750
}
751
752
753
void ff_poly_eval (ff_t o[1], ff_t f[], int d, ff_t x[1])
754
{
755
_ff_t_declare_reg t,y;
756
register int i;
757
#if FF_INIT_REQUIRED
758
static int init;
759
if ( ! init ) { _ff_init (t); _ff_init (y); init = 1; }
760
#endif
761
if ( d < 0 ) { _ff_set_zero (o[0]); return; }
762
763
_ff_set (y,f[d]);
764
_ff_set (t,x[0]);
765
for ( i = d-1 ; i >= 0 ; i-- ) ff_multadd(y,y,t,f[i]);
766
_ff_set(o[0],y);
767
return;
768
}
769
770
771
void ff_poly_twist_mpz (ff_t g[], mpz_t F[], int d)
772
{
773
_ff_t_declare f[POLY_MAX_DEGREE+1];
774
int i;
775
#if FF_INIT_REQUIRED
776
static int init;
777
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) _ff_init(f[i]); init = 1; }
778
#endif
779
if ( d > POLY_MAX_DEGREE ) { err_printf ("ff_poly_twist_mpz: exceeded max degree %d > %d\n", d, POLY_MAX_DEGREE); exit (0); }
780
for ( i = 0 ; i <= d ; i++ ) _ff_set_mpz (f[i], F[i]);
781
ff_poly_twist (g, f, d);
782
return;
783
}
784
785
/*
786
Computes the quadratic twist of y^2=f(x) by a non-residue a in F_p, giving the curve a*y^2=f(x), assuming f(x) has odd degree.
787
788
We put this in a more convenient isomorphic form by replacing y with y/a^{g+1} and x with x/a and multiplying
789
both sides by a^{2g+1}. This will make the result monic if f is, and keep any zero coefficients zero.
790
791
Overlap of f and g is ok.
792
*/
793
void ff_poly_twist (ff_t g[], ff_t f[], int d)
794
{
795
_ff_t_declare a, b;
796
int i;
797
#if FF_INIT_REQUIRED
798
static int init;
799
if ( ! init ) { _ff_init (a); _ff_init(b); init = 1; }
800
#endif
801
if ( d > POLY_MAX_DEGREE ) { err_printf ("ff_poly_twist: exceeded max degree %d > %d\n", d, POLY_MAX_DEGREE); exit (0); }
802
if ( ! (d&0x1) ) { err_printf ("ff_poly_twist: degree must be odd.\n"); exit (0); }
803
_ff_set (g[d], f[d]); // leading coefficient unchanged - means twist is monic if f is
804
_ff_set (b, _ff_2g); // use the generator of the 2-Sylow as our non-residue
805
_ff_set (a,b);
806
for ( i = d-1 ; i >= 0 ; i-- ) {
807
ff_mult (g[i], b, f[i]); // g[i] = a^{d-i}f[i] for i = d-1 down to 0
808
ff_mult (b, b, a);
809
}
810
return;
811
}
812
813
// overlap not ok
814
void ff_poly_derivative (ff_t g[], int *pd_g, ff_t f[], int d_f)
815
{
816
_ff_t_declare a;
817
int i;
818
#if FF_INIT_REQUIRED
819
static int init;
820
if ( ! init ) { _ff_init (a); init = 1; }
821
#endif
822
823
_ff_set_one (a);
824
for ( i = 0 ; i < d_f ; i++ ) {
825
_ff_mult (g[i], a, f[i+1]);
826
_ff_inc(a);
827
}
828
for ( i = d_f-1 ; i >= 0 && _ff_zero(g[i]) ; i-- );
829
*pd_g = i;
830
}
831
832
833
// overlap not ok - use poly_addto instead
834
void ff_poly_add (ff_t c[], int *pd_c, ff_t a[], int d_a, ff_t b[], int d_b)
835
{
836
int d_c;
837
int i;
838
839
if ( d_a < 0 ) { ff_poly_copy (c, pd_c, b, d_b); return; }
840
if ( d_b < 0 ) { ff_poly_copy (c, pd_c, a, d_a); return; }
841
842
d_c = d_a;
843
if ( d_b > d_a ) d_c = d_b;
844
for ( i = 0 ; i <= d_c ; i++ ) {
845
_ff_set_zero (c[i]);
846
if ( i <= d_a ) _ff_addto (c[i], a[i]);
847
if ( i <= d_b ) _ff_addto (c[i], b[i]);
848
}
849
for ( i = d_c ; i >= 0 && _ff_zero(c[i]) ; i-- );
850
*pd_c = i;
851
}
852
853
// overlap ok
854
void ff_poly_addto (ff_t c[], int *pd_c, ff_t b[], int d_b)
855
{
856
int i;
857
858
if ( d_b < 0 ) return;
859
for ( i = 0 ; i <= d_b ; i++ ) {
860
if ( i > *pd_c ) {
861
_ff_set (c[i], b[i]);
862
*pd_c = i;
863
} else {
864
_ff_addto (c[i], b[i]);
865
}
866
}
867
for ( i = *pd_c ; i >= 0 && _ff_zero(c[i]) ; i-- );
868
*pd_c = i;
869
}
870
871
872
// overlap not ok
873
void ff_poly_neg (ff_t c[], int *pd_c, ff_t b[], int d_b)
874
{
875
int i;
876
877
*pd_c = d_b;
878
for ( i = 0 ; i <= d_b ; i++ ) _ff_neg(c[i], b[i]);
879
}
880
881
882
// overlap not ok
883
void ff_poly_monic (ff_t c[], int *pd_c, ff_t b[], int d_b)
884
{
885
_ff_t_declare z;
886
int i;
887
#if FF_INIT_REQUIRED
888
static int init;
889
if ( ! init ) { _ff_init (z); init = 1; }
890
#endif
891
892
if ( d_b < 0 || _ff_one (b[d_b]) ) { ff_poly_copy (c, pd_c, b, d_b); return; }
893
_ff_invert (z, b[d_b]);
894
*pd_c = d_b;
895
for ( i = 0 ; i <= d_b ; i++ ) _ff_mult(c[i],z,b[i]);
896
}
897
898
899
void ff_poly_sub (ff_t c[], int *pd_c, ff_t a[], int d_a, ff_t b[], int d_b)
900
{
901
int d_c;
902
int i;
903
904
if ( d_a < 0 ) { ff_poly_neg (c, pd_c, b, d_b); return; }
905
if ( d_b < 0 ) { ff_poly_copy (c, pd_c, a, d_a); return; }
906
907
d_c = d_a;
908
if ( d_b > d_a ) d_c = d_b;
909
for ( i = 0 ; i <= d_c ; i++ ) {
910
_ff_set_zero (c[i]);
911
if ( i <= d_a ) _ff_addto (c[i], a[i]);
912
if ( i <= d_b ) _ff_subfrom (c[i], b[i]);
913
}
914
for ( i = d_c ; i >= 0 && _ff_zero(c[i]) ; i-- );
915
*pd_c = i;
916
}
917
918
919
void ff_poly_mult (ff_t c[], int *pd_c, ff_t a[], int d_a, ff_t b[], int d_b)
920
{
921
_ff_t_declare s, t[POLY_MAX_DEGREE+1];
922
int d_t;
923
int i, j;
924
#if FF_INIT_REQUIRED
925
static int init;
926
if ( ! init ) { _ff_init (s); for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) _ff_init (t[i]); init = 1; }
927
#endif
928
929
if ( d_a < 0 || d_b < 0 ) { *pd_c = -1; return; }
930
if ( _ff_zero(a[d_a]) || _ff_zero(b[d_b]) ) { err_printf ("zero leading coefficient in ff_poly_mult!\n"); ff_poly_print (a, d_a); puts(""); ff_poly_print (b, d_b); exit (0); }
931
932
d_t = d_a + d_b;
933
for ( i = 0 ; i <= d_t ; i++ ) _ff_set_zero (t[i]);
934
935
// multiply into temporary storage to ensure we handle duplicated inputs
936
for ( i = 0 ; i <= d_a ; i++ ) {
937
for ( j = 0 ; j <= d_b ; j++ ) {
938
_ff_mult (s, a[i], b[j]);
939
_ff_addto (t[i+j], s);
940
}
941
}
942
ff_poly_copy (c, pd_c, t, d_t);
943
}
944
945
946
// overlap is ok. Does not require any inversions if b is monic
947
void ff_poly_div (ff_t q[], int *pd_q, ff_t r[], int *pd_r, ff_t a[], int d_a, ff_t b[], int d_b)
948
{
949
_ff_t_declare_reg s, t, x;
950
ff_t c[POLY_MAX_DEGREE+1];
951
register int i, j;
952
int d_c, d_q, d_r, d_s;
953
#if FF_INIT_REQUIRED
954
static int init;
955
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { _ff_init (c[i]); } _ff_init (s); _ff_init (t); _ff_init (x); init = 1; }
956
#endif
957
if ( d_b < 0 ) { err_printf ("poly division by zero in ff_poly_div!\n"); exit (0); }
958
if ( _ff_zero(b[d_b]) ) { err_printf ("zero leading coefficient in ff_poly_div!\n"); exit (0); }
959
if ( d_a >= 0 && _ff_zero(a[d_a]) ) { err_printf ("zero leading coefficient in ff_poly_div!\n"); exit (0); }
960
961
ff_poly_copy (c, &d_c, b, d_b); // copy b to ensure we handle overlapping input/output case
962
ff_poly_copy (r, &d_r, a, d_a);
963
d_q = -1;
964
// the code duplication below saves a mult and/or a test inside the loop
965
if ( ! _ff_one(c[d_c]) ) {
966
_ff_invert (x, c[d_c]);
967
while ( d_r >= d_c ) {
968
_ff_mult (s, x, r[d_r]);
969
d_s = d_r - d_c;
970
if ( d_s > d_q ) {
971
for ( j = d_q+1 ; j < d_s ; j++ ) _ff_set_zero (q[j]);
972
d_q = d_s;
973
_ff_set (q[d_q], s);
974
} else {
975
_ff_addto (q[d_s], s);
976
}
977
for ( i = 0 ; i < d_c ; i++ ) {
978
_ff_mult (t, s, c[i]);
979
_ff_subfrom (r[i+d_s], t);
980
}
981
_ff_set_zero(r[d_r]);
982
while ( d_r && _ff_zero (r[d_r]) ) d_r--;
983
if ( _ff_zero (r[d_r]) ) d_r = -1;
984
}
985
} else {
986
while ( d_r >= d_c ) {
987
_ff_set (s, r[d_r]);
988
d_s = d_r - d_c;
989
if ( d_s > d_q ) {
990
for ( j = d_q+1 ; j < d_s ; j++ ) _ff_set_zero (q[j]);
991
d_q = d_s;
992
_ff_set (q[d_q], s);
993
} else {
994
_ff_addto (q[d_s], s);
995
}
996
for ( i = 0 ; i < d_c ; i++ ) {
997
_ff_mult (t, s, c[i]);
998
_ff_subfrom (r[i+d_s], t);
999
}
1000
_ff_set_zero(r[d_r]);
1001
while ( d_r && _ff_zero (r[d_r]) ) d_r--;
1002
if ( _ff_zero (r[d_r]) ) d_r = -1;
1003
}
1004
}
1005
*pd_q = d_q;
1006
*pd_r = d_r;
1007
}
1008
1009
1010
void ff_poly_mod (ff_t g[], int *pd_g, ff_t a[], int d_a, ff_t f[], int d_f)
1011
{
1012
_ff_t_declare q[POLY_MAX_DEGREE+1];
1013
int i;
1014
int d_q;
1015
#if FF_INIT_REQUIRED
1016
static int init;
1017
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { _ff_init (q[i]); } init = 1; }
1018
#endif
1019
ff_poly_div (q, &d_q, g, pd_g, a, d_a, f, d_f);
1020
}
1021
1022
// computes h=af-bg of degree less than max(d_f,d_g) (f and g must both be non-zero). One of a or b (or both) is a unit
1023
// h is divisible by gcd(f,g) but could be (a lot) bigger than f mod g or g mod f
1024
// this function is most useful when d_f~d_g or both are small
1025
void ff_poly_reduce (ff_t h[], int *pd_h, ff_t f[], int d_f, ff_t g[], int d_g)
1026
{
1027
_ff_t_declare_reg t0,t1,t2,t3;
1028
register int i,j;
1029
#if FF_INIT_REQUIRED
1030
static int init;
1031
if ( ! init ) { _ff_init (t0); _ff_init (t1); _ff_init(t2); _ff_init (t3); init = 1; }
1032
#endif
1033
1034
if ( d_f < 0 || d_g < 0 ) { puts ("Zero polynomial in ff_poly_reduce!"); exit (0); }
1035
if ( ! d_f || ! d_g ) { _ff_set_one(h[0]); *pd_h=0; return; }
1036
1037
// avoid unnecessary copying, but allow overlap of h with f or g
1038
_ff_set(t0,f[d_f]);
1039
_ff_set(t1,g[d_g]);
1040
if ( d_f > d_g ) {
1041
j = d_f-d_g;
1042
for ( i = d_f-1 ; i >= j ; i-- ) {
1043
_ff_mult(t2,t1,f[i]);
1044
_ff_mult(t3,t0,g[i-j]);
1045
_ff_sub(h[i],t2,t3);
1046
}
1047
for ( ; i >= 0 ; i-- ) ff_mult(h[i],f[i],t1);
1048
for ( i = d_f-1 ; i >= 0 ; i-- ) if ( ! _ff_zero(h[i]) ) break;
1049
*pd_h = i;
1050
} else {
1051
j = d_g-d_f;
1052
for ( i = d_g-1 ; i >= j ; i-- ) {
1053
_ff_mult(t2,t0,g[i]);
1054
_ff_mult(t3,t1,f[i-j]);
1055
_ff_sub(h[i],t2,t3);
1056
}
1057
for ( ; i >= 0 ; i-- ) ff_mult(h[i],g[i],t0);
1058
for ( i = d_g-1 ; i >= 0 ; i-- ) if ( ! _ff_zero(h[i]) ) break;
1059
*pd_h = i;
1060
}
1061
}
1062
1063
// note that g is not made monic (and need not be, even if a and b both are)
1064
void ff_poly_gcd (ff_t g[], int *pd_g, ff_t a[], int d_a, ff_t b[], int d_b)
1065
{
1066
_ff_t_declare q[POLY_MAX_DEGREE+1], r[POLY_MAX_DEGREE+1], s[POLY_MAX_DEGREE+1], t[POLY_MAX_DEGREE+1];
1067
int d_q, d_r, d_s, d_t;
1068
int i, j;
1069
#if FF_INIT_REQUIRED
1070
static int init;
1071
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { _ff_init (q[i]); _ff_init (r[i]); _ff_init(s[i]); _ff_init (t[i]); } init = 1; }
1072
#endif
1073
if ( d_a > POLY_MAX_DEGREE || d_b > POLY_MAX_DEGREE ) { err_printf ("Exceeded POLY_MAX_DEGREE in ff_poly_gcd!\n"); exit (0); }
1074
ff_poly_copy (s, &d_s, a, d_a);
1075
ff_poly_copy (t, &d_t, b, d_b);
1076
while ( d_t >= 0 ) {
1077
ff_poly_div (q, &d_q, r, &d_r, s, d_s, t, d_t);
1078
ff_poly_copy (s, &d_s, t, d_t);
1079
ff_poly_copy (t, &d_t, r, d_r);
1080
}
1081
ff_poly_copy (g, pd_g, s, d_s);
1082
if ( *pd_g==0 ) _ff_set_one(g[0]);
1083
return;
1084
}
1085
1086
// compute gcd using poly_reduce - faster than ff_poly_gcd for small or roughly equal size polys but slower if one poly is much bigger than the other
1087
// uses 2n^2+O(n) M+A and *no* inversions
1088
void ff_poly_gcd_red (ff_t g[], int *pd_g, ff_t a[], int d_a, ff_t b[], int d_b)
1089
{
1090
_ff_t_declare s[POLY_MAX_DEGREE+1], t[POLY_MAX_DEGREE+1];
1091
int d_s, d_t;
1092
int i, j;
1093
#if FF_INIT_REQUIRED
1094
static int init;
1095
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { _ff_init (q[i]); _ff_init (r[i]); _ff_init(s[i]); _ff_init (t[i]); } init = 1; }
1096
#endif
1097
if ( d_a > POLY_MAX_DEGREE || d_b > POLY_MAX_DEGREE ) { err_printf ("Exceeded POLY_MAX_DEGREE in ff_poly_gcd!\n"); exit (0); }
1098
if ( d_a < 0 ) { ff_poly_copy(g,pd_g, b,d_b); return; }
1099
if ( d_b < 0 ) { ff_poly_copy(g,pd_g, a,d_a); return; }
1100
1101
// reduce into s first, avoid copying
1102
ff_poly_reduce (s, &d_s, a, d_a, b, d_b);
1103
if ( d_s < 0 ) { if ( d_a < d_b ) ff_poly_copy (g,pd_g,a,d_a); else ff_poly_copy(g,pd_g,b,d_b); return; }
1104
if ( d_s == 0 ) { *pd_g = 0; _ff_set_one(g[0]); return; }
1105
if ( d_a < d_b ) {
1106
ff_poly_reduce (t, &d_t, s, d_s, a, d_a);
1107
if ( d_t < 0 ) { if ( d_a < d_s ) ff_poly_copy (g,pd_g,a,d_a); else ff_poly_copy(g,pd_g,s,d_s); return; }
1108
if ( d_t == 0 ) { *pd_g = 0; _ff_set_one(g[0]); return; }
1109
if ( d_s > d_a ) ff_poly_copy(s,&d_s,a,d_a); // can't easily avoid a copy in this case
1110
} else {
1111
ff_poly_reduce (t, &d_t, s, d_s, b, d_b);
1112
if ( d_t < 0 ) { if ( d_b < d_s ) ff_poly_copy (g,pd_g,b,d_b); else ff_poly_copy(g,pd_g,s,d_s); return; }
1113
if ( d_t == 0 ) { *pd_g = 0; _ff_set_one(g[0]); return; }
1114
if ( d_s > d_b ) ff_poly_copy(s,&d_s,b,d_b); // can't easily avoid a copy in this case
1115
}
1116
1117
// we now have polys in s and t of degree > 0
1118
while ( d_s > 0 && d_t > 0 ) {
1119
if ( d_s < d_t ) {
1120
ff_poly_reduce (t, &d_t, s, d_s, t, d_t);
1121
} else {
1122
ff_poly_reduce (s, &d_s, s, d_s, t, d_t);
1123
}
1124
}
1125
if ( d_s < d_t ) {
1126
if ( d_s < 0 ) { ff_poly_copy (g,pd_g,t,d_t); return; }
1127
} else {
1128
if ( d_t < 0 ) { ff_poly_copy (g,pd_g,s,d_s); return; }
1129
}
1130
*pd_g = 0; _ff_set_one(g[0]);
1131
return;
1132
}
1133
1134
// [CCANT] algorithm 3.2.2. None of the polynomials can overlap
1135
void ff_poly_gcdext (ff_t D[], int *pd_D, ff_t u[], int *pd_u, ff_t v[], int *pd_v, ff_t a[], int d_a, ff_t b[], int d_b)
1136
{
1137
_ff_t_declare q[POLY_MAX_DEGREE+1], r[POLY_MAX_DEGREE+1], t[POLY_MAX_DEGREE+1];
1138
_ff_t_declare t2[POLY_MAX_DEGREE+1], v1[POLY_MAX_DEGREE+1], v3[POLY_MAX_DEGREE+1];
1139
int d_q, d_r, d_t, d_t2, d_v1, d_v3;
1140
int i, j;
1141
#if FF_INIT_REQUIRED
1142
static int init;
1143
if ( ! init ) {
1144
for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ )
1145
{ _ff_init (q[i]); _ff_init (r[i]); _ff_init(s[i]); _ff_init (t[i]); _ff_init (t2[i]); _ff_init (v1[i]); _ff_init (v3[i]); }
1146
init = 1;
1147
}
1148
#endif
1149
// GCd(0,b) = b = 0*a+1*b
1150
if ( d_a < 0 ) {
1151
ff_poly_copy (D, pd_D, b, d_b);
1152
*pd_v = 0; _ff_set_one(v[0]);
1153
*pd_u = -1;
1154
return;
1155
}
1156
// GCD(a,0) = a = 1*a+0*b
1157
if ( d_b < 0 ) {
1158
ff_poly_copy (D, pd_D, a, d_a);
1159
*pd_u= 0; _ff_set_one(u[0]);
1160
*pd_v = -1;
1161
return;
1162
}
1163
1164
if ( d_a > POLY_MAX_DEGREE || d_b > POLY_MAX_DEGREE ) { err_printf ("Exceeded POLY_MAX_DEGREE in ff_poly_gcd!\n"); exit (0); }
1165
*pd_u = 0; _ff_set_one(u[0]); // u = 1
1166
ff_poly_copy (D, pd_D, a, d_a); // D = a
1167
d_v1 = -1; // v1 = 0
1168
ff_poly_copy (v3, &d_v3, b, d_b); // v3 = b
1169
1170
while ( d_v3 >= 0 ) {
1171
ff_poly_div (q, &d_q, r, &d_r, D, *pd_D, v3, d_v3);
1172
ff_poly_mult (t2, &d_t2, v1, d_v1, q, d_q);
1173
ff_poly_sub (t, &d_t, u, *pd_u, t2, d_t2); // t = u-v1q
1174
ff_poly_copy (u, pd_u, v1, d_v1); // u = v1
1175
ff_poly_copy (D, pd_D, v3, d_v3); // D = v3
1176
ff_poly_copy (v1, &d_v1, t, d_t); // v1 = t
1177
ff_poly_copy (v3, &d_v3, r, d_r); // v3 = r
1178
}
1179
ff_poly_mult (v3, &d_v3, a, d_a, u, *pd_u);
1180
ff_poly_sub (v1, &d_v1, D, *pd_D, v3, d_v3);
1181
ff_poly_div (v, pd_v, r, &d_r, v1, d_v1, b, d_b); // v = (D-au)/b (exact division)
1182
if ( d_r != -1 ) { err_printf ("Division not exact in ff_poly_gcdext! r = "); ff_poly_print(r,d_r); exit (0); }
1183
return;
1184
}
1185
1186
1187
void ff_poly_exp_mod (ff_t g[], int *pd_g, ff_t a[], int d_a, mpz_t e, ff_t f[], int d_f)
1188
{
1189
_ff_t_declare h[POLY_MAX_DEGREE+1];
1190
int d_h;
1191
int i, j, t;
1192
#if FF_INIT_REQUIRED
1193
static int init;
1194
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { _ff_init (h[i]); } init = 1; }
1195
#endif
1196
if ( d_f <= 1 ) { err_printf ("Invalid modulus in ff_poly_exp_mod, degree must be > 1\n"); exit (0); }
1197
if ( _ff_zero(f[d_f]) ) { err_printf ("zero leading coefficient in ff_poly_exp_mod!\n"); exit (0); }
1198
if ( ! mpz_sgn (e) ) { _ff_set_one(g[0]); *pd_g = 0; return; }
1199
if ( d_a < 0 ) { *pd_g = 0; return; }
1200
if ( _ff_zero(a[d_a]) ) { err_printf ("zero leading coefficient in ff_poly_mult!\n"); exit (0); }
1201
1202
_ff_set_one (h[0]);
1203
d_h = 0;
1204
t = mpz_sizeinbase (e, 2) - 1;
1205
while ( t >= 0 ) {
1206
if ( mpz_tstbit (e, t) ) {
1207
ff_poly_mult (h, &d_h, h, d_h, a, d_a);
1208
ff_poly_mod (h, &d_h, h, d_h, f, d_f);
1209
}
1210
if ( t > 0 ) {
1211
ff_poly_mult (h, &d_h, h, d_h, h, d_h);
1212
ff_poly_mod (h, &d_h, h, d_h, f, d_f);
1213
}
1214
t--;
1215
}
1216
ff_poly_copy (g, pd_g, h, d_h);
1217
}
1218
1219
// computes x^n mod f for monic f
1220
void ff_poly_xn_mod (ff_t g[], int *pd_g, mpz_t e, ff_t f[], int d_f)
1221
{
1222
_ff_t_declare h[POLY_MAX_DEGREE+1], w[2*POLY_MAX_DEGREE];
1223
_ff_t_declare_reg t0;
1224
register int i, j, m, n, t;
1225
#if FF_INIT_REQUIRED
1226
static int init;
1227
if ( ! init ) { for ( i = 0 ; i <= POLY_MAX_DEGREE ; i++ ) { _ff_init (h[i]); } init = 1; }
1228
#endif
1229
if ( d_f <= 1 ) { err_printf ("Invalid modulus in ff_poly_exp_mod, degree must be > 1\n"); exit (0); }
1230
if ( ! _ff_one(f[d_f]) ) { err_printf ("nonmonic in ff_poly_exp_mod!\n"); exit (0); }
1231
if ( ! mpz_sgn (e) ) { _ff_set_one(g[0]); *pd_g = 0; return; }
1232
1233
n = d_f;
1234
for ( m = d_f-1 ; _ff_zero(f[m]) ; m-- ); // m is the index of first nonzero nonleading coefficient of f
1235
_ff_set_one(h[1]); _ff_set_zero(h[0]);
1236
for ( i = 2 ; i < n ; i++ ) _ff_set_zero(h[i]);
1237
t = mpz_sizeinbase (e, 2) - 2;
1238
while ( t >= 0 ) {
1239
if ( mpz_tstbit (e, t) ) {
1240
// square h and multiply it by x, into w
1241
for ( i = 0 ; i < n ; i++ ) { _ff_set_zero(w[2*i]); _ff_square(w[2*i+1],h[i]); }
1242
for ( i = 0 ; i < n ; i++ ) for ( j = 0 ; j < i ; j++ ) { _ff_mult(t0,h[i],h[j]); _ff_x2(t0); _ff_addto(w[i+j+1],t0); }
1243
} else {
1244
// square h into w
1245
for ( i = 0 ; i < n ; i++ ) { _ff_square(w[2*i],h[i]); _ff_set_zero(w[2*i+1]); }
1246
for ( i = 0 ; i < n ; i++ ) for ( j = 0 ; j < i ; j++ ) { _ff_mult(t0,h[i],h[j]); _ff_x2(t0); _ff_addto(w[i+j],t0); }
1247
}
1248
// reduce w mod f into h
1249
for ( i = 2*n-1 ; i >= n ; i-- ) if ( ! _ff_zero(w[i]) ) for ( j = 0 ; j <= m ; j++ ) { _ff_mult(t0,w[i],f[j]); _ff_subfrom(w[i-n+j],t0); }
1250
for ( i = 0 ; i < n ; i++ ) _ff_set(h[i],w[i]);
1251
t--;
1252
}
1253
for ( i = n-1 ; i >= 0 && _ff_zero(h[i]) ; i-- );
1254
for ( *pd_g = i ; i >= 0 ; i-- ) _ff_set(g[i],h[i]);
1255
}
1256
1257
1258
// Algorithm IPT from Shoup "A Computational Introduction to Number Theory and Algebra" p. 463
1259
int ff_poly_irreducible (ff_t f[], int d_f, int *pnroots)
1260
{
1261
static mpz_t q;
1262
static int init;
1263
_ff_t_declare h[POLY_MAX_DEGREE+1], X[2], t[POLY_MAX_DEGREE+1];
1264
int d, d_h, d_t, d_X;
1265
int i;
1266
1267
if ( ! init ) { mpz_init(q); init = 1; }
1268
1269
if ( d_f < 1 ) { err_printf ("Invalid input to ff_poly_irreducible, must have degree > 0\n"); exit (0); }
1270
if ( ! _ff_one(f[d_f]) ) { err_printf ("Input to ff_poly_irreducible must be monic.\n"); exit (0); }
1271
if ( d_f == 1 ) {
1272
if ( pnroots ) *pnroots = 1;
1273
return 1;
1274
}
1275
1276
_ff_set_one (h[1]); _ff_set_zero (h[0]);
1277
d_h = 1;
1278
_ff_set_zero (X[0]); _ff_set_one (X[1]); ff_negate (X[1]);
1279
d_X = 1;
1280
mpz_set(q,_ff_mpz_p);
1281
for ( i = 1 ; i <= d_f/2 ; i++ ) {
1282
if ( i > 1 ) mpz_mul(q,q,_ff_mpz_p);
1283
ff_poly_xn_mod (h, &d_h, q, f, d_f);
1284
ff_poly_add (t, &d_t, h, d_h, X, d_X);
1285
ff_poly_gcd (t, &d_t, t, d_t, f, d_f);
1286
if ( d_t > 0 ) break;
1287
}
1288
if ( i <= d_f/2 ) {
1289
if ( pnroots ) {
1290
if ( i == 1 ) {
1291
*pnroots = d_t;
1292
} else {
1293
*pnroots = 0;
1294
}
1295
}
1296
return 0;
1297
}
1298
return 1;
1299
1300
}
1301
1302
/*
1303
Counts the distinct factors of f using the standard distinct degree factorization algorithm (just a straight-forward generalization of the irreducibiilty test)
1304
*/
1305
int ff_poly_factors (ff_t f[], int d_f)
1306
{
1307
static mpz_t q;
1308
static int init;
1309
_ff_t_declare g[POLY_MAX_DEGREE+1], h[POLY_MAX_DEGREE+1], X[2], t[POLY_MAX_DEGREE+1], r[POLY_MAX_DEGREE+1], s[POLY_MAX_DEGREE+1], v[POLY_MAX_DEGREE];
1310
int d, d_g, d_r, d_s, d_h, d_t, d_X, d_v;
1311
int i, n;
1312
1313
if ( ! init ) { mpz_init(q); init = 1; }
1314
if ( d_f < 1 ) { err_printf ("Invalid input to ff_poly_factors, must have degree > 0\n"); exit (0); }
1315
if ( ! _ff_one(f[d_f]) ) { err_printf ("Input to ff_poly_factors must be monic.\n"); exit (0); }
1316
if ( d_f == 1 ) return 1;
1317
1318
_ff_set_one (h[1]); _ff_set_zero (h[0]);
1319
d_h = 1;
1320
_ff_set_zero (X[0]); _ff_set_one (X[1]); ff_negate (X[1]);
1321
d_X = 1;
1322
ff_poly_monic (g, &d_g, f, d_f);
1323
n = 0;
1324
mpz_set(q,_ff_mpz_p);
1325
for ( i = 1 ; i <= d_g/2 ; i++ ) {
1326
if ( i > 1 ) mpz_mul(q,q,_ff_mpz_p);
1327
ff_poly_xn_mod (h, &d_h, q, g, d_g); // h = x^{p^i}
1328
ff_poly_add (t, &d_t, h, d_h, X, d_X); // t = x^{p^i}-x
1329
do {
1330
ff_poly_gcd_red (s, &d_s, t, d_t, g, d_g);
1331
if ( i > 1 && d_s % i ) { err_printf ("Unexpected gcd in ff_poly_factors, degree not a multiple of i\n"); exit (0); }
1332
n += d_s / i;
1333
if ( d_s > 0 ) {
1334
ff_poly_div (v, &d_v, r, &d_r, g, d_g, s, d_s);
1335
if ( d_r > -1 ) { err_printf ("Error in ff_poly_factors - division by gcd not exact, remainder:"); ff_poly_print(r, d_r); exit(0); }
1336
ff_poly_monic(g,&d_g,v,d_v);
1337
}
1338
} while ( d_s > 0 );
1339
}
1340
if ( d_g ) n++;
1341
return n;
1342
1343
}
1344
1345
// returns the degree of gcd(f,x^p-x) which will be the number of roots if f is square-free and will always be non-zero if f has a root over F_p
1346
int ff_poly_roots (ff_t f[], int d_f)
1347
{
1348
_ff_t_declare g[POLY_MAX_DEGREE+1], h[POLY_MAX_DEGREE+1], X[2], t[POLY_MAX_DEGREE+1], r[POLY_MAX_DEGREE+1], s[POLY_MAX_DEGREE+1];
1349
int d, d_g, d_r, d_s, d_h, d_t, d_X;
1350
int i, n;
1351
1352
if ( d_f < 1 ) { err_printf ("Invalid input to ff_poly_has_root, must have degree > 0\n"); exit (0); }
1353
if ( ! _ff_one(f[d_f]) ) { err_printf ("Input to ff_poly_roots must be monic.\n"); exit (0); }
1354
if ( d_f == 1 ) return 1;
1355
1356
_ff_set_one (h[1]); _ff_set_zero (h[0]);
1357
d_h = 1;
1358
_ff_set_zero (X[0]); _ff_set_one (X[1]); ff_negate (X[1]);
1359
d_X = 1;
1360
ff_poly_monic (g, &d_g, f, d_f);
1361
ff_poly_xn_mod (h, &d_h, _ff_mpz_p, g, d_g); // h = x^p
1362
ff_poly_add (t, &d_t, h, d_h, X, d_X); // t = x^p-x
1363
ff_poly_gcd_red (s, &d_s, t, d_t, g, d_g);
1364
return d_s;
1365
}
1366
1367
1368
// This function only returns bad primes that fit in an unsigned long - larger primes are ignored.
1369
int mpz_poly_bad_primes (unsigned long bad[], int maxbad, mpz_t f[], int d)
1370
{
1371
static int init;
1372
static mpz_t D, P;
1373
unsigned long h[MPZ_MAX_FACTORS];
1374
int w;
1375
1376
if ( ! init ) { mpz_init (D); mpz_init (P); init = 1; }
1377
1378
mpz_poly_discriminant(D, f, d);
1379
if ( ! mpz_sgn(D) ) return -1;
1380
w = mpz_factor_small (bad, h, P, D, _ui_min(maxbad,MPZ_MAX_FACTORS), 128);
1381
if ( ! w ) { err_printf ("unable to factor_small %Zd\n", D); return -2; }
1382
return w;
1383
}
1384
1385
1386
// This function only returns bad primes that fit in an unsigned long - larger primes are ignored.
1387
int mpq_poly_bad_primes (unsigned long bad[], int maxbad, mpq_t f[], int d)
1388
{
1389
static int init;
1390
static mpq_t D;
1391
static mpz_t P, Q;
1392
unsigned long p1[MPZ_MAX_FACTORS], p2[MPZ_MAX_FACTORS];
1393
unsigned long h[MPZ_MAX_FACTORS];
1394
int i, j, k, w1, w2;
1395
1396
if ( ! init ) { mpq_init (D); mpz_init (P); mpz_init (Q); init = 1; }
1397
mpq_poly_discriminant (D, f, d);
1398
if ( ! mpq_sgn(D) ) return -1;
1399
w1 = mpz_factor_small (p1, h, P, mpq_numref(D), MPZ_MAX_FACTORS, 128);
1400
if ( ! w1 ) { err_printf ("unable to small_factor %Zd\n", mpq_numref(D)); return -2; }
1401
1402
mpq_get_den(Q, f[0]);
1403
for ( i = 1 ; i <= d ; i++ ) mpz_lcm (Q, Q, mpq_denref(f[i]));
1404
if ( mpz_cmp_ui (Q,1) == 0 ) {
1405
for ( i = 0 ; i < w1 ; i++ ) bad[i] = p1[i];
1406
return w1;
1407
}
1408
w2 = mpz_factor_small (p2, h, P, Q, MPZ_MAX_FACTORS, 128);
1409
if ( ! w2 ) { err_printf ("unable to small_factor %Zd\n", Q); return -2; }
1410
1411
for ( i = j = k = 0 ; i < w1 || j < w2 ; k++ ) {
1412
if ( k >= maxbad ) { err_printf ("too many bad primes, increase maxbad value\n"); return -2; }
1413
if ( i >= w1 ) { bad[k] = p2[j++]; continue; }
1414
if ( j >= w2 ) { bad[k] = p1[i++]; continue; }
1415
if ( p1[i] < p2[j] ) {
1416
bad[k] = p1[i++];
1417
} else {
1418
bad[k] = p2[j++];
1419
}
1420
}
1421
return k;
1422
}
1423
1424
/*
1425
The discriminant functions below are optimized for computing the discriminant of monic polys of degree 3, 5, or 7
1426
whose d-1 term is 0. They use an explicit formula generated via Magma with coefficients in polydisc.h.
1427
*/
1428
1429
void mpz_poly_discriminant (mpz_t D, mpz_t f[], int degree)
1430
{
1431
static int init, warn;
1432
static mpz_t temp1, temp2, fpow[6][8];
1433
struct disc_terms *dt;
1434
int i, j, k;
1435
1436
if ( ! init ) { mpz_init (temp1); mpz_init (temp2); for ( i = 0 ; i < 6 ; i++ ) for ( j = 0 ; j <= 7 ; j++ ) mpz_init(fpow[i][j]); init = 1; }
1437
if ( ! (degree&0x1) ) { err_printf ("Don't know how to compute discriminant for even degree\n"); exit (0); }
1438
if ( mpz_cmp_ui (f[degree], 1) != 0 ) { err_printf ("Don't know how to compute discriminant for non-monic poly, degree %d, leading coeff %Zd\n", degree, f[degree]); exit (0); }
1439
if ( mpz_sgn(f[degree-1]) ) { err_printf ("Don't know how to compute discriminant for non-zero d-1 term, please standardize poly\n"); exit (0); }
1440
for ( i = degree-1 ; i > 1 ; i-- ) if ( mpz_sgn(f[i]) ) break;
1441
if ( i == 1 ) {
1442
mpz_ui_pow_ui (temp1, (degree-1), (degree-1));
1443
mpz_pow_ui (D, f[1], degree);
1444
mpz_mul (D, D, temp1);
1445
mpz_ui_pow_ui (temp1, degree, degree);
1446
mpz_pow_ui (temp2, f[0], degree-1);
1447
mpz_mul (temp2, temp2, temp1);
1448
mpz_add (D, D, temp2);
1449
mpz_neg (D, D);
1450
} else {
1451
if ( degree != 5 && degree != 7) { err_printf ("Don't know how to compute discriminant for degree != 5 or 7 and not x^d+ax+b\n"); exit (0); }
1452
1453
// not the most efficient way to do this...
1454
for ( i = 0 ; i < degree-1 ; i++ ) {
1455
mpz_set_ui (fpow[i][0], 1);
1456
for ( j = 1 ; j <= degree ; j++ ) mpz_mul (fpow[i][j], fpow[i][j-1], f[i]);
1457
}
1458
1459
mpz_set_ui (temp1, 0);
1460
if ( degree == 5 ) {
1461
for ( i = 0 ; i < PD_D5_TERMS ; i++ ) {
1462
if ( PD_D5[i].c < 0 ) {
1463
mpz_mul_ui (temp2, fpow[0][PD_D5[i].f[0]], -PD_D5[i].c);
1464
mpz_neg(temp2, temp2);
1465
} else {
1466
mpz_mul_ui (temp2, fpow[0][PD_D5[i].f[0]], PD_D5[i].c);
1467
}
1468
for ( j = 1 ; j < degree-1 ; j++ ) mpz_mul (temp2, temp2, fpow[j][PD_D5[i].f[j]]);
1469
mpz_add (temp1, temp1, temp2);
1470
}
1471
} else if ( degree == 7 ) {
1472
for ( i = 0 ; i < PD_D7_TERMS ; i++ ) {
1473
if ( PD_D7[i].c < 0 ) {
1474
mpz_mul_ui (temp2, fpow[0][PD_D7[i].f[0]], -PD_D7[i].c);
1475
mpz_neg(temp2, temp2);
1476
} else {
1477
mpz_mul_ui (temp2, fpow[0][PD_D7[i].f[0]], PD_D7[i].c);
1478
}
1479
for ( j = 1 ; j < degree-1 ; j++ ) mpz_mul (temp2, temp2, fpow[j][PD_D7[i].f[j]]);
1480
mpz_add (temp1, temp1, temp2);
1481
}
1482
}
1483
mpz_set (D, temp1);
1484
}
1485
}
1486
1487
1488
// For degree 6 (only) we handle the fully general case.
1489
void mpq_poly_discriminant (mpq_t D, mpq_t f[], int degree)
1490
{
1491
static int init, warn;
1492
static mpq_t temp1, temp2, temp3, fpow[7][8];
1493
static mpz_t z;
1494
struct disc_terms *dt;
1495
int i, j, k;
1496
1497
if ( ! init ) { mpz_init (z); mpq_init (temp1); mpq_init (temp2); mpq_init (temp3); for ( i = 0 ; i < 7 ; i++ ) for ( j = 0 ; j <= 7 ; j++ ) mpq_init(fpow[i][j]); init = 1; }
1498
if ( degree != 6 ) {
1499
if ( degree < 2 || ! (degree&0x1) ) { err_printf ("Degree must be odd > 1 to compute discriminant\n"); exit (0); }
1500
if ( mpq_cmp_ui (f[degree], 1, 1) != 0 ) { err_printf ("Don't know how to compute discriminant for non-monic poly, degree %d, leading coeff %Zd\n", degree, f[degree]); exit (0); }
1501
if ( mpq_sgn(f[degree-1]) ) { err_printf ("Don't know how to compute discriminant for non-zero d-1 term, please standardize poly\n"); exit (0); }
1502
for ( i = degree-1 ; i > 1 ; i-- ) if ( mpq_sgn(f[i]) ) break;
1503
} else {
1504
i = 5;
1505
}
1506
if ( i == 1 ) {
1507
mpq_set (D, f[1]);
1508
for ( i = 1 ; i < degree ; i++ ) mpq_mul (D, D, f[1]);
1509
mpz_ui_pow_ui (z, (degree-1), (degree-1));
1510
mpq_set_z (temp1, z);
1511
mpq_mul (D, D, temp1);
1512
mpq_set (temp2, f[0]);
1513
for ( i = 1 ; i < degree-1 ; i++ ) mpq_mul (temp2, temp2, f[0]);
1514
mpz_ui_pow_ui (z, degree, degree);
1515
mpq_set_z (temp1, z);
1516
mpq_mul (temp2, temp2, temp1);
1517
mpq_add (D, D, temp2);
1518
mpq_neg (D, D);
1519
} else {
1520
if ( degree < 5 || degree > 7) { err_printf ("Don't know how to compute discriminant for degree != 5, 6, or 7 and not x^d+ax+b\n"); mpq_set_ui(D,1,1); return; }
1521
1522
// not the most efficient way to do this...
1523
k = (degree==6?7:degree-1);
1524
for ( i = 0 ; i < k ; i++ ) {
1525
mpq_set_ui (fpow[i][0], 1, 1);
1526
for ( j = 1 ; j <= degree ; j++ ) mpq_mul (fpow[i][j], fpow[i][j-1], f[i]);
1527
}
1528
1529
mpq_set_ui (temp1, 0, 1);
1530
if ( degree == 5 ) {
1531
for ( i = 0 ; i < PD_D5_TERMS ; i++ ) {
1532
mpq_set_si (temp3, PD_D5[i].c, 1);
1533
mpq_mul (temp2, fpow[0][PD_D5[i].f[0]], temp3);
1534
for ( j = 1 ; j < k ; j++ ) mpq_mul (temp2, temp2, fpow[j][PD_D5[i].f[j]]);
1535
mpq_add (temp1, temp1, temp2);
1536
}
1537
} else if ( degree == 6 ) {
1538
for ( i = 0 ; i < PD_D6_TERMS ; i++ ) {
1539
mpq_set_si (temp3, PD_D6[i].c, 1);
1540
mpq_mul (temp2, fpow[0][PD_D6[i].f[0]], temp3);
1541
for ( j = 1 ; j < k ; j++ ) mpq_mul (temp2, temp2, fpow[j][PD_D6[i].f[j]]);
1542
mpq_add (temp1, temp1, temp2);
1543
}
1544
} else if ( degree == 7 ) {
1545
for ( i = 0 ; i < PD_D7_TERMS ; i++ ) {
1546
mpq_set_si (temp3, PD_D7[i].c, 1);
1547
mpq_mul (temp2, fpow[0][PD_D7[i].f[0]], temp3);
1548
for ( j = 1 ; j < k ; j++ ) mpq_mul (temp2, temp2, fpow[j][PD_D7[i].f[j]]);
1549
mpq_add (temp1, temp1, temp2);
1550
}
1551
}
1552
mpq_set (D, temp1);
1553
}
1554
}
1555
1556
1557
/*
1558
Assumes f is monic, degree 3, 5, or, 7, and has d-1 coefficient zero.
1559
*/
1560
void _ff_poly_discriminant (ff_t disc[1], ff_t f[], int degree)
1561
{
1562
_ff_t_declare temp1, temp2, temp3, fpow[6][8];
1563
struct disc_terms *dt;
1564
int i, j, k;
1565
#if FF_INIT_REQUIRED
1566
static int init;
1567
if ( ! init ) { _ff_init (temp1); _ff_init (temp2); _ff_init(temp3); for ( i = 0 ; i < 6 ; i++ ) for ( j = 0 ; j <= 7 ; j++ ) _ff_init(fpow[i][j]); init = 1; }
1568
#endif
1569
if ( degree != 5 && degree != 7) { err_printf ("Don't know how to compute discriminant for degree != 5 or 7 and not x^d+ax+b\n"); exit (0); }
1570
if ( ! _ff_one(f[degree]) ) { err_printf ("Don't know how to compute discriminant when poly is not monic\n"); exit (0); }
1571
if ( _ff_nonzero(f[degree-1]) ) { err_printf ("Don't know how to compute discriminant when degree-1 coefficient is non-zero, please standardize poly\n"); exit (0); }
1572
1573
// not the most efficient way to do this...
1574
for ( i = 0 ; i < degree-1 ; i++ ) {
1575
_ff_set_one (fpow[i][0]);
1576
for ( j = 1 ; j <= degree ; j++ ) _ff_mult (fpow[i][j], fpow[i][j-1], f[i]);
1577
}
1578
1579
_ff_set_zero(temp1);
1580
if ( degree == 5 ) {
1581
for ( i = 0 ; i < PD_D5_TERMS ; i++ ) {
1582
_ff_set_i (temp3, PD_D5[i].c);
1583
_ff_mult (temp2, temp3, fpow[0][PD_D5[i].f[0]]);
1584
for ( j = 1 ; j < degree-1 ; j++ ) _ff_mult (temp2, temp2, fpow[j][PD_D5[i].f[j]]);
1585
_ff_addto (temp1, temp2);
1586
}
1587
} else if ( degree == 7 ) {
1588
for ( i = 0 ; i < PD_D7_TERMS ; i++ ) {
1589
_ff_set_i (temp3, PD_D7[i].c);
1590
_ff_mult (temp2, temp3, fpow[0][PD_D7[i].f[0]]);
1591
for ( j = 1 ; j < degree-1 ; j++ ) _ff_mult (temp2, temp2, fpow[j][PD_D7[i].f[j]]);
1592
_ff_addto (temp1, temp2);
1593
}
1594
}
1595
_ff_set (disc[0], temp1);
1596
}
1597
1598
// Requires f monic, hardwired for degrees 2, 3, and 4, and also x^d+ax+b cases for d=5 or 7
1599
void ff_poly_discriminant (ff_t disc[1], ff_t f[], int degree)
1600
{
1601
_ff_t_declare_reg A, B, temp1, temp2, temp3;
1602
int i;
1603
#if FF_INIT_REQUIRED
1604
static int init;
1605
if ( ! init ) { _ff_init(A); _ff_init(B); _ff_init (temp1); _ff_init (temp2); _ff_init(temp3); init = 1; }
1606
#endif
1607
#ifndef FF_FAST
1608
if ( ! _ff_one (f[degree]) ) { err_printf ("Don't know how to compute discriminant for non-monic poly, leading coeff = %Zd\n", _ff_wrap_mpz(f[degree],0)); exit (0); }
1609
#endif
1610
switch (degree) {
1611
case 1: _ff_set_one (disc[0]); return;
1612
case 2: _ff_square(temp1,f[1]); _ff_add(temp2,f[0],f[0]); _ff_x2(temp2); _ff_sub(disc[0],temp1,temp2); return;
1613
case 3:
1614
_ff_square(temp1,f[1]); ff_mult(temp1,temp1,f[1]); _ff_x2(temp1); _ff_x2(temp1); // temp1 = 4f1^3
1615
_ff_square(temp2,f[0]); _ff_set_i(temp3,27); ff_mult(temp2,temp2,temp3); // temp2 = 27f2^2
1616
_ff_add(disc[0],temp1,temp2);
1617
ff_negate(disc[0]); // disc = -4f1^3-27f0^2
1618
if ( ! _ff_zero(f[2]) ) {
1619
_ff_square(temp2,f[2]); _ff_mult(temp3,f[2],f[0]); ff_mult(temp1,temp2,temp3); _ff_x2(temp1); _ff_x2(temp1); // temp1 = 4f2^3f0
1620
_ff_square(temp3,f[1]); _ff_mult(temp3,temp2,temp3); _ff_subfrom(temp3,temp1); // temp3 = f2^2f1^2 - 4f2^3f0
1621
_ff_set_ui(temp2,18); _ff_mult (temp1,f[2],temp2); _ff_mult(temp2,f[1],f[0]); ff_mult(temp1,temp1,temp2); // temp1 = 18f0f1f2
1622
_ff_addto(disc[0],temp1);
1623
_ff_addto(disc[0],temp3); // disc = -4f2^3f0+f2^2f1^2+18f2f1f0-4f1^3-27f0^2
1624
}
1625
return;
1626
case 4:
1627
if ( ! _ff_zero(f[3]) ) {
1628
_ff_square(A,f[3]); ff_mult(A,A,f[0]); _ff_square(temp1,f[1]); _ff_addto(A,temp1); // A = f3^2f0 + f1^2
1629
_ff_mult(temp1,f[2],f[0]); _ff_x2(temp1); _ff_x2(temp1); _ff_subfrom(A,temp1); // A = f3^2f0 + f1^2 - 4f2f0
1630
_ff_mult(B,f[3],f[1]); _ff_add(temp1,f[0],f[0]); _ff_x2(temp1); _ff_subfrom(B,temp1); // B = f3f1 - 4f0
1631
} else {
1632
_ff_square(A,f[1]); _ff_mult(temp1,f[2],f[0]); _ff_x2(temp1); _ff_x2(temp1); _ff_subfrom(A,temp1); // A = f1^2 - 4f2f0
1633
_ff_add(B,f[0],f[0]); _ff_x2(B); ff_negate(B); // B = -4f0
1634
}
1635
_ff_square(temp3,f[2]); _ff_mult(temp1,temp3,f[2]); ff_mult(temp1,temp1,A); _ff_x2(temp1); _ff_x2(temp1); // temp1 = 4f2^3A
1636
_ff_square(temp2,B); ff_mult(disc[0],temp2,temp3); _ff_subfrom (disc[0],temp1); // disc = -4f2^3A + f2^2B^2
1637
ff_mult(temp2,temp2,B); _ff_x2(temp2); _ff_x2(temp2); _ff_subfrom(disc[0],temp2); // disc = -4f2^3A + f2^2B^2 - 4*B^3
1638
_ff_set_ui(temp1,18); _ff_mult(temp3,temp1,f[0]); _ff_mult(temp1,A,B); ff_mult(temp1,temp1,temp3); // temp1 = 18f0BA
1639
_ff_set_ui(temp2,27); _ff_square(temp3,A); ff_mult(temp2,temp2,temp3); _ff_subfrom(temp1,temp2); // temp1 = 18f0BA - 27A^2
1640
_ff_addto(disc[0],temp1); // disc = -4f2^3A + f2^2B^2 + 18f0BA - B^3 - 27A^2
1641
return;
1642
case 5:
1643
if ( ! _ff_zero(f[4]) || _ff_zero(f[3]) || ! _ff_zero(f[2]) ) { _ff_poly_discriminant (disc, f, degree); return; }
1644
_ff_square(temp1,f[1]);
1645
ff_square(temp1,temp1);
1646
ff_mult(temp1,temp1,f[1]);
1647
_ff_set_i(temp2,-256);
1648
_ff_mult(disc[0],temp1,temp2);
1649
_ff_square(temp1,f[0]);
1650
ff_square(temp1,temp1);
1651
_ff_set_i(temp2,-3125);
1652
ff_mult(temp1,temp1,temp2);
1653
_ff_addto(disc[0],temp1);
1654
return;
1655
case 7:
1656
if ( ! _ff_zero(f[6]) || ! _ff_zero(f[5]) || ! _ff_zero(f[4]) || _ff_zero(f[3]) || ! _ff_zero(f[2]) ) { _ff_poly_discriminant (disc, f, degree); return; }
1657
_ff_square(temp1,f[1]);
1658
ff_square(temp2,temp1);
1659
ff_mult(temp1,temp1,temp2);
1660
ff_mult(temp1,temp1,f[1]);
1661
_ff_set_i(temp2,-46656);
1662
_ff_mult(disc[0],temp1,temp2);
1663
_ff_square(temp1,f[0]);
1664
ff_square(temp2,temp1);
1665
ff_mult(temp1,temp1,temp2);
1666
_ff_set_i(temp2,-823543);
1667
ff_mult(temp1,temp1,temp2);
1668
_ff_addto(disc[0],temp1);
1669
return;
1670
default:
1671
err_printf ("Unhandled poly in ff_poly_discriminant\n"); exit (0);
1672
}
1673
}
1674
1675
1676