1 /*
2 These files (mpz_poly.*) implement arithmetics of polynomials whose
3 coefficients are in multiprecision integers (using mpz_t from GNU MP).
4
5 We use them in sqrt/algsqrt.c to represent rings of integers.
6
7 Please see the file README_POLYNOMIALS for more details and
8 comparisons to other poly formats.
9 */
10
11
12 #include "cado.h" // IWYU pragma: keep
13 // IWYU pragma: no_include <bits/exception.h>
14 #include <exception> // std::exception // IWYU pragma: keep
15 #include <sstream> // std::ostringstream // IWYU pragma: keep
16 #include <vector>
17 #include <string>
18 #include <ostream> // for operator<<, basic_ostream, basic_ostream::o...
19 #include <climits> // ULONG_MAX
20 #include <cctype> // isdigit etc
21 #include <cstdio> // fprintf // IWYU pragma: keep
22 #include <cstdlib>
23 #include <cstring>
24 #include <gmp.h>
25 #include "cxx_mpz.hpp" // for cxx_mpz
26 #include "double_poly.h" // for double_poly_s, double_poly_srcptr
27 #include "gmp_aux.h" // for mpz_addmul_si, mpz_mul_uint64, mpz_ndiv_r
28 #include "lll.h" // for mat_Z, LLL
29 #include "mpz_poly.h"
30 #include "mpz_poly_parallel.hpp"
31 #include "omp_proxy.h" // IWYU pragma: keep
32 #include "portability.h" // for strlcpy
33 #include "rootfinder.h" // for mpz_poly_roots_mpz
34 #ifdef MPZ_POLY_TIMINGS
35 #include "timing.h"
36 #endif
37 /* and just because we expose a proxy to usp.c's root finding... */
38 #include "usp.h" // for numberOfRealRoots
39
40 #ifndef max
41 #define max(a,b) ((a)<(b) ? (b) : (a))
42 #endif
43
44 /* A note on the parallel interface.
45 *
46 * The interface in mpz_poly.h has some of its functions duplicated in
47 * mpz_poly_parallel.hpp. Those functions can be used either with or
48 * without openmp.
49 *
50 * A function such as ::mpz_poly_blah is implemented here as a simple
51 * trampoline to mpz_poly_notparallel_info::mpz_poly_blah.
52 *
53 * Then both mpz_poly_notparallel_info::mpz_poly_blah and
54 * mpz_poly_parallel_info::mpz_poly_blah are created as instances of a
55 * template member functions, so that the "parallel" criterion can
56 * resolve statically. (static resolution is the main reason why I
57 * didn't go for virtual functions)
58 *
59 * The code to implement mpz_poly_blah is therefore:
60 *
61 * void mpz_poly_blah(...)
62 * {
63 * mpz_poly_notparallel_info().mpz_poly_blah(...);
64 * }
65 * template<typename inf>
66 * void mpz_poly_parallel_interface<inf>::mpz_poly_blah(...)
67 * {
68 * then std::is_same<inf, mpz_poly_notparallel_info>::value is a
69 * compile-time constant
70 * }
71 *
72 */
73
74
75 // compute timings for Q^a mod(f,p): square, multiplication, reduction mod f
76 // PZ piece of code:
77 // in mpz_poly.h: add #define MPZ_POLY_TIMINGS
78 // beware: these timers are not thread-safe.
79 #ifdef MPZ_POLY_TIMINGS
80 #include <time.h>
81 #include <timing.h>
82 #include "macros.h"
83 static double timer[3] = {0.0, 0.0, 0.0};
84 static unsigned long calls[3] = {0, 0, 0};
85 #endif
86
87 #define TIMER_MUL 0
88 #define TIMER_SQR 1
89 #define TIMER_RED 2
90
91 #ifdef MPZ_POLY_TIMINGS
92 #define START_TIMER double t = seconds_thread ()
93 #define RESTART_TIMER t = seconds_thread ()
94 #define END_TIMER(x) add_timer (x, seconds_thread () - t)
95
96 /* flag=0: computing roots of f mod p
97 1: checking irreducibility of f
98 2: LLL reduction
99 3: computing MurphyE */
100 static void
add_timer(int flag,double t)101 add_timer (int flag, double t)
102 {
103 timer[flag] += t;
104 calls[flag] += 1;
105 }
106 #else
107 #define START_TIMER
108 #define RESTART_TIMER
109 #define END_TIMER(x)
110 #endif
111
112 #ifdef MPZ_POLY_TIMINGS
print_timings_pow_mod_f_mod_p()113 void print_timings_pow_mod_f_mod_p(){
114 printf (" (mul %.2fs/%lu, square %.2fs/%lu, red mod (f,p) %.2fs/%lu)",
115 timer[TIMER_MUL], calls[TIMER_MUL], timer[TIMER_SQR], calls[TIMER_SQR],
116 timer[TIMER_RED], calls[TIMER_RED]);
117 }
118 #endif
119
120
121 /* --------------------------------------------------------------------------
122 Static functions
123 -------------------------------------------------------------------------- */
124
125 /* Return f=g*h, where g has degree r, and h has degree s. */
126 static int
mpz_poly_mul_basecase(mpz_t * f,mpz_t * g,int r,mpz_t * h,int s)127 mpz_poly_mul_basecase (mpz_t *f, mpz_t *g, int r, mpz_t *h, int s) {
128 int i, j;
129 ASSERT(f != g && f != h);
130 for (i = 0; i <= r + s; i++)
131 mpz_set_ui (f[i], 0);
132 for (i = 0; i <= r; ++i)
133 for (j = 0; j <= s; ++j)
134 mpz_addmul(f[i+j], g[i], h[j]);
135 return r + s;
136 }
137
138 /* f <- g^2 where g has degree r */
139 static int
mpz_poly_sqr_basecase(mpz_t * f,mpz_t * g,int r)140 mpz_poly_sqr_basecase (mpz_t *f, mpz_t *g, int r) {
141 int i, j;
142 ASSERT(f != g);
143 for (i = 0; i <= 2 * r; i++)
144 mpz_set_ui (f[i], 0);
145 for (i = 0; i <= r; ++i)
146 for (j = 0; j < i; ++j)
147 mpz_addmul(f[i+j], g[i], g[j]);
148 for (i = 0; i < 2*r ; i++)
149 mpz_mul_2exp(f[i], f[i], 1);
150 for (i = 0; i < r ; i++) {
151 mpz_mul(f[2*r], g[i], g[i]);
152 mpz_add(f[2*i], f[2*i], f[2*r]);
153 }
154 mpz_mul(f[2*r], g[r], g[r]);
155 return 2 * r;
156 }
157
158 /* To interpolate a polynomial of degree <= MAX_TC_DEGREE, we use the following
159 MAX_TC_DEGREE evaluation points, plus the point at infinity.
160 The first point should always be 0. */
161 static const long tc_points[MAX_TC_DEGREE] = {0, 1, -1, 2, -2, 3, -3, 4, -4,
162 5, -5, 6, -6, 7, -7, 8, -8, 9, -9};
163
164 #if GNUC_VERSION_ATLEAST(7,0,0)
165 #pragma GCC diagnostic push
166 #pragma GCC diagnostic ignored "-Wstrict-overflow"
167 #endif
168 /* Given f[0]...f[t] that contain respectively f(0), ..., f(t),
169 put in f[0]...f[t] the coefficients of f. Assumes t <= MAX_TC_DEGREE.
170
171 In the square root, with an algebraic polynomial of degree d,
172 we have to multiply polynomials of degree d-1, thus we have t=2(d-1).
173 */
174 static void
mpz_poly_mul_tc_interpolate(mpz_t * f,int t)175 mpz_poly_mul_tc_interpolate (mpz_t *f, int t) {
176 int64_t M[MAX_TC_DEGREE+1][MAX_TC_DEGREE+1], g, h;
177 int i, j, k, l;
178 /* G[] is the list of gcd's that appear in the forward Gauss loop, in the
179 order they appear (they don't depend on t, since we start with the low
180 triangular submatrix for t-1) */
181 static const int64_t G[] = {1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368000,20922789888000,355687428096000};
182
183 ASSERT (t <= MAX_TC_DEGREE); /* Ensures that all M[i][j] fit in uint64_t,
184 and similarly for all intermediate
185 computations on M[i][j]. This avoids the
186 use of mpz_t to store the M[i][j]. */
187
188 /* initialize M[i][j] = tc_points[i]^j */
189 for (i = 0; i <= t; i++)
190 for (j = 0; j <= t; j++)
191 {
192 if (i < t)
193 M[i][j] = (j == 0) ? 1 : tc_points[i] * M[i][j-1];
194 else /* evaluation point is infinity */
195 M[i][j] = (j == t);
196 }
197
198 /* Forward Gauss: zero the under-diagonal coefficients while going down.
199 Since the last point of evaluation is infinity, the last row is already
200 reduced, thus we go up to i=t-1. */
201 for (i = 1; i < t; i++)
202 {
203 for (j = 0, l = 0; j < i; j++)
204 {
205 g = G[l++]; /* same as gcd_int64 (M[i][j], M[j][j]) */
206 h = M[i][j] / g;
207 g = M[j][j] / g;
208 /* f[i] <- g*f[i] - h*f[j] */
209 ASSERT(g > 0);
210 if (g != 1)
211 mpz_mul_uint64 (f[i], f[i], g);
212 mpz_submul_int64 (f[i], f[j], h);
213 for (k = j; k <= t; k++)
214 M[i][k] = g * M[i][k] - h * M[j][k];
215 }
216 }
217
218 /* now zero upper-diagonal coefficients while going up */
219 for (i = t - 1; i >= 0; i--)
220 {
221 for (j = i + 1; j <= t; j++)
222 /* f[i] = f[i] - M[i][j] * f[j] */
223 mpz_submul_int64 (f[i], f[j], M[i][j]);
224 ASSERT (mpz_divisible_uint64_p (f[i], M[i][i]));
225 mpz_divexact_uint64 (f[i], f[i], M[i][i]);
226 }
227 }
228 #if GNUC_VERSION_ATLEAST(7,0,0)
229 #pragma GCC diagnostic pop
230 #endif
231
232 /* v <- g(i) */
233 static void
mpz_poly_mul_eval_si(mpz_t v,mpz_t * g,int r,long i)234 mpz_poly_mul_eval_si (mpz_t v, mpz_t *g, int r, long i)
235 {
236 mpz_set (v, g[r]);
237 for (int j = r - 1; j >= 0; j--)
238 {
239 mpz_mul_si (v, v, i);
240 mpz_add (v, v, g[j]);
241 }
242 }
243
244 /* Generic Toom-Cook implementation: stores in f[0..r+s] the coefficients
245 of g*h, where g has degree r and h has degree s, and their coefficients
246 are in g[0..r] and h[0..s].
247 Assumes f differs from g and h, and f[0..r+s] are already allocated.
248 Returns the degree of f.
249 */
250 template<typename inf>
251 static int
mpz_poly_mul_tc(inf & inf_arg,mpz_t * f,mpz_t * g,int r,mpz_t * h,int s)252 mpz_poly_mul_tc(inf& inf_arg, mpz_t *f, mpz_t *g, int r, mpz_t *h, int s)
253 {
254 int t;
255
256 if ((r == -1) || (s == -1)) /* g or h is 0 */
257 return -1;
258
259 if (r < s)
260 return mpz_poly_mul_tc(inf_arg, f, h, s, g, r);
261
262 /* now r >= s */
263
264 if (s == 0)
265 {
266 for (int i = 0; i <= r; i++)
267 mpz_mul (f[i], g[i], h[0]);
268 return r;
269 }
270
271 t = r + s; /* degree of f, which has t+1 coefficients */
272
273 if (t == 2) /* necessary r = s = 1, use vanilla Karatsuba with 3 MUL,
274 this is always optimal */
275 {
276 /* TODO: does it make sense to do the two last MULs below in
277 * parallel if entries are large enough ? */
278 mpz_add (f[0], g[0], g[1]);
279 mpz_add (f[2], h[0], h[1]);
280
281 mpz_mul (f[1], f[0], f[2]);
282
283 mpz_mul (f[0], g[0], h[0]);
284 mpz_mul (f[2], g[1], h[1]);
285
286 mpz_sub (f[1], f[1], f[0]);
287
288 mpz_sub (f[1], f[1], f[2]);
289 return 2;
290 }
291
292 if (t == 3) /* r = 2, s = 1, the following code in 4 MUL is optimal */
293 {
294 /* TODO: do part of the stuff (if relevant) in parallel if entries
295 * are large enough ? */
296 mpz_add (f[1], g[2], g[0]);
297 mpz_add (f[2], f[1], g[1]); /* g(1) */
298 mpz_sub (f[1], f[1], g[1]); /* g(-1) */
299 mpz_add (f[0], h[0], h[1]); /* h(1) */
300 mpz_mul (f[2], f[2], f[0]); /* f(1) = g(1)*h(1) */
301 mpz_sub (f[0], h[0], h[1]); /* h(-1) */
302 mpz_mul (f[0], f[1], f[0]); /* f(-1) = g(-1)*h(-1) */
303 mpz_sub (f[1], f[2], f[0]); /* f(1) - f(-1) = 2*g2*h1+2*g1*h0+2*g0*h1 */
304 mpz_add (f[2], f[2], f[0]); /* f(1) + f(-1) = 2*g2*h0+2*g1*h1+2*g0*h0 */
305 mpz_div_2exp (f[1], f[1], 1); /* g2*h1 + g1*h0 + g0*h1 */
306 mpz_div_2exp (f[2], f[2], 1); /* g2*h0 + g1*h1 + g0*h0 */
307 mpz_mul (f[0], g[0], h[0]);
308 mpz_sub (f[2], f[2], f[0]); /* g2*h0 + g1*h1 */
309 mpz_mul (f[3], g[2], h[1]);
310 mpz_sub (f[1], f[1], f[3]); /* g1*h0 + g0*h1 */
311 return 3;
312 }
313
314 if (r == 2) /* Necessarily s = 2 since r >= s and the cases s = 0 and
315 (r,s) = (2,1) have already been treated. */
316 {
317 /* TODO: do part of the stuff (if relevant) in parallel if entries
318 * are large enough ? */
319 /* we use here the code from Appendix Z from "Towards Optimal Toom-Cook
320 Multiplication for Univariate and Multivariate Polynomials in
321 Characteristic 2 and 0" from Marco Bodrato, WAIFI 2007, LNCS 4547,
322 with the change: W3 -> f[1], W2 -> f[3], W1 -> f[2]. */
323 mpz_add (f[0], g[2], g[0]); mpz_add (f[4], h[2], h[0]);
324 mpz_sub (f[3], f[0], g[1]); mpz_sub (f[2], f[4], h[1]);
325 mpz_add (f[0], f[0], g[1]); mpz_add (f[4], f[4], h[1]);
326 mpz_mul (f[1], f[3], f[2]); mpz_mul (f[2], f[0], f[4]);
327 mpz_add (f[0], f[0], g[2]);
328 mpz_mul_2exp (f[0], f[0], 1);
329 mpz_sub (f[0], f[0], g[0]);
330 mpz_add (f[4], f[4], h[2]);
331 mpz_mul_2exp (f[4], f[4], 1);
332 mpz_sub (f[4], f[4], h[0]);
333 mpz_mul (f[3], f[0], f[4]);
334 mpz_mul (f[0], g[0], h[0]);
335 mpz_mul (f[4], g[2], h[2]);
336 /* interpolation */
337 mpz_sub (f[3], f[3], f[1]);
338 ASSERT (mpz_divisible_ui_p (f[3], 3));
339 mpz_divexact_ui (f[3], f[3], 3);
340 mpz_sub (f[1], f[2], f[1]);
341 ASSERT (mpz_divisible_ui_p (f[1], 2));
342 mpz_div_2exp (f[1], f[1], 1); /* exact */
343 mpz_sub (f[2], f[2], f[0]);
344 mpz_sub (f[3], f[3], f[2]);
345 ASSERT (mpz_divisible_ui_p (f[3], 2));
346 mpz_div_2exp (f[3], f[3], 1); /* exact */
347 mpz_submul_ui (f[3], f[4], 2);
348 mpz_sub (f[2], f[2], f[1]);
349 mpz_sub (f[2], f[2], f[4]);
350 mpz_sub (f[1], f[1], f[3]);
351 return 4;
352 }
353
354 if (t > MAX_TC_DEGREE) {
355 /* naive product */
356 /* currently we have to resort to this for larger degree, because
357 * the generic Toom implementation is bounded in degree.
358 */
359 return mpz_poly_mul_basecase (f, g, r, h, s);
360 }
361
362 /* now t <= MAX_TC_DEGREE */
363
364 /* store g(tc_points[i])*h(tc_points[i]) in f[i] for 0 <= i <= t */
365
366 ASSERT(tc_points[0] == 0);
367
368 #ifdef HAVE_OPENMP
369 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
370 #endif
371 for (int i = 0; i <= t; i++)
372 {
373 if (i == 0) /* evaluate at 0 */
374 mpz_mul (f[0], g[0], h[0]);
375 else if (i == t) /* evaluate at infinity */
376 mpz_mul (f[t], g[r], h[s]);
377 else
378 {
379 ASSERT_FOR_STATIC_ANALYZER(i < t);
380 mpz_t tmp;
381 mpz_init (tmp);
382 /* f[i] <- g(i) */
383 mpz_poly_mul_eval_si (f[i], g, r, tc_points[i]);
384 /* f[t] <- h(i) */
385 mpz_poly_mul_eval_si (tmp, h, s, tc_points[i]);
386 /* f[i] <- g(i)*h(i) */
387 mpz_mul (f[i], f[i], tmp);
388 mpz_clear (tmp);
389 }
390 }
391
392 mpz_poly_mul_tc_interpolate (f, t);
393
394 return t;
395 }
396
397 /* f2*x^2+f1*x+f0 = (g1*x+g0)^2 using Karatsuba and 3 SQR */
398 static int
mpz_poly_sqr_tc2(mpz_t * f,mpz_t * g)399 mpz_poly_sqr_tc2 (mpz_t *f, mpz_t *g)
400 {
401 mpz_mul (f[0], g[0], g[0]);
402 mpz_mul (f[2], g[1], g[1]);
403 mpz_add (f[1], g[0], g[1]);
404 mpz_mul (f[1], f[1], f[1]);
405 mpz_sub (f[1], f[1], f[0]);
406 mpz_sub (f[1], f[1], f[2]);
407 return 2;
408 }
409
410 #if 1
411 /* Algorithm SQR3 from Asymmetric Squaring Formulae by Chung and Hasan,
412 with 4 SQR and 1 MUL. */
413 static int
mpz_poly_sqr_tc3(mpz_t * c,mpz_t * a)414 mpz_poly_sqr_tc3 (mpz_t *c, mpz_t *a)
415 {
416 mpz_mul (c[0], a[0], a[0]); /* c0 = S0 = a0^2 */
417 mpz_add (c[1], a[2], a[0]); /* c1 = a2 + a0 */
418 mpz_sub (c[2], c[1], a[1]); /* c2 = a2 - a1 + a0 */
419 mpz_add (c[1], c[1], a[1]); /* c1 = a2 + a1 + a0 */
420 mpz_mul (c[1], c[1], c[1]); /* S1 = (a2 + a1 + a0)^2 */
421 mpz_mul (c[2], c[2], c[2]); /* S2 = (a2 - a1 + a0)^2 */
422 mpz_mul (c[3], a[2], a[1]);
423 mpz_mul_2exp (c[3], c[3], 1); /* S3 = 2*a1*a2 */
424 mpz_add (c[2], c[1], c[2]);
425 mpz_tdiv_q_2exp (c[2], c[2], 1); /* T1 = (S1 + S2) / 2 */
426 mpz_sub (c[1], c[1], c[2]); /* S1 - T1 */
427 mpz_sub (c[1], c[1], c[3]); /* c1 = S1 - T1 - S3 */
428 mpz_mul (c[4], a[2], a[2]); /* c4 = S4 = a2^2 */
429 mpz_sub (c[2], c[2], c[4]); /* T1 - S4 */
430 mpz_sub (c[2], c[2], c[0]); /* c2 = T1 - S4 - S0 */
431 return 4;
432 }
433 #else
434 /* (g2*x^2+g1*x+g0)^2 = g2^2*x^4 + (2*g2*g1)*x^3 +
435 (g1^2+2*g2*g0)*x^2 + (2*g1*g0)*x + g0^2 in 3 SQR + 2 MUL.
436 Experimentally this is faster for less than 4096 bits than the
437 algorithm in 5 SQR from mpz_poly_mul_tc_interpolate. */
438 static int
mpz_poly_sqr_tc3(mpz_t * f,mpz_t * g)439 mpz_poly_sqr_tc3 (mpz_t *f, mpz_t *g)
440 {
441 mpz_mul (f[4], g[2], g[2]); /* g2^2 */
442 mpz_mul (f[3], g[2], g[1]);
443 mpz_mul_2exp (f[3], f[3], 1); /* 2*g2*g1 */
444 mpz_mul (f[1], g[1], g[0]);
445 mpz_mul_2exp (f[1], f[1], 1); /* 2*g1*g0 */
446 mpz_mul (f[0], g[0], g[0]); /* g0^2 */
447 mpz_add (f[2], g[2], g[1]);
448 mpz_add (f[2], f[2], g[0]);
449 mpz_mul (f[2], f[2], f[2]); /* (g2+g1+g0)^2 */
450 mpz_sub (f[2], f[2], f[4]);
451 mpz_sub (f[2], f[2], f[0]); /* g1^2 + 2*g2*g0 + 2*g2*g1 + 2*g1*g0 */
452 mpz_sub (f[2], f[2], f[3]); /* g1^2 + 2*g2*g0 + 2*g1*g0 */
453 mpz_sub (f[2], f[2], f[1]); /* g1^2 + 2*g2*g0 */
454 return 4;
455 }
456 #endif
457
458 #if 1
459 /* 2 levels of Karatsuba: 9 SQR */
460 static int
mpz_poly_sqr_tc4(mpz_t * f,mpz_t * g)461 mpz_poly_sqr_tc4 (mpz_t *f, mpz_t *g)
462 {
463 mpz_t t;
464
465 mpz_init (t);
466 /* f4*x^2+f3*x+f2 <- [(g3+g1)*x + (g2+g0)]^2 */
467 mpz_add (f[0], g[0], g[2]);
468 mpz_add (f[1], g[1], g[3]);
469 mpz_poly_sqr_tc2 (f + 2, f);
470 /* save f2 into t */
471 mpz_swap (t, f[2]);
472 /* f2*x^2+f1*x+f0 <- (g1*x+g0)^2 */
473 mpz_poly_sqr_tc2 (f, g);
474 /* subtract f2*x^2+f1*x+f0 from f4*x^2+f3*x+t */
475 mpz_sub (f[4], f[4], f[2]);
476 mpz_sub (f[3], f[3], f[1]);
477 mpz_sub (t, t, f[0]);
478 /* re-add t into f2 */
479 mpz_add (f[2], f[2], t);
480 /* save f4 into t */
481 mpz_swap (t, f[4]);
482 /* f6*x^2+f5*x+f4 <- (g3*x+g2)^2 */
483 mpz_poly_sqr_tc2 (f + 4, g + 2);
484 /* subtract f6*x^2+f5*x+f4 from t*x^2+f3*x+f2 */
485 mpz_sub (t, t, f[6]);
486 mpz_sub (f[3], f[3], f[5]);
487 mpz_sub (f[2], f[2], f[4]);
488 /* re-add t into f4 */
489 mpz_add (f[4], f[4], t);
490 mpz_clear (t);
491 return 6;
492 }
493 #else
494 static int
mpz_poly_sqr_tc4(mpz_t * f,mpz_t * g)495 mpz_poly_sqr_tc4 (mpz_t *f, mpz_t *g)
496 {
497 /* (g3*x^3+g2*x^2+g1*x+g0)^2 = g3^2*x^6 + (2*g3*g2)*x^5
498 + (g2^2+2*g3*g1)*x^4 + (2*g3*g0+2*g2*g1)*x^3
499 + (g1^2+2*g2*g0)*x^2 + (2*g1*g0)*x + g0^2 in 4 SQR + 6 MUL.
500 Experimentally this is faster for less than 4096 bits than the
501 algorithm in 7 SQR from mpz_poly_mul_tc_interpolate. */
502 mpz_mul (f[6], g[3], g[3]); /* g3^2 */
503 mpz_mul (f[5], g[3], g[2]);
504 mpz_mul_2exp (f[5], f[5], 1); /* 2*g3*g2 */
505 mpz_mul (f[1], g[1], g[0]);
506 mpz_mul_2exp (f[1], f[1], 1); /* 2*g1*g0 */
507 mpz_mul (f[2], g[1], g[1]); /* g1^2 */
508 mpz_mul (f[0], g[2], g[0]);
509 mpz_addmul_ui (f[2], f[0], 2); /* g1^2+2*g2*g0 */
510 mpz_mul (f[4], g[2], g[2]); /* g2^2 */
511 mpz_mul (f[0], g[3], g[1]);
512 mpz_addmul_ui (f[4], f[0], 2); /* g2^2+2*g3*g1 */
513 mpz_mul (f[3], g[3], g[0]);
514 mpz_mul (f[0], g[2], g[1]);
515 mpz_add (f[3], f[3], f[0]);
516 mpz_mul_2exp (f[3], f[3], 1); /* 2*g3*g0+2*g2*g1 */
517 mpz_mul (f[0], g[0], g[0]); /* g0^2 */
518 return 6;
519 }
520 #endif
521
522 /* Same as mpz_poly_mul_tc for the squaring: store in f[0..2r] the coefficients
523 of g^2, where g has degree r, and its coefficients are in g[0..r].
524 Assumes f differs from g, and f[0..2r] are already allocated.
525 Returns the degree of f.
526 */
527 template<typename inf>
528 static int
mpz_poly_sqr_tc(inf &,mpz_t * f,mpz_t * g,int r)529 mpz_poly_sqr_tc (inf& /* unused */, mpz_t *f, mpz_t *g, int r)
530 {
531 int t;
532 size_t nbits;
533
534 if (r == -1) /* g is 0 */
535 return -1;
536
537 if (r == 0)
538 {
539 mpz_mul (f[0], g[0], g[0]);
540 return 0;
541 }
542
543 if (r == 1) /* 3 SQR: always optimal */
544 return mpz_poly_sqr_tc2 (f, g);
545
546 /* we assume the number of bits of f[0] is representative of the size of
547 the coefficients of f */
548 nbits = mpz_sizeinbase (f[0], 2);
549
550 if (r == 2 && nbits < 4096)
551 return mpz_poly_sqr_tc3 (f, g);
552
553 if (r == 3 && nbits < 4096)
554 return mpz_poly_sqr_tc4 (f, g);
555
556 t = 2 * r; /* product has degree t thus t+1 coefficients */
557 if (t > MAX_TC_DEGREE) {
558 /* naive product */
559 /* currently we have to resort to this for larger degree, because
560 * the generic toom implementation is bounded in degree.
561 */
562 return mpz_poly_sqr_basecase (f, g, r);
563 }
564
565 ASSERT (t <= MAX_TC_DEGREE);
566
567 /* store g(tc_points[i])^2 in f[i] for 0 <= i <= t */
568
569 ASSERT(tc_points[0] == 0);
570
571 #ifdef HAVE_OPENMP
572 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
573 #endif
574 for (int i = 0; i <= t; i++)
575 {
576 if (i == 0) /* evaluate at 0 */
577 mpz_mul (f[0], g[0], g[0]);
578 else if (i == t) /* evaluate at infinity */
579 mpz_mul (f[t], g[r], g[r]);
580 else
581 {
582 ASSERT_FOR_STATIC_ANALYZER(i < t);
583 /* f[i] <- g(i) */
584 mpz_poly_mul_eval_si (f[i], g, r, tc_points[i]);
585 mpz_mul (f[i], f[i], f[i]);
586 }
587 }
588
589 mpz_poly_mul_tc_interpolate (f, t);
590
591 return t;
592 }
593
594 /* Pseudo-reduce a plain polynomial p modulo a non-monic polynomial F.
595 The result is of type polymodF_t P, and satisfies:
596 P->p = lc(F)^P->v * p mod F.
597 WARNING: this function destroys its input p !!!
598
599 TODO: parallel version ?
600 */
601 static void
mpz_poly_reducemodF(polymodF_t P,mpz_poly_ptr p,mpz_poly_srcptr F)602 mpz_poly_reducemodF(polymodF_t P, mpz_poly_ptr p, mpz_poly_srcptr F)
603 {
604 int v = 0;
605
606 if (p->deg < F->deg) {
607 mpz_poly_set(P->p, p);
608 P->v = 0;
609 return;
610 }
611
612 const int d = F->deg;
613
614 while (p->deg >= d) {
615 const int k = p->deg;
616 int i;
617
618 /* We compute F[d]*p - p[k]*F. In case F[d] divides p[k], we can simply
619 compute p - p[k]/F[d]*F. However this will happen rarely with
620 Kleinjung's polynomial selection, since lc(F) is large. */
621
622 /* FIXME: in msieve, Jason Papadopoulos reduces by F[d]^d*F(x/F[d])
623 instead of F(x). This might avoid one of the for-loops below. */
624
625 // temporary hack: account for the possibility that we're indeed
626 // using f_hat instead of f.
627 if (mpz_cmp_ui(F->coeff[d], 1) != 0) {
628 v++; /* we consider p/F[d]^v */
629 for (i = 0; i < k; ++i)
630 mpz_mul (p->coeff[i], p->coeff[i], F->coeff[d]);
631 }
632
633 for (i = 0; i < d; ++i)
634 mpz_submul (p->coeff[k-d+i], p->coeff[k], F->coeff[i]);
635
636 mpz_poly_cleandeg (p, k-1);
637 }
638
639 mpz_poly_set(P->p, p);
640 P->v = v;
641 }
642
643
644
645 /* --------------------------------------------------------------------------
646 Public functions
647 -------------------------------------------------------------------------- */
648
649
650 /* Management of the structure, set and print coefficients. */
651
652
653 /* Allocate a polynomial that can contain 'd+1' coefficients and set to zero.
654 We allow d < 0, which is equivalent to d = -1.
655 */
mpz_poly_init(mpz_poly_ptr f,int d)656 void mpz_poly_init(mpz_poly_ptr f, int d)
657 {
658 f->deg = -1;
659 if (d < 0)
660 {
661 f->alloc = 0;
662 f->coeff = (mpz_t *) NULL;
663 }
664 else
665 {
666 int i;
667 f->alloc = d+1;
668 f->coeff = (mpz_t *) malloc ((d+1)*sizeof(mpz_t));
669 FATAL_ERROR_CHECK (f->coeff == NULL, "not enough memory");
670 for (i = 0; i <= d; ++i)
671 mpz_init (f->coeff[i]);
672 }
673 }
674
675
676 /* realloc f to (at least) nc coefficients */
mpz_poly_realloc(mpz_poly_ptr f,int nc)677 void mpz_poly_realloc (mpz_poly_ptr f, int nc)
678 {
679 int i;
680 if (f->alloc < nc)
681 {
682 f->coeff = (mpz_t*) realloc (f->coeff, nc * sizeof (mpz_t));
683 FATAL_ERROR_CHECK (f->coeff == NULL, "not enough memory");
684 for (i = f->alloc; i < nc; i++)
685 mpz_init (f->coeff[i]);
686 f->alloc = nc;
687 }
688 }
689
690 /* Copy f to g, where g must be initialized (but there is no need it has
691 enough allocated coefficients, since mpz_poly_setcoeff reallocates if
692 needed). */
mpz_poly_set(mpz_poly_ptr g,mpz_poly_srcptr f)693 void mpz_poly_set(mpz_poly_ptr g, mpz_poly_srcptr f)
694 {
695 int i;
696
697 if (g == f)
698 return; /* nothing to do */
699
700 g->deg = f->deg;
701 for (i = f->deg; i >= 0; --i)
702 mpz_poly_setcoeff (g, i, f->coeff[i]);
703 }
704
mpz_poly_set_double_poly(mpz_poly_ptr g,double_poly_srcptr f)705 void mpz_poly_set_double_poly(mpz_poly_ptr g, double_poly_srcptr f)
706 {
707 mpz_poly_realloc (g, f->deg + 1);
708 g->deg = f->deg;
709 for (int i = f->deg; i >= 0; --i)
710 mpz_set_d (g->coeff[i], f->coeff[i]);
711 }
712
713 /* Init polynomial rel and set it to a - b*x */
714 void
mpz_poly_init_set_ab(mpz_poly_ptr rel,int64_t a,uint64_t b)715 mpz_poly_init_set_ab (mpz_poly_ptr rel, int64_t a, uint64_t b)
716 {
717 mpz_poly_init(rel, 1);
718 mpz_poly_setcoeff_int64(rel, 0, a);
719 mpz_poly_setcoeff_int64(rel, 1, -b);
720 }
721
722 /* rel <- a-b*x */
723 void
mpz_poly_init_set_mpz_ab(mpz_poly_ptr rel,mpz_srcptr a,mpz_srcptr b)724 mpz_poly_init_set_mpz_ab (mpz_poly_ptr rel, mpz_srcptr a, mpz_srcptr b)
725 {
726 mpz_poly_init(rel, 1);
727 mpz_poly_setcoeff(rel, 0, a);
728 mpz_t mb;
729 mpz_init(mb);
730 mpz_neg(mb, b);
731 mpz_poly_setcoeff(rel, 1, mb);
732 mpz_clear(mb);
733 }
734
735 /* swap f and g */
736 void
mpz_poly_swap(mpz_poly_ptr f,mpz_poly_ptr g)737 mpz_poly_swap (mpz_poly_ptr f, mpz_poly_ptr g)
738 {
739 int i;
740 mpz_t *t;
741
742 i = f->alloc;
743 f->alloc = g->alloc;
744 g->alloc = i;
745 i = f->deg;
746 f->deg = g->deg;
747 g->deg = i;
748 t = f->coeff;
749 f->coeff = g->coeff;
750 g->coeff = t;
751 }
752
753 /* Free polynomial f in mpz_poly. */
mpz_poly_clear(mpz_poly_ptr f)754 void mpz_poly_clear(mpz_poly_ptr f)
755 {
756 int i;
757 for (i = 0; i < f->alloc; ++i)
758 mpz_clear(f->coeff[i]);
759 if (f->coeff != NULL)
760 free(f->coeff);
761 f->coeff = NULL; /* to avoid a double-free */
762 memset(f, 0, sizeof(mpz_poly));
763 f->deg = -1;
764 f->alloc = 0; /* to avoid a double-free */
765 }
766
767 /* Return 0 if f[i] is zero, -1 is f[i] is negative and +1 if f[i] is positive,
768 like mpz_sgn function. */
mpz_poly_coeff_sgn(mpz_poly_srcptr f,int i)769 static inline int mpz_poly_coeff_sgn (mpz_poly_srcptr f, int i)
770 {
771 if (i >= f->alloc)
772 return 0;
773 else
774 return mpz_sgn (f->coeff[i]);
775 }
776
777 /* removed mpz_poly_set_deg, as for all purposes there is no reason to
778 * not use the more robust mpz_poly_cleandeg */
779
780 /* Find polynomial degree. */
mpz_poly_cleandeg(mpz_poly_ptr f,int deg)781 void mpz_poly_cleandeg(mpz_poly_ptr f, int deg)
782 {
783 ASSERT(deg >= -1);
784 while ((deg >= 0) && (mpz_poly_coeff_sgn (f, deg)==0))
785 deg--;
786 f->deg = deg;
787 }
788
789 /* Sets f to the polynomial of degree d, of coefficients
790 given by coeffs. */
mpz_poly_setcoeffs(mpz_poly_ptr f,mpz_t * coeffs,int d)791 void mpz_poly_setcoeffs (mpz_poly_ptr f, mpz_t * coeffs, int d)
792 {
793 int i;
794 for (i=d; i>=0; --i)
795 mpz_poly_setcoeff(f, i, coeffs[i]);
796 mpz_poly_cleandeg(f, d);
797 }
798
799 /* Set a zero polynomial. */
mpz_poly_set_zero(mpz_poly_ptr f)800 void mpz_poly_set_zero(mpz_poly_ptr f)
801 {
802 f->deg = -1;
803 }
804
805 /* Set mpz_t coefficient for the i-th term. */
mpz_poly_setcoeff(mpz_poly_ptr f,int i,mpz_srcptr z)806 void mpz_poly_setcoeff (mpz_poly_ptr f, int i, mpz_srcptr z)
807 {
808 mpz_poly_realloc (f, i + 1);
809 mpz_set (f->coeff[i], z);
810 if (i >= f->deg)
811 mpz_poly_cleandeg (f, i);
812 }
813
814 /* Set signed int coefficient for the i-th term. */
mpz_poly_setcoeff_si(mpz_poly_ptr f,int i,long z)815 void mpz_poly_setcoeff_si(mpz_poly_ptr f, int i, long z)
816 {
817 mpz_poly_realloc (f, i + 1);
818 mpz_set_si (f->coeff[i], z);
819 if (i >= f->deg)
820 mpz_poly_cleandeg (f, i);
821 }
822
823 /* Set unsigned int coefficient for the i-th term. */
mpz_poly_setcoeff_ui(mpz_poly_ptr f,int i,unsigned long z)824 void mpz_poly_setcoeff_ui(mpz_poly_ptr f, int i, unsigned long z)
825 {
826 mpz_poly_realloc (f, i + 1);
827 mpz_set_ui (f->coeff[i], z);
828 if (i >= f->deg)
829 mpz_poly_cleandeg (f, i);
830 }
831
832 /* Set int64 coefficient for the i-th term. */
mpz_poly_setcoeff_int64(mpz_poly_ptr f,int i,int64_t z)833 void mpz_poly_setcoeff_int64(mpz_poly_ptr f, int i, int64_t z)
834 {
835 mpz_poly_realloc (f, i + 1);
836 mpz_set_int64 (f->coeff[i], z);
837 if (i >= f->deg)
838 mpz_poly_cleandeg (f, i);
839 }
840
841 /* Set uint64 coefficient for the i-th term. */
mpz_poly_setcoeff_uint64(mpz_poly_ptr f,int i,uint64_t z)842 void mpz_poly_setcoeff_uint64(mpz_poly_ptr f, int i, uint64_t z)
843 {
844 mpz_poly_realloc (f, i + 1);
845 mpz_set_uint64 (f->coeff[i], z);
846 if (i >= f->deg)
847 mpz_poly_cleandeg (f, i);
848 }
849
850 /* f[i] <- z */
mpz_poly_setcoeff_double(mpz_poly_ptr f,int i,double z)851 void mpz_poly_setcoeff_double(mpz_poly_ptr f, int i, double z)
852 {
853 mpz_poly_realloc (f, i + 1);
854 mpz_set_d (f->coeff[i], z);
855 if (i >= f->deg)
856 mpz_poly_cleandeg (f, i);
857 }
858
859 /* Get coefficient for the i-th term. */
mpz_poly_getcoeff(mpz_ptr res,int i,mpz_poly_srcptr f)860 void mpz_poly_getcoeff(mpz_ptr res, int i, mpz_poly_srcptr f)
861 {
862 if (i > f->deg)
863 mpz_set_ui (res, 0);
864 else
865 mpz_set (res, f->coeff[i]);
866 }
867
868 /* x^i is often useful */
mpz_poly_set_xi(mpz_poly_ptr f,int i)869 void mpz_poly_set_xi(mpz_poly_ptr f, int i)
870 {
871 mpz_poly_realloc (f, i + 1);
872 for(int j = 0 ; j <= i ; j++) {
873 mpz_set_ui(f->coeff[j], j == i);
874 }
875 f->deg = i;
876 }
877
mpz_poly_set_mpz(mpz_poly_ptr f,mpz_srcptr z)878 void mpz_poly_set_mpz(mpz_poly_ptr f, mpz_srcptr z)
879 {
880 mpz_poly_realloc (f, 1);
881 mpz_set(f->coeff[0], z);
882 mpz_poly_cleandeg(f, 0);
883 }
884
885 /* g <- quo (f, x^i) */
mpz_poly_div_xi(mpz_poly_ptr g,mpz_poly_srcptr f,int i)886 void mpz_poly_div_xi(mpz_poly_ptr g, mpz_poly_srcptr f, int i)
887 {
888 if (f->deg < i) {
889 mpz_poly_set_zero(g);
890 return;
891 }
892 if (i == 0) {
893 mpz_poly_set(g, f);
894 return;
895 }
896 if (g == f) {
897 /* rotate the coefficients, don't do any freeing */
898 mpz_t * temp = (mpz_t*) malloc(i * sizeof(mpz_t));
899 memcpy(temp, g->coeff, i * sizeof(mpz_t));
900 memmove(g->coeff, g->coeff + i, (g->deg + 1 - i) * sizeof(mpz_t));
901 memcpy(g->coeff + (g->deg + 1 - i), temp, i * sizeof(mpz_t));
902 g->deg -= i;
903 free(temp);
904 return;
905 }
906
907 mpz_poly_realloc(g, 1 + f->deg - i);
908 for(int j = i ; j <= f->deg ; j++) {
909 mpz_set(g->coeff[j - i], f->coeff[j]);
910 }
911 g->deg = f->deg - i;
912 }
913
914 /* g <- f * x^i */
915 void
mpz_poly_mul_xi(mpz_poly_ptr g,mpz_poly_srcptr f,int i)916 mpz_poly_mul_xi (mpz_poly_ptr g, mpz_poly_srcptr f, int i)
917 {
918 if (i == 0) {
919 mpz_poly_set(g, f);
920 return;
921 }
922
923 mpz_poly_realloc(g, 1 + f->deg + i);
924
925 if (g == f) {
926 for(int j = g->deg ; j >= 0 ; j--) {
927 mpz_swap(g->coeff[j + i], g->coeff[j]);
928 }
929 } else {
930 for(int j = g->deg ; j >= 0 ; j--) {
931 mpz_set(g->coeff[j + i], g->coeff[j]);
932 }
933 }
934 for(int j = 0 ; j < i ; j++) {
935 mpz_set_ui(g->coeff[j], 0);
936 }
937 g->deg = f->deg + i;
938 }
939
940 /* g <- f * (x + a) */
mpz_poly_mul_xplusa(mpz_poly_ptr g,mpz_poly_srcptr f,mpz_srcptr a)941 void mpz_poly_mul_xplusa(mpz_poly_ptr g, mpz_poly_srcptr f, mpz_srcptr a)
942 {
943 mpz_t aux;
944 mpz_init_set_ui(aux, 0);
945 mpz_poly_realloc(g, f->deg + 2);
946 for(int i = 0 ; i <= f->deg ; i++) {
947 /* aux is is coeff of degree [i-1]. We want
948 * (coeff_i, aux) <- (coeff_{i-1} + a * coeff_i, coeff_i)
949 * (aux + a * coeff_i, coeff_i)
950 */
951 if (a) mpz_addmul(aux, f->coeff[i], a);
952 mpz_swap(g->coeff[i], aux);
953 if (f != g) {
954 mpz_set(aux, f->coeff[i]);
955 }
956 }
957 /* last coefficient */
958 mpz_swap(g->coeff[f->deg + 1], aux);
959 /* This is just as valid as it was for f */
960 g->deg = f->deg + 1;
961 mpz_clear(aux);
962 }
963
964 /* return the valuation of f */
mpz_poly_valuation(mpz_poly_srcptr f)965 int mpz_poly_valuation(mpz_poly_srcptr f)
966 {
967 int n = 0;
968 ASSERT(f->deg >= 0);
969 for( ; n < f->deg && mpz_cmp_ui(f->coeff[n], 0) == 0 ; n++) ;
970 return n;
971 }
972
973
mpz_poly_asprintf(char ** res,mpz_poly_srcptr f)974 int mpz_poly_asprintf(char ** res, mpz_poly_srcptr f)
975 {
976 size_t alloc = 0;
977 size_t size = 0;
978 int rc;
979 static const size_t batch = 4;
980 *res = NULL;
981
982 alloc += batch;
983 *res = (char*) realloc(*res, alloc);
984 if (*res == NULL) goto oom;
985
986 #define SNPRINTF_FRAGMENT(fmt, arg) do { \
987 rc = gmp_snprintf(*res + size, alloc - size, fmt, arg); \
988 if (size + (size_t) rc + 1 >= alloc) { \
989 alloc = MAX(alloc + batch, size + (size_t) rc + 1); \
990 *res = (char*) realloc(*res, alloc); \
991 if (*res == NULL) goto oom; \
992 rc = gmp_snprintf(*res + size, alloc - size, fmt, arg); \
993 } \
994 size += rc; \
995 ASSERT_ALWAYS(size < alloc); \
996 } while (0)
997
998 #define PUTS_FRAGMENT(arg) do { \
999 rc = strlen(arg); \
1000 if (size + (size_t) rc + 1 >= alloc) { \
1001 alloc = MAX(alloc + batch, size + (size_t) rc + 1); \
1002 *res = (char*) realloc(*res, alloc); \
1003 if (*res == NULL) goto oom; \
1004 } \
1005 size += strlcpy(*res + size, arg, alloc-size); \
1006 ASSERT_ALWAYS(size < alloc); \
1007 } while (0)
1008
1009 if (f->deg == -1) {
1010 SNPRINTF_FRAGMENT("%d", 0);
1011 return size;
1012 }
1013 for (int i = 0, printed = 0; i <= f->deg; ++i) {
1014 if (mpz_cmp_ui(f->coeff[i], 0) == 0) continue;
1015 if (printed++ && mpz_cmp_ui(f->coeff[i], 0) > 0)
1016 PUTS_FRAGMENT ("+");
1017 if (i && mpz_cmp_ui(f->coeff[i], 1) == 0) {
1018 PUTS_FRAGMENT ("x");
1019 } else if (i && mpz_cmp_si(f->coeff[i], -1) == 0) {
1020 PUTS_FRAGMENT ("-x");
1021 } else {
1022 SNPRINTF_FRAGMENT ("%Zd", f->coeff[i]);
1023 if (i) {
1024 PUTS_FRAGMENT ("*x");
1025 }
1026 }
1027
1028 if (i > 1) {
1029 SNPRINTF_FRAGMENT ("^%d", i);
1030 }
1031 }
1032
1033 return size;
1034 #undef SNPRINTF_FRAGMENT
1035 #undef PUTS_FRAGMENT
1036 oom:
1037 free(*res);
1038 *res = NULL;
1039 return -1;
1040 }
1041
1042 /* Print coefficients of f.
1043 * endl = 1 if "\n" at the end of fprintf. */
mpz_poly_fprintf_endl(FILE * fp,mpz_poly_srcptr f,int endl)1044 void mpz_poly_fprintf_endl (FILE *fp, mpz_poly_srcptr f, int endl)
1045 {
1046 char * res;
1047 int rc = mpz_poly_asprintf(&res, f);
1048 ASSERT_ALWAYS(rc >= 0);
1049 fprintf(fp, "%s", res);
1050 if (endl) {
1051 fprintf(fp, "\n");
1052 }
1053 free(res);
1054 }
1055
1056 /* Print coefficients of f. */
mpz_poly_fprintf(FILE * fp,mpz_poly_srcptr f)1057 void mpz_poly_fprintf (FILE *fp, mpz_poly_srcptr f)
1058 {
1059 mpz_poly_fprintf_endl (fp, f, 1);
1060 }
1061
1062 /* Print f of degree d with the following format
1063 f0<sep>f1<sep>...<sep>fd\n
1064 Print only '\n' if f = 0 (ie deg(f) = -1)
1065 */
mpz_poly_fprintf_coeffs(FILE * fp,mpz_poly_srcptr f,const char sep)1066 void mpz_poly_fprintf_coeffs (FILE *fp, mpz_poly_srcptr f, const char sep)
1067 {
1068 if (f->deg >= 0)
1069 {
1070 gmp_fprintf (fp, "%Zd", f->coeff[0]);
1071 for (int i = 1; i <= f->deg; i++)
1072 gmp_fprintf (fp, "%c%Zd", sep, f->coeff[i]);
1073 }
1074 fprintf (fp, "\n");
1075 }
1076
1077 /* Read a polynomial printed using mpz_poly_fprintf_coeffs, with the same
1078 separator. */
1079 void
mpz_poly_fscanf_coeffs(FILE * fp,mpz_poly_ptr f,const char sep)1080 mpz_poly_fscanf_coeffs (FILE *fp, mpz_poly_ptr f, const char sep)
1081 {
1082 int c, deg = -1;
1083 mpz_t z;
1084
1085 mpz_init (z);
1086 while ((c = getc (fp)) != '\n')
1087 {
1088 ungetc (c, fp);
1089 int ret = gmp_fscanf (fp, "%Zd", z);
1090 ASSERT_ALWAYS (ret == 1);
1091 deg ++;
1092 mpz_poly_setcoeff (f, deg, z);
1093 c = getc (fp);
1094 if (c == '\n')
1095 break;
1096 ASSERT_ALWAYS (c == sep);
1097 }
1098 mpz_clear (z);
1099 }
1100
1101 /* Print f of degree d with the following format
1102 <pre><letter>0: f0\n
1103 <pre><letter>1: f1\n
1104 ...
1105 <pre><letter>d: fd\n
1106 Print nothing if f = 0 (ie deg(f) = -1)
1107 */
1108 void
mpz_poly_fprintf_cado_format(FILE * fp,mpz_poly_srcptr f,const char letter,const char * prefix)1109 mpz_poly_fprintf_cado_format (FILE *fp, mpz_poly_srcptr f, const char letter,
1110 const char *prefix)
1111 {
1112 for (int i = 0; i <= f->deg; i++)
1113 {
1114 if (prefix)
1115 fputs (prefix, fp);
1116 gmp_fprintf (fp, "%c%d: %Zd\n", letter, i, f->coeff[i]);
1117 }
1118 }
1119
mpz_poly_print_raw(mpz_poly_srcptr f)1120 void mpz_poly_print_raw(mpz_poly_srcptr f){
1121 cxx_mpz_poly F;
1122 mpz_poly_set(F, f);
1123 std::string s = F.print_poly("x");
1124 printf("%s\n", s.c_str());
1125 }
1126
1127 /* -------------------------------------------------------------------------- */
1128
1129 /* Tests and comparison functions */
1130
1131
1132 /* return 0 if f and g are equal,
1133 * -1 if f is "smaller" and 1 if f is "bigger", for some arbitrary
1134 * ordering (lowest degree first, then lex order).
1135 *
1136 * Assumes f and g are normalized */
mpz_poly_cmp(mpz_poly_srcptr a,mpz_poly_srcptr b)1137 int mpz_poly_cmp (mpz_poly_srcptr a, mpz_poly_srcptr b)
1138 {
1139 int r = (a->deg > b->deg) - (b->deg > a->deg);
1140 if (r) return r;
1141 for(int d = a->deg; d >= 0 ; d--) {
1142 r = mpz_cmp(a->coeff[d], b->coeff[d]);
1143 if (r) return r;
1144 }
1145 return 0;
1146 }
1147
1148 /* return 1 if f is normalized, i.e. f[deg] != 0, or the null polynomial. */
mpz_poly_normalized_p(mpz_poly_srcptr f)1149 int mpz_poly_normalized_p (mpz_poly_srcptr f)
1150 {
1151 return (f->deg == -1) || mpz_cmp_ui (f->coeff[f->deg], 0) != 0;
1152 }
1153
1154 /* return 1 if f is nmonic, i.e. f[deg] == 1, return 0 otherwise (null
1155 * polynomial is considered monic).
1156 */
mpz_poly_is_monic(mpz_poly_srcptr f)1157 int mpz_poly_is_monic (mpz_poly_srcptr f)
1158 {
1159 if (f->deg == -1)
1160 return 1;
1161 else if (mpz_cmp_ui (f->coeff[f->deg], 1) == 0)
1162 return 1;
1163 else
1164 return 0;
1165 }
1166
1167 /* -------------------------------------------------------------------------- */
1168
1169 /* Set f=-g.
1170 Note: f can be the same as g. */
mpz_poly_neg(mpz_poly_ptr f,mpz_poly_srcptr g)1171 void mpz_poly_neg (mpz_poly_ptr f, mpz_poly_srcptr g) {
1172 mpz_poly_realloc(f, g->deg + 1);
1173 for (int i = 0 ; i <= g->deg ; i++) {
1174 mpz_neg (f->coeff[i], g->coeff[i]);
1175 }
1176 }
1177
1178 /* Set f=g+h.
1179 Note: f can be the same as g or h;
1180 g can be the same as h. */
mpz_poly_add(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h)1181 void mpz_poly_add(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h) {
1182 int i, maxdeg;
1183 mpz_t z;
1184 mpz_init(z);
1185 maxdeg = max(g->deg, h->deg);
1186 mpz_poly_realloc(f, maxdeg + 1);
1187 for (i = 0 ; i <= maxdeg ; i++) {
1188 if (i <= g->deg)
1189 mpz_set(z, g->coeff[i]);
1190 else
1191 mpz_set_ui(z, 0);
1192 if (i <= h->deg)
1193 mpz_add(z, z, h->coeff[i]);
1194 mpz_set(f->coeff[i], z);
1195 }
1196 f->deg = maxdeg;
1197 mpz_clear(z);
1198 mpz_poly_cleandeg(f, maxdeg);
1199 }
1200
1201 /* Set f=g-h.
1202 Note: f can be the same as g or h;
1203 g can be the same as h. */
1204 void
mpz_poly_sub(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h)1205 mpz_poly_sub(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h)
1206 {
1207 mpz_poly_notparallel_info().mpz_poly_sub(f, g, h);
1208 }
1209 template<typename inf>
mpz_poly_sub(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h)1210 void mpz_poly_parallel_interface<inf>::mpz_poly_sub(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h)
1211 {
1212 int maxdeg = max(g->deg, h->deg);
1213 mpz_poly_realloc(f, maxdeg + 1);
1214 #ifdef HAVE_OPENMP
1215 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
1216 #endif
1217 for (int i = 0 ; i <= maxdeg ; i++) {
1218 if (i <= g->deg && i <= h->deg)
1219 mpz_sub(f->coeff[i], g->coeff[i], h->coeff[i]);
1220 else if (i <= g->deg)
1221 mpz_set(f->coeff[i], g->coeff[i]);
1222 else
1223 mpz_neg(f->coeff[i], h->coeff[i]);
1224 }
1225 f->deg = maxdeg;
1226 mpz_poly_cleandeg(f, maxdeg);
1227 }
1228
1229 /* Set g=f+a where a is unsigned long. */
1230 void
mpz_poly_add_ui(mpz_poly_ptr g,mpz_poly_srcptr f,unsigned long a)1231 mpz_poly_add_ui (mpz_poly_ptr g, mpz_poly_srcptr f, unsigned long a)
1232 {
1233 mpz_poly_set(g, f);
1234 mpz_poly_realloc(g, 1);
1235 if (f->deg >= 0) {
1236 mpz_add_ui(g->coeff[0], f->coeff[0], a);
1237 g->deg = f->deg;
1238 if (g->deg == 0)
1239 mpz_poly_cleandeg(g, g->deg);
1240 } else {
1241 mpz_set_ui(g->coeff[0], a);
1242 g->deg = 0;
1243 }
1244 }
1245
1246 /* Set g=f-a where a is unsigned long. */
1247 void
mpz_poly_sub_ui(mpz_poly_ptr g,mpz_poly_srcptr f,unsigned long a)1248 mpz_poly_sub_ui (mpz_poly_ptr g, mpz_poly_srcptr f, unsigned long a)
1249 {
1250 mpz_poly_set(g, f);
1251 mpz_poly_realloc(g, 1);
1252 if (f->deg >= 0) {
1253 mpz_sub_ui(g->coeff[0], f->coeff[0], a);
1254 g->deg = f->deg;
1255 if (g->deg == 0)
1256 mpz_poly_cleandeg(g, g->deg);
1257 } else {
1258 mpz_set_ui(g->coeff[0], a);
1259 mpz_neg(g->coeff[0], g->coeff[0]);
1260 g->deg = 0;
1261 }
1262 }
1263
mpz_poly_add_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_srcptr a)1264 void mpz_poly_add_mpz(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_srcptr a)
1265 {
1266 mpz_poly_set(f, g);
1267 if (f->deg == -1) {
1268 mpz_poly_set_mpz(f, a);
1269 } else {
1270 mpz_add(f->coeff[0], f->coeff[0], a);
1271 if (f->deg == 0)
1272 mpz_poly_cleandeg(f, 0);
1273 }
1274 }
1275
mpz_poly_sub_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_srcptr a)1276 void mpz_poly_sub_mpz(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_srcptr a)
1277 {
1278 mpz_poly_set(f, g);
1279 if (f->deg == -1) {
1280 mpz_poly_set_mpz(f, a);
1281 mpz_neg(f->coeff[0], f->coeff[0]);
1282 } else {
1283 mpz_sub(f->coeff[0], f->coeff[0], a);
1284 if (f->deg == 0)
1285 mpz_poly_cleandeg(f, 0);
1286 }
1287 }
1288
1289 /* Set f=g-h (mod m). */
1290 void
mpz_poly_sub_mod_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h,mpz_srcptr m)1291 mpz_poly_sub_mod_mpz (mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h, mpz_srcptr m)
1292 {
1293 mpz_poly_notparallel_info().mpz_poly_sub_mod_mpz (f, g, h, m);
1294 }
1295 template<typename inf>
mpz_poly_sub_mod_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h,mpz_srcptr m)1296 void mpz_poly_parallel_interface<inf>::mpz_poly_sub_mod_mpz (mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h, mpz_srcptr m)
1297 {
1298 mpz_poly_sub(f, g, h);
1299 mpz_poly_mod_mpz(f, f, m, NULL);
1300 }
1301
1302 /* Set f=g*h. Note: f might equal g or h.
1303 Assumes the g[g->deg] and h[h->deg[] are not zero. */
mpz_poly_mul(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h)1304 void mpz_poly_mul (mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h)
1305 {
1306 mpz_poly_notparallel_info().mpz_poly_mul(f, g, h);
1307 }
1308 template<typename inf>
1309 void
mpz_poly_mul(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_poly_srcptr h)1310 mpz_poly_parallel_interface<inf>::mpz_poly_mul (mpz_poly_ptr f, mpz_poly_srcptr g, mpz_poly_srcptr h)
1311 {
1312 if (f == h || f == g)
1313 {
1314 mpz_poly aux;
1315 mpz_poly_init (aux, -1);
1316 mpz_poly_mul (aux, g, h);
1317 mpz_poly_set (f, aux);
1318 mpz_poly_clear (aux);
1319 return;
1320 }
1321
1322 /* now f differs from g and h */
1323
1324 if ((g->deg == -1) || (h->deg == -1)) {
1325 f->deg = -1;
1326 return;
1327 }
1328
1329 mpz_poly_realloc (f, g->deg + h->deg + 1);
1330
1331 if (g == h) /* this is a square */
1332 {
1333 f->deg = mpz_poly_sqr_tc ((inf&)*this, f->coeff, g->coeff, g->deg);
1334 return;
1335 }
1336
1337 if (g->deg == 0) {
1338 mpz_poly_mul_mpz (f, h, g->coeff[0]);
1339 return;
1340 }
1341
1342 if (h->deg == 0) {
1343 mpz_poly_mul_mpz (f, g, h->coeff[0]);
1344 return;
1345 }
1346
1347 ASSERT(mpz_cmp_ui (g->coeff[g->deg], 0) != 0);
1348 ASSERT(mpz_cmp_ui (h->coeff[h->deg], 0) != 0);
1349 ASSERT(f != g);
1350 ASSERT(f != h);
1351
1352 #if 1
1353 f->deg = mpz_poly_mul_tc((inf&)*this,f->coeff, g->coeff, g->deg, h->coeff, h->deg);
1354 #else /* segmentation, this code has problem with huge runs, for example
1355 degree 5 with lifting to 631516975 bits */
1356 {
1357 mpz_t G, H;
1358 size_t sg, sh, s;
1359 int i;
1360
1361 mpz_init (G);
1362 mpz_init (H);
1363 sg = mpz_poly_sizeinbase (g, 2);
1364 sh = mpz_poly_sizeinbase (h, 2);
1365 /* the +1 accounts for a possible sign */
1366 for (s = sg + sh + 1, i = (g->deg >= h->deg) ? h->deg + 1 : g->deg + 1;
1367 i > 1; i = (i + 1) / 2, s++);
1368 mpz_set (G, g->coeff[g->deg]);
1369 for (i = g->deg - 1; i >= 0; i--)
1370 {
1371 mpz_mul_2exp (G, G, s);
1372 mpz_add (G, G, g->coeff[i]);
1373 }
1374 /* sanity check: G should have sizeinbase(lc(g))+d*s bits (or -1) */
1375 size_t size_g = mpz_sizeinbase (g->coeff[g->deg], 2) + g->deg * s;
1376 ASSERT(mpz_sizeinbase (G, 2) == size_g ||
1377 mpz_sizeinbase (G, 2) == size_g - 1);
1378 mpz_set (H, h->coeff[h->deg]);
1379 for (i = h->deg - 1; i >= 0; i--)
1380 {
1381 mpz_mul_2exp (H, H, s);
1382 mpz_add (H, H, h->coeff[i]);
1383 }
1384 /* sanity check: H should have sizeinbase(lc(h))+d*s bits (or -1) */
1385 size_t size_h = mpz_sizeinbase (h->coeff[h->deg], 2) + h->deg * s;
1386 ASSERT(mpz_sizeinbase (H, 2) == size_h ||
1387 mpz_sizeinbase (H, 2) == size_h - 1);
1388 size_g = mpz_sizeinbase (G, 2);
1389 size_h = mpz_sizeinbase (H, 2);
1390 /* sanity check: we verify that the product agrees both mod B and B-1 */
1391 mp_limb_t g0 = mpz_getlimbn (G, 0);
1392 mpz_mul (G, G, H);
1393 ASSERT(mpz_getlimbn (G, 0) == g0 * mpz_getlimbn (H, 0));
1394 ASSERT(mpz_sizeinbase (G, 2) == size_g + size_h ||
1395 mpz_sizeinbase (G, 2) == size_g + size_h - 1);
1396 for (i = 0; i < g->deg + h->deg; i++)
1397 {
1398 mpz_fdiv_r_2exp (f->coeff[i], G, s);
1399 if (mpz_sizeinbase (f->coeff[i], 2) == s)
1400 {
1401 mpz_cdiv_r_2exp (f->coeff[i], G, s);
1402 mpz_cdiv_q_2exp (G, G, s);
1403 }
1404 else
1405 mpz_fdiv_q_2exp (G, G, s);
1406 ASSERT(mpz_sizeinbase (f->coeff[i], 2) < s);
1407 }
1408 mpz_set (f->coeff[i], G);
1409 mpz_clear (G);
1410 mpz_clear (H);
1411 f->deg = g->deg + h->deg;
1412 }
1413 #endif
1414 /* there is no need to run mpz_poly_cleandeg since g[g->deg] <> 0
1415 and h[h->deg] <> 0 */
1416 ASSERT(mpz_cmp_ui (f->coeff[f->deg], 0) != 0);
1417 }
1418
1419 /* Set Q=a*P, where a is an mpz_t */
1420 void
mpz_poly_mul_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_srcptr a)1421 mpz_poly_mul_mpz(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_srcptr a)
1422 {
1423 mpz_poly_notparallel_info().mpz_poly_mul_mpz(f, g, a);
1424 }
1425 template<typename inf>
1426 void
mpz_poly_mul_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_srcptr a)1427 mpz_poly_parallel_interface<inf>::mpz_poly_mul_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_srcptr a)
1428 {
1429 mpz_poly_realloc (Q, P->deg + 1);
1430 #ifdef HAVE_OPENMP
1431 #pragma omp parallel if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
1432 #endif
1433 {
1434 mpz_t aux;
1435 mpz_init (aux);
1436 #ifdef HAVE_OPENMP
1437 #pragma omp for
1438 #endif
1439 for (int i = 0; i <= P->deg; i++)
1440 {
1441 mpz_mul (aux, P->coeff[i], a);
1442 mpz_set (Q->coeff[i], aux);
1443 }
1444 mpz_clear (aux);
1445 }
1446 mpz_poly_cleandeg (Q, P->deg);
1447 }
1448
1449 /* Set Q=P/a, where a is an mpz_t. Assume a divides the content of P (the
1450 division is done with mpz_divexact). Otherwise the result is not correct. */
1451 void
mpz_poly_divexact_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_srcptr a)1452 mpz_poly_divexact_mpz(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_srcptr a)
1453 {
1454 mpz_poly_notparallel_info().mpz_poly_divexact_mpz(f, g, a);
1455 }
1456 template<typename inf>
1457 void
mpz_poly_divexact_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_srcptr a)1458 mpz_poly_parallel_interface<inf>::mpz_poly_divexact_mpz(mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_srcptr a)
1459 {
1460 mpz_poly_realloc (Q, P->deg + 1);
1461 #ifdef HAVE_OPENMP
1462 #pragma omp parallel if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
1463 #endif
1464 {
1465 mpz_t aux;
1466 mpz_init (aux);
1467 #ifdef HAVE_OPENMP
1468 #pragma omp for
1469 #endif
1470 for (int i = 0; i <= P->deg; i++)
1471 {
1472 mpz_divexact (aux, P->coeff[i], a);
1473 mpz_set (Q->coeff[i], aux);
1474 }
1475 mpz_clear (aux);
1476 }
1477 mpz_poly_cleandeg (Q, P->deg);
1478 }
1479
1480 /* Test whether a divides P, where a is an mpz_t. */
1481 int
mpz_poly_divisible_mpz(mpz_poly_srcptr P,mpz_srcptr a)1482 mpz_poly_divisible_mpz (mpz_poly_srcptr P, mpz_srcptr a)
1483 {
1484 for (int i = 0; i <= P->deg; ++i)
1485 if (!mpz_divisible_p(P->coeff[i], a)) return 0;
1486 return 1;
1487 }
1488
1489 /* Set ft(x) = f(x+k) where k is an mpz_t, ft and f can be the same poly. */
1490 void
mpz_poly_translation(mpz_poly_ptr ft,mpz_poly_srcptr f,mpz_srcptr k)1491 mpz_poly_translation (mpz_poly_ptr ft, mpz_poly_srcptr f, mpz_srcptr k)
1492 {
1493 int i, j;
1494 int d = f->deg;
1495
1496 mpz_poly_set (ft, f);
1497 for (i = d - 1; i >= 0; i--)
1498 for (j = i; j < d; j++)
1499 mpz_addmul (ft->coeff[j], ft->coeff[j+1], k);
1500 }
1501
1502 /* Set fr = f + k * x^t * g such that t+deg(g) <= deg(f) and t >= 0 (those two
1503 * assumptions are not checked). fr and f can be the same poly */
mpz_poly_rotation(mpz_poly_ptr fr,mpz_poly_srcptr f,mpz_poly_srcptr g,mpz_srcptr k,int t)1504 void mpz_poly_rotation (mpz_poly_ptr fr, mpz_poly_srcptr f, mpz_poly_srcptr g,
1505 mpz_srcptr k, int t)
1506 {
1507 mpz_poly_set (fr, f);
1508 for (int i = 0; i <= g->deg; i++)
1509 mpz_addmul (fr->coeff[i+t], g->coeff[i], k);
1510 }
1511
1512 /* Set f = f + k * g such that deg(g) <= deg(f) (this assumption is not
1513 checked). */
1514 void
mpz_poly_addmul_si(mpz_poly_ptr f,mpz_poly_srcptr g,long k)1515 mpz_poly_addmul_si (mpz_poly_ptr f, mpz_poly_srcptr g, long k)
1516 {
1517 for (int i = 0; i <= g->deg; i++)
1518 mpz_addmul_si (f->coeff[i], g->coeff[i], k);
1519 }
1520
1521 /* Set f = k * g such that deg(g) <= deg(f) (this assumption is not
1522 checked). */
1523 void
mpz_poly_mul_si(mpz_poly_ptr f,mpz_poly_srcptr g,long k)1524 mpz_poly_mul_si (mpz_poly_ptr f, mpz_poly_srcptr g, long k)
1525 {
1526 for (int i = 0; i <= g->deg; i++)
1527 mpz_mul_si (f->coeff[i], g->coeff[i], k);
1528 }
1529
1530 /* Set f = g / k such that deg(g) <= deg(f) and k divides g
1531 (those assumptions are not checked). */
1532 void
mpz_poly_divexact_ui(mpz_poly_ptr f,mpz_poly_srcptr g,unsigned long k)1533 mpz_poly_divexact_ui (mpz_poly_ptr f, mpz_poly_srcptr g, unsigned long k)
1534 {
1535 for (int i = 0; i <= g->deg; i++)
1536 mpz_divexact_ui (f->coeff[i], g->coeff[i], k);
1537 }
1538
1539 /* Set h = fr + k * x^t * g such that t+deg(g) <= deg(f) and t >= 0 (those two
1540 * assumptions are not checked). fr and f can be the same poly */
mpz_poly_rotation_int64(mpz_poly_ptr fr,mpz_poly_srcptr f,mpz_poly_srcptr g,const int64_t k,int t)1541 void mpz_poly_rotation_int64 (mpz_poly_ptr fr, mpz_poly_srcptr f,
1542 mpz_poly_srcptr g, const int64_t k, int t)
1543 {
1544 mpz_poly_set (fr, f);
1545 for (int i = 0; i <= g->deg; i++)
1546 mpz_addmul_int64 (fr->coeff[i+t], g->coeff[i], k);
1547 }
1548
1549 /* h=rem(h, f) mod N, f not necessarily monic, N not necessarily prime */
1550 /* Coefficients of f must be reduced mod N
1551 * Coefficients of h need not be reduced mod N on input, but are reduced
1552 * on output.
1553 *
1554 * If division fails, stores a non-trivial factor of N in factor. This is
1555 * not done if factor==NULL.
1556 */
1557 static int
mpz_poly_pseudodiv_r(mpz_poly_ptr h,mpz_poly_srcptr f,mpz_srcptr N,mpz_ptr factor)1558 mpz_poly_pseudodiv_r (mpz_poly_ptr h, mpz_poly_srcptr f, mpz_srcptr N, mpz_ptr factor)
1559 {
1560 int i, d = f->deg, dh = h->deg;
1561 mpz_t tmp, inv;
1562
1563 mpz_init_set_ui (inv, 1);
1564 mpz_init_set_ui (tmp, 1);
1565
1566 mpz_set (tmp, f->coeff[d]);
1567 if (mpz_cmp_ui(tmp, 1) != 0) {
1568 /* inv is 1/f[d] mod N */
1569 if (!mpz_invert (inv, tmp, N)) {
1570 if (factor != NULL)
1571 mpz_gcd(factor, tmp, N);
1572 mpz_clear(inv);
1573 mpz_clear(tmp);
1574 return 0;
1575 }
1576 }
1577
1578 while (dh >= d)
1579 {
1580 /* subtract h[dh]/f[d]*x^(dh-d)*f from h */
1581 if (mpz_cmp_ui(inv, 1) != 0) {
1582 mpz_mul (h->coeff[dh], h->coeff[dh], inv);
1583 mpz_ndiv_r (h->coeff[dh], h->coeff[dh], N);
1584 }
1585
1586 for (i = 0; i < d; i++) {
1587 mpz_mul (tmp, h->coeff[dh], f->coeff[i]);
1588 mpz_mod (tmp, tmp, N);
1589 mpz_sub (h->coeff[dh - d + i], h->coeff[dh - d + i], tmp);
1590 mpz_ndiv_r (h->coeff[dh - d + i], h->coeff[dh - d + i], N);
1591 }
1592
1593 do {
1594 dh --;
1595 }
1596 while (dh >= 0 && mpz_divisible_p (h->coeff[dh], N));
1597
1598 h->deg = dh;
1599 }
1600
1601 mpz_clear (inv);
1602 mpz_clear (tmp);
1603 return 1;
1604 }
1605
1606 /* h=rem(h, f) mod p, f not necessarily monic. */
1607 /* returns 0 if an inverse of the leading coeff could not be found. */
1608 int
mpz_poly_div_r(mpz_poly_ptr h,mpz_poly_srcptr f,mpz_srcptr p)1609 mpz_poly_div_r (mpz_poly_ptr h, mpz_poly_srcptr f, mpz_srcptr p)
1610 {
1611 return mpz_poly_pseudodiv_r (h, f, p, NULL);
1612 }
1613
1614 /*
1615 computes q, r such that f = q*g + r mod p, with deg(r) < deg(g)
1616 and p in mpz_t
1617 q and r must be allocated!
1618 the only aliasing allowed is f==r.
1619 */
mpz_poly_div_qr(mpz_poly_ptr q,mpz_poly_ptr r,mpz_poly_srcptr f,mpz_poly_srcptr g,mpz_srcptr p)1620 int mpz_poly_div_qr (mpz_poly_ptr q, mpz_poly_ptr r, mpz_poly_srcptr f, mpz_poly_srcptr g, mpz_srcptr p)
1621 {
1622 int k, j, df = f->deg, dg = g->deg, dq = df - dg;
1623 mpz_t lg, invlg;
1624
1625 if (df < dg) /* f is already reduced mod g */
1626 {
1627 mpz_poly_set_zero (q);
1628 mpz_poly_set (r, f);
1629 return 1;
1630 }
1631
1632 /* now df >= dg */
1633 mpz_poly_realloc(q, dq + 1);
1634
1635 mpz_init(lg);
1636 mpz_init_set_ui(invlg, 1);
1637
1638 mpz_poly_set(r, f);
1639 q->deg = dq;
1640
1641 mpz_set (lg, g->coeff[dg]);
1642 mpz_mod (lg, lg, p);
1643 /* invlg = 1/g[dg] mod p */
1644 if (mpz_cmp_ui(lg, 1) != 0)
1645 if (!mpz_invert(invlg, lg, p)) {
1646 mpz_clear(lg);
1647 mpz_clear(invlg);
1648 return 0;
1649 }
1650
1651
1652 for (k = df-dg ; k >=0 ; k--) {
1653 mpz_mul(q->coeff[k], r->coeff[k+dg], invlg);
1654 mpz_mod(q->coeff[k], q->coeff[k], p);
1655 for (j = dg+k ; j >= k ; j--) {
1656 mpz_submul(r->coeff[j], q->coeff[k], g->coeff[j-k]);
1657 mpz_mod(r->coeff[j], r->coeff[j], p);
1658 }
1659 }
1660 mpz_poly_cleandeg(r, r->deg);
1661
1662 mpz_clear(invlg);
1663 mpz_clear(lg);
1664 return 1;
1665 }
1666
1667 /* This also computes q and r such that f = q * g + r, but over Z, not
1668 * modulo a prime. Also, we do not assume that g is monic. Of course, if
1669 * it is not, then most often the result will be undefined (over Z). We
1670 * return something well-defined if q and r happen to be integer
1671 * polynomials.
1672 * We return 0 if this is not the case (in which case q and r are
1673 * undefined).
1674 * r==f is allowed.
1675 *
1676 * TODO: do the parallel version
1677 */
mpz_poly_div_qr_z(mpz_poly_ptr q,mpz_poly_ptr r,mpz_poly_srcptr f,mpz_poly_srcptr g)1678 int mpz_poly_div_qr_z (mpz_poly_ptr q, mpz_poly_ptr r, mpz_poly_srcptr f, mpz_poly_srcptr g)
1679 {
1680 int k, j, df = f->deg, dg = g->deg, dq = df - dg;
1681
1682 if (df < dg) /* f is already reduced mod g */
1683 {
1684 mpz_poly_set_zero (q);
1685 mpz_poly_set (r, f);
1686 return 1;
1687 }
1688
1689 /* now df >= dg */
1690 mpz_poly_realloc(q, dq + 1);
1691
1692 mpz_poly_set(r, f);
1693 q->deg = dq;
1694
1695 mpz_srcptr lg = g->coeff[dg];
1696
1697 for (k = df-dg ; k >=0 ; k--) {
1698 if (!mpz_divisible_p(r->coeff[k+dg], lg))
1699 return 0;
1700 mpz_divexact(q->coeff[k], r->coeff[k+dg], lg);
1701 for (j = dg+k ; j >= k ; j--) {
1702 mpz_submul(r->coeff[j], q->coeff[k], g->coeff[j-k]);
1703 }
1704 }
1705 mpz_poly_cleandeg(r, r->deg);
1706 return 1;
1707 }
mpz_poly_div_r_z(mpz_poly_ptr r,mpz_poly_srcptr f,mpz_poly_srcptr g)1708 int mpz_poly_div_r_z (mpz_poly_ptr r, mpz_poly_srcptr f, mpz_poly_srcptr g)
1709 {
1710 mpz_poly quo;
1711 mpz_poly_init(quo,-1);
1712 int ret = mpz_poly_div_qr_z(quo,r,f,g);
1713 mpz_poly_clear(quo);
1714 return ret;
1715 }
1716
1717
1718 /* q=divexact(h, f) mod p, f not necessarily monic.
1719 Assumes lc(h) <> 0 mod p.
1720 Clobbers h. */
1721 /* Coefficients of f must be reduced mod p
1722 * Coefficients of h need not be reduced mod p
1723 * Coefficients of q are reduced mod p
1724 */
1725 static int
mpz_poly_divexact_clobber(mpz_poly_ptr q,mpz_poly_ptr h,mpz_poly_srcptr f,mpz_srcptr p)1726 mpz_poly_divexact_clobber (mpz_poly_ptr q, mpz_poly_ptr h, mpz_poly_srcptr f,
1727 mpz_srcptr p)
1728 {
1729 int i, d = f->deg, dh = h->deg;
1730 mpz_t t, aux;
1731
1732 mpz_init (t);
1733 mpz_init (aux);
1734 ASSERT (d >= 0);
1735 ASSERT (dh >= 0);
1736 ASSERT (dh >= d);
1737 ASSERT (mpz_divisible_p (h->coeff[dh], p) == 0);
1738
1739 mpz_poly_realloc (q, dh + 1 - d);
1740 q->deg = dh - d;
1741 /* t is 1/f[d] mod p */
1742 mpz_set (aux, f->coeff[d]);
1743 mpz_mod (aux, aux, p);
1744 if (!mpz_invert (t, aux, p)) {
1745 mpz_clear(t);
1746 mpz_clear(aux);
1747 return 0;
1748 }
1749
1750
1751 while (dh >= d) {
1752
1753 /* subtract h[dh]/f[d]*x^(dh-d)*f from h */
1754 if (mpz_cmp_ui(t, 1) != 0) {
1755 mpz_mul (h->coeff[dh], h->coeff[dh], t);
1756 mpz_mod (h->coeff[dh], h->coeff[dh], p);
1757 }
1758 mpz_set (q->coeff[dh-d], h->coeff[dh]);
1759 mpz_mod (q->coeff[dh-d], q->coeff[dh - d], p);
1760
1761 /* we only need to update the coefficients of degree >= d of h,
1762 i.e., we want i >= 2d - dh */
1763 for (i = (2 * d > dh) ? 2 * d - dh : 0; i < d; i++) {
1764 mpz_mul (aux, h->coeff[dh], f->coeff[i]);
1765 mpz_sub (h->coeff[dh - d + i], h->coeff[dh - d + i], aux);
1766 mpz_mod (h->coeff[dh - d + i], h->coeff[dh - d + i], p);
1767 }
1768 dh --;
1769 }
1770 /* since lc(h) <> 0 mod p, q is normalized */
1771
1772 mpz_clear (t);
1773 mpz_clear (aux);
1774 return 1;
1775 }
1776
1777 /* q <- divexact(h, f) mod p, f not necessarily monic. */
1778 /* Coefficients of f must be reduced mod p
1779 * Coefficients of h need not be reduced mod p
1780 * Coefficients of q are reduced mod p
1781 */
1782 int
mpz_poly_divexact(mpz_poly_ptr q,mpz_poly_srcptr h,mpz_poly_srcptr f,mpz_srcptr p)1783 mpz_poly_divexact (mpz_poly_ptr q, mpz_poly_srcptr h, mpz_poly_srcptr f, mpz_srcptr p)
1784 {
1785 mpz_poly hh;
1786 mpz_poly_init(hh, h->deg);
1787 mpz_poly_set(hh, h);
1788 int r = mpz_poly_divexact_clobber(q, hh, f, p);
1789 mpz_poly_clear(hh);
1790 return r;
1791 }
1792
1793 /* Set f=g/2 (mod m), where f might equal g.
1794 Assumes m is odd. */
1795 /* If coefficients of g are reduced mod m, then coefficients of f are
1796 * reduced.
1797 */
1798 void
mpz_poly_div_2_mod_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_srcptr a)1799 mpz_poly_div_2_mod_mpz(mpz_poly_ptr f, mpz_poly_srcptr g, mpz_srcptr a)
1800 {
1801 mpz_poly_notparallel_info().mpz_poly_div_2_mod_mpz(f, g, a);
1802 }
1803 template<typename inf>
mpz_poly_div_2_mod_mpz(mpz_poly_ptr f,mpz_poly_srcptr g,mpz_srcptr m)1804 void mpz_poly_parallel_interface<inf>::mpz_poly_div_2_mod_mpz (mpz_poly_ptr f, mpz_poly_srcptr g, mpz_srcptr m)
1805 {
1806 ASSERT_ALWAYS(mpz_scan1 (m, 0) == 0);
1807
1808 mpz_poly_realloc (f, g->deg + 1);
1809
1810 #ifdef HAVE_OPENMP
1811 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
1812 #endif
1813 for (int i = g->deg; i >= 0; --i)
1814 {
1815 if (mpz_scan1 (g->coeff[i], 0) == 0) /* g[i] is odd */
1816 {
1817 mpz_add (f->coeff[i], g->coeff[i], m);
1818 mpz_div_2exp (f->coeff[i], f->coeff[i], 1);
1819 }
1820 else
1821 mpz_div_2exp (f->coeff[i], g->coeff[i], 1);
1822 }
1823 }
1824
1825 /* Set res=f(x). Assumes res and x are different variables. */
mpz_poly_eval(mpz_ptr res,mpz_poly_srcptr f,mpz_srcptr x)1826 void mpz_poly_eval(mpz_ptr res, mpz_poly_srcptr f, mpz_srcptr x) {
1827 int i, d;
1828 ASSERT_ALWAYS(res != x);
1829 d = f->deg;
1830 if (d == -1) {
1831 mpz_set_ui(res, 0);
1832 return;
1833 }
1834 mpz_set(res, f->coeff[d]);
1835 for (i = d-1; i>=0; --i) {
1836 mpz_mul(res, res, x);
1837 mpz_add(res, res, f->coeff[i]);
1838 }
1839 }
1840
1841 /* Set res=f(x). Assumes res and x are different variables. */
mpz_poly_eval_poly(mpz_poly_ptr res,mpz_poly_srcptr f,mpz_poly_srcptr x)1842 void mpz_poly_eval_poly(mpz_poly_ptr res, mpz_poly_srcptr f, mpz_poly_srcptr x)
1843 {
1844 int i, d;
1845 ASSERT_ALWAYS(res != x);
1846 ASSERT_ALWAYS(res != f);
1847 d = f->deg;
1848 if (d == -1) {
1849 mpz_poly_set_zero(res);
1850 return;
1851 }
1852 mpz_poly_set_mpz(res, f->coeff[d]);
1853 for (i = d-1; i>=0; --i) {
1854 mpz_poly_mul(res, res, x);
1855 mpz_poly_add_mpz(res, res, f->coeff[i]);
1856 }
1857 }
1858
1859 /* Set res=f(x) where x is an unsigned long. */
mpz_poly_eval_ui(mpz_ptr res,mpz_poly_srcptr f,unsigned long x)1860 void mpz_poly_eval_ui (mpz_ptr res, mpz_poly_srcptr f, unsigned long x)
1861 {
1862 int d = f->deg;
1863
1864 mpz_set (res, f->coeff[d]);
1865 for (int i = d - 1; i >= 0; i--)
1866 {
1867 mpz_mul_ui (res, res, x);
1868 mpz_add (res, res, f->coeff[i]);
1869 }
1870 }
1871
1872 /* Set res=f'(x), where x is an unsigned long */
1873 void
mpz_poly_eval_diff_ui(mpz_ptr res,mpz_poly_srcptr f,unsigned long x)1874 mpz_poly_eval_diff_ui (mpz_ptr res, mpz_poly_srcptr f, unsigned long x)
1875 {
1876 int d = f->deg;
1877
1878 mpz_mul_ui (res, f->coeff[d], d);
1879 for (int i = d - 1; i >= 1; i--)
1880 {
1881 mpz_mul_ui (res, res, x);
1882 mpz_addmul_ui (res, f->coeff[i], i); /* res <- res + i*f[i] */
1883 }
1884 }
1885
1886 void
mpz_poly_eval_diff(mpz_ptr res,mpz_poly_srcptr f,mpz_srcptr x)1887 mpz_poly_eval_diff (mpz_ptr res, mpz_poly_srcptr f, mpz_srcptr x)
1888 {
1889 int d = f->deg;
1890 ASSERT_ALWAYS(res != x);
1891
1892 mpz_mul_ui (res, f->coeff[d], d);
1893 for (int i = d - 1; i >= 1; i--)
1894 {
1895 mpz_mul (res, res, x);
1896 mpz_addmul_ui (res, f->coeff[i], i); /* res <- res + i*f[i] */
1897 }
1898 }
1899
1900
1901 /* Set res=f'(x), where x is a polynomial */
mpz_poly_eval_diff_poly(mpz_poly_ptr res,mpz_poly_srcptr f,mpz_poly_srcptr x)1902 void mpz_poly_eval_diff_poly (mpz_poly_ptr res, mpz_poly_srcptr f, mpz_poly_srcptr x)
1903 {
1904 ASSERT_ALWAYS(res != x);
1905 ASSERT_ALWAYS(res != f);
1906 int d = f->deg;
1907 mpz_poly_realloc(res, f->deg * x->deg + 1);
1908 mpz_t t;
1909 mpz_init(t);
1910 mpz_mul_ui (t, f->coeff[d], d);
1911 mpz_poly_add_mpz(res, res, t);
1912 for (int i = d - 1; i >= 1; i--)
1913 {
1914 mpz_poly_mul (res, res, x);
1915 mpz_mul_ui (t, f->coeff[i], i); /* res <- res + i*f[i] */
1916 mpz_poly_add_mpz(res, res, t);
1917 }
1918 mpz_clear(t);
1919 }
1920
1921
1922 /* Return 1 if poly(root) % modulus == 0, return 0 otherwise */
1923 /* Coefficients of f(x) need not be reduced mod m */
mpz_poly_is_root(mpz_poly_srcptr poly,mpz_srcptr root,mpz_srcptr modulus)1924 int mpz_poly_is_root(mpz_poly_srcptr poly, mpz_srcptr root, mpz_srcptr modulus)
1925 {
1926 mpz_t x;
1927 mpz_init(x);
1928 mpz_poly_eval_mod_mpz(x, poly, root, modulus);
1929 int is_root = (mpz_cmp_ui(x, 0) == 0);
1930 mpz_clear(x);
1931 return is_root;
1932 }
1933
1934 /* Set res=f(x) (mod m). Assume res and x are different variables. */
1935 /* Coefficients of f(x) need not be reduced mod m.
1936 * The computed value res is reduced mod m
1937 */
1938 void
mpz_poly_eval_mod_mpz(mpz_t res,mpz_poly_srcptr f,mpz_srcptr x,mpz_srcptr m)1939 mpz_poly_eval_mod_mpz (mpz_t res, mpz_poly_srcptr f, mpz_srcptr x,
1940 mpz_srcptr m)
1941 {
1942 int i, d;
1943
1944 d = f->deg;
1945 if (d == -1) {
1946 mpz_set_ui(res, 0);
1947 return;
1948 }
1949 mpz_mod (res, f->coeff[d], m);
1950 for (i = d-1; i>=0; --i) {
1951 mpz_mul(res, res, x);
1952 mpz_add(res, res, f->coeff[i]);
1953 mpz_mod (res, res, m);
1954 }
1955 }
1956
1957 /* This evaluates several polynomials at the same point w. It is possible
1958 * to do fewer modular reductions in this case.
1959 *
1960 * When k==1, we use mpz_poly_eval_mod_mpz instead, since it's faster
1961 * then.
1962 */
1963 /* Coefficients of f[i](x) need not be reduced mod m.
1964 * The computed values r[i] are reduced mod m
1965 */
1966 void
mpz_poly_eval_several_mod_mpz(mpz_ptr * r,mpz_poly_srcptr * f,int k,mpz_srcptr x,mpz_srcptr m)1967 mpz_poly_eval_several_mod_mpz (mpz_ptr *r, mpz_poly_srcptr *f, int k,
1968 mpz_srcptr x, mpz_srcptr m)
1969 {
1970 int i;
1971
1972 if (k == 1) {
1973 mpz_poly_eval_mod_mpz (r[0], f[0], x, m);
1974 return;
1975 }
1976
1977 mpz_t w;
1978 mpz_init(w);
1979 int maxdeg = -1;
1980 for(int j = 0 ; j < k ; j++) {
1981 if (f[j]->deg >= 0)
1982 mpz_set(r[j], f[j]->coeff[0]);
1983 else
1984 mpz_set_ui(r[j], 0);
1985 if (f[j]->deg > maxdeg)
1986 maxdeg = f[j]->deg;
1987 }
1988
1989 mpz_set(w, x);
1990 for(int j = 0 ; j < k ; j++) {
1991 if (f[j]->deg >= 1)
1992 mpz_addmul(r[j], w, f[j]->coeff[1]);
1993 }
1994 for(i = 2 ; i <= maxdeg ; i++) {
1995 mpz_mul (w, w, x);
1996 mpz_mod (w, w, m);
1997 for(int j = 0 ; j < k ; j++)
1998 if (f[j]->deg >= i)
1999 mpz_addmul(r[j], w, f[j]->coeff[i]);
2000 }
2001 for(int j = 0 ; j < k ; j++) {
2002 mpz_mod (r[j], r[j], m);
2003 }
2004 mpz_clear(w);
2005 }
2006
2007 /* Set Q=P1*P2 (mod F). Warning: Q might equal P1 (or P2). */
polymodF_mul(polymodF_t Q,const polymodF_t P1,const polymodF_t P2,mpz_poly_srcptr F)2008 void polymodF_mul (polymodF_t Q,
2009 const polymodF_t P1, const polymodF_t P2,
2010 mpz_poly_srcptr F)
2011 {
2012 mpz_poly_notparallel_info().polymodF_mul (Q, P1, P2, F);
2013 }
2014 template<typename inf>
polymodF_mul(polymodF_t Q,const polymodF_t P1,const polymodF_t P2,mpz_poly_srcptr F)2015 void mpz_poly_parallel_interface<inf>::polymodF_mul (polymodF_t Q,
2016 const polymodF_t P1, const polymodF_t P2,
2017 mpz_poly_srcptr F)
2018 {
2019 mpz_poly prd;
2020 int v;
2021
2022 /* beware: if P1 and P2 are zero, P1->p->deg + P2->p->deg = -2 */
2023 mpz_poly_init (prd, (P1->p->deg == -1) ? -1 : P1->p->deg + P2->p->deg);
2024
2025 ASSERT_ALWAYS(mpz_poly_normalized_p (P1->p));
2026 ASSERT_ALWAYS(mpz_poly_normalized_p (P2->p));
2027
2028 mpz_poly_mul (prd, P1->p, P2->p);
2029 v = P1->v + P2->v;
2030
2031 mpz_poly_reducemodF(Q, prd, F);
2032 Q->v += v;
2033 mpz_poly_clear (prd);
2034 }
2035
2036 /* Set Q = P/lc(P) (mod m). Q and P might be identical. */
2037 /* Coefficients of P need not be reduced mod m
2038 * Coefficients of Q are reduced mod m
2039 */
2040 void
mpz_poly_makemonic_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_srcptr m)2041 mpz_poly_makemonic_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_srcptr m)
2042 {
2043 int i;
2044 mpz_t aux;
2045 mpz_init(aux);
2046 for(i = P->deg; i>=0; i--) {
2047 mpz_mod(aux, P->coeff[i], m);
2048 if (mpz_cmp_ui(aux, 0) != 0) break;
2049 }
2050 /* i is the degree of the leading monomial */
2051 Q->deg = i;
2052 if (i < 0) {
2053 /* if i == -1, then Q is the zero polynomial, there's nothing to do */
2054 mpz_clear(aux);
2055 return;
2056 }
2057
2058 mpz_t aux2;
2059 mpz_init(aux2);
2060 mpz_invert(aux2, aux, m);
2061 for (i = 0; i < Q->deg; ++i) {
2062 mpz_mul(aux, aux2, P->coeff[i]);
2063 mpz_mod(aux, aux, m);
2064 mpz_poly_setcoeff(Q, i, aux);
2065 }
2066 mpz_clear(aux2);
2067
2068 /* we can directly set the leading coefficient to 1 */
2069 mpz_poly_setcoeff_si (Q, Q->deg, 1);
2070 mpz_clear(aux);
2071 }
2072
2073 /* Algorithm 2.5 from "Modern Computer Arithmetic" */
2074 void
barrett_precompute_inverse(mpz_ptr invm,mpz_srcptr m)2075 barrett_precompute_inverse (mpz_ptr invm, mpz_srcptr m)
2076 {
2077 size_t n = mpz_sizeinbase (m, 2);
2078 ASSERT_ALWAYS(mpz_cmp_ui (m, 0) > 0);
2079 /* with B = 2^n, we have B/2 <= m < B */
2080 mpz_set_ui (invm, 0);
2081 mpz_setbit (invm, 2 * n); /* invm = B^2 */
2082 mpz_tdiv_q (invm, invm, m); /* floor(B^2/m) */
2083 }
2084
2085 /* r <- a mod m */
2086 static void
mpz_mod_barrett(mpz_ptr r,mpz_srcptr a,mpz_srcptr m,mpz_srcptr invm)2087 mpz_mod_barrett (mpz_ptr r, mpz_srcptr a, mpz_srcptr m, mpz_srcptr invm)
2088 {
2089 size_t n = mpz_sizeinbase (m, 2);
2090 mpz_srcptr r_or_a = a;
2091
2092 while (mpz_sizeinbase (r_or_a, 2) > n + 1)
2093 {
2094 mpz_t a1;
2095 size_t sr = mpz_sizeinbase (r_or_a, 2);
2096 mpz_init (a1);
2097 /* if sr <= 2n we consider the sr-n most significant bits of r,
2098 otherwise we take the n most significant bits */
2099 mpz_tdiv_q_2exp (a1, r_or_a, (sr <= 2 * n) ? n : sr - n);
2100 mpz_mul (a1, a1, invm);
2101 mpz_tdiv_q_2exp (a1, a1, n);
2102 mpz_mul (a1, a1, m);
2103 /* if sr > 2*n we have to multiply by 2^(sr-2n) */
2104 if (sr >= 2 * n)
2105 mpz_mul_2exp (a1, a1, sr - 2 * n);
2106 mpz_sub (r, r_or_a, a1);
2107 r_or_a = r;
2108 mpz_clear (a1);
2109 }
2110 /* now r_or_a has at most n bits */
2111 while (mpz_cmpabs (r_or_a, m) >= 0)
2112 {
2113 if (mpz_cmp_ui (r_or_a, 0) > 0)
2114 mpz_sub (r, r_or_a, m);
2115 else
2116 mpz_add (r, r_or_a, m);
2117 r_or_a = r;
2118 }
2119 /* now |r_or_a| < m */
2120 if (mpz_cmp_ui (r_or_a, 0) < 0)
2121 {
2122 mpz_add (r, r_or_a, m);
2123 r_or_a = r;
2124 }
2125 /* now 0 <= r_or_a < m */
2126 if (r_or_a == a && r != a)
2127 mpz_set (r, r_or_a);
2128 }
2129
2130 /* Coefficients of A need not be reduced mod m
2131 * Coefficients of R are reduced mod m
2132 * If invm = NULL, use mpz_mod.
2133 * Otherwise use mpz_mod_barrett, where invm should have been precomputed
2134 * using barrett_precompute_inverse (invm, m).
2135 */
mpz_poly_mod_mpz(mpz_poly_ptr R,mpz_poly_srcptr A,mpz_srcptr m,mpz_srcptr invm)2136 int mpz_poly_mod_mpz (mpz_poly_ptr R, mpz_poly_srcptr A, mpz_srcptr m, mpz_srcptr invm)
2137 {
2138 return mpz_poly_notparallel_info().mpz_poly_mod_mpz(R, A, m, invm);
2139 }
2140 template<typename inf>
2141 int
mpz_poly_mod_mpz(mpz_poly_ptr R,mpz_poly_srcptr A,mpz_srcptr m,mpz_srcptr invm)2142 mpz_poly_parallel_interface<inf>::mpz_poly_mod_mpz (mpz_poly_ptr R, mpz_poly_srcptr A, mpz_srcptr m,
2143 mpz_srcptr invm)
2144 {
2145 /* reduce lower coefficients */
2146 mpz_poly_realloc(R, A->deg + 1);
2147 #ifdef HAVE_OPENMP
2148 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2149 #endif
2150 for (int i = 0; i <= A->deg; ++i)
2151 if (invm == NULL)
2152 mpz_mod (R->coeff[i], A->coeff[i], m);
2153 else
2154 mpz_mod_barrett (R->coeff[i], A->coeff[i], m, invm);
2155
2156 mpz_poly_cleandeg(R, A->deg);
2157 return R->deg;
2158 }
2159
2160 /* reduce non-negative coefficients in [0, p-1], negative ones in [1-p, -1] */
2161 int
mpz_poly_mod_mpz_lazy(mpz_poly_ptr R,mpz_poly_srcptr A,mpz_srcptr m)2162 mpz_poly_mod_mpz_lazy (mpz_poly_ptr R, mpz_poly_srcptr A, mpz_srcptr m)
2163 {
2164 mpz_poly_realloc(R, A->deg + 1);
2165 for (int i = 0; i <= A->deg; ++i)
2166 {
2167 if (mpz_sgn (A->coeff[i]) >= 0)
2168 mpz_mod (R->coeff[i], A->coeff[i], m);
2169 else
2170 {
2171 mpz_neg (R->coeff[i], A->coeff[i]);
2172 mpz_mod (R->coeff[i], R->coeff[i], m);
2173 mpz_neg (R->coeff[i], R->coeff[i]);
2174 }
2175 }
2176
2177 mpz_poly_cleandeg(R, A->deg);
2178 return R->deg;
2179 }
2180
2181 /* Reduce R[d]*x^d + ... + R[0] mod f[df]*x^df + ... + f[0] modulo m.
2182 Return the degree of the remainder.
2183 Coefficients of f must be reduced mod m on input.
2184 Coefficients of R need not be reduced mod m on input, but are reduced
2185 on output.
2186 If invf is not NULL, it should be 1/m mod lc(f). */
2187 int
mpz_poly_mod_f_mod_mpz(mpz_poly_ptr R,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf)2188 mpz_poly_mod_f_mod_mpz (mpz_poly_ptr R, mpz_poly_srcptr f, mpz_srcptr m,
2189 mpz_srcptr invf)
2190 {
2191 return mpz_poly_mod_f_mod_mpz (R, f, m, invf, NULL);
2192 }
2193
mpz_poly_mod_f_mod_mpz(mpz_poly_ptr R,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf,mpz_srcptr invm)2194 int mpz_poly_mod_f_mod_mpz(mpz_poly_ptr R, mpz_poly_srcptr f, mpz_srcptr m,
2195 mpz_srcptr invf, mpz_srcptr invm)
2196 {
2197 return mpz_poly_notparallel_info().mpz_poly_mod_f_mod_mpz(R, f, m, invf, invm);
2198 }
2199 template<typename inf>
2200 int
mpz_poly_mod_f_mod_mpz(mpz_poly_ptr R,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf,mpz_srcptr invm)2201 mpz_poly_parallel_interface<inf>::mpz_poly_mod_f_mod_mpz (mpz_poly_ptr R, mpz_poly_srcptr f, mpz_srcptr m,
2202 mpz_srcptr invf, mpz_srcptr invm)
2203 {
2204 mpz_t aux, c;
2205 size_t size_f, size_R;
2206
2207 if (f == NULL)
2208 goto reduce_R;
2209
2210 if (invf == NULL)
2211 {
2212 mpz_init (aux);
2213 /* aux = 1/m mod lc(f) */
2214 mpz_invert (aux, m, f->coeff[f->deg]);
2215 }
2216
2217 size_f = mpz_poly_size (f);
2218 size_R = mpz_poly_size (R);
2219
2220 mpz_init (c);
2221 // FIXME: write a subquadratic variant
2222 while (R->deg >= f->deg)
2223 {
2224 /* Here m is large (thousand to million bits) and lc(f) is small
2225 * (typically one word). We first subtract lambda * m * x^(dR-df) ---
2226 * which is zero mod m --- to R such that the new coefficient of degree
2227 * dR is divisible by lc(f), i.e., lambda = lc(R)/m mod lc(f). Then if
2228 * c = (lc(R) - lambda * m) / lc(f), we subtract c * x^(dR-df) * f. */
2229 mpz_mod (c, R->coeff[R->deg], f->coeff[f->deg]); /* lc(R) mod lc(f) */
2230 mpz_mul (c, c, (invf == NULL) ? aux : invf);
2231 mpz_mod (c, c, f->coeff[f->deg]); /* lc(R)/m mod lc(f) */
2232 mpz_submul (R->coeff[R->deg], m, c); /* lc(R) - m * (lc(R) / m mod lc(f)) */
2233 ASSERT (mpz_divisible_p (R->coeff[R->deg], f->coeff[f->deg]));
2234 mpz_divexact (c, R->coeff[R->deg], f->coeff[f->deg]);
2235 /* If R[deg] has initially size 2n, and f[deg] = O(1), then c has size
2236 2n here. However, in the equal-degree factorization, even if f[deg]
2237 = O(1), the lower coefficients of f might have n bits. Thus we decide
2238 to reduce whenever the total size exceeds 2n. */
2239 /* FIXME: commit a85444984 changed the line below but not the
2240 * comment above. */
2241 size_t size_c = mpz_size (c);
2242 if (size_c + size_f > (3 * size_R) / 2)
2243 mpz_mod (c, c, m);
2244 #ifdef HAVE_OPENMP
2245 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2246 #endif
2247 for (int i = R->deg - 1; i >= R->deg - f->deg; --i)
2248 mpz_submul (R->coeff[i], c, f->coeff[f->deg - R->deg + i]);
2249 R->deg--;
2250 }
2251
2252 mpz_clear (c);
2253 if (invf == NULL)
2254 mpz_clear (aux);
2255
2256 reduce_R:
2257 mpz_poly_mod_mpz (R, R, m, invm);
2258
2259 return R->deg;
2260 }
2261
2262 /* Stores in g the polynomial linked to f by:
2263 * - alpha is a root of f if and only if lc(f)*alpha is a root of g
2264 * - g is monic
2265 */
mpz_poly_to_monic(mpz_poly_ptr g,mpz_poly_srcptr f)2266 void mpz_poly_to_monic(mpz_poly_ptr g, mpz_poly_srcptr f)
2267 {
2268 mpz_t fd,temp;
2269 mpz_init(fd);
2270 mpz_init(temp);
2271 mpz_poly_getcoeff(fd,f->deg,f);
2272
2273 mpz_poly_set(g,f);
2274 for (int k = 0 ; k < g->deg ; k++) {
2275 mpz_poly_getcoeff(temp,k,g);
2276 for(int j = 1 ; j <= g->deg-1-k ; j++){
2277 mpz_mul(temp,temp,fd);
2278 }
2279 mpz_poly_setcoeff(g,k,temp);
2280 }
2281 mpz_poly_setcoeff_ui(g,g->deg,1);
2282
2283 mpz_clear(temp);
2284 mpz_clear(fd);
2285 }
2286
2287 /* Reduce frac (= num / denom) mod F mod m ,
2288 i.e. compute num * denom^-1 mod F mod m .
2289 The return value is in num, denom is set to constant polynomial 1
2290 */
2291 /* TODO: We must state the input / output requirements with respect to
2292 * reduction mod m */
2293 void
mpz_poly_reduce_frac_mod_f_mod_mpz(mpz_poly_ptr num,mpz_poly_ptr denom,mpz_poly_srcptr F,mpz_srcptr m)2294 mpz_poly_reduce_frac_mod_f_mod_mpz (
2295 mpz_poly_ptr num, mpz_poly_ptr denom,
2296 mpz_poly_srcptr F, mpz_srcptr m)
2297 {
2298 mpz_poly_notparallel_info().mpz_poly_reduce_frac_mod_f_mod_mpz (
2299 num, denom,
2300 F, m);
2301 }
2302 template<typename inf>
2303 void
mpz_poly_reduce_frac_mod_f_mod_mpz(mpz_poly_ptr num,mpz_poly_ptr denom,mpz_poly_srcptr F,mpz_srcptr m)2304 mpz_poly_parallel_interface<inf>::mpz_poly_reduce_frac_mod_f_mod_mpz (
2305 mpz_poly_ptr num, mpz_poly_ptr denom,
2306 mpz_poly_srcptr F, mpz_srcptr m)
2307 {
2308 if (denom->deg == 0)
2309 {
2310 mpz_t inv;
2311 mpz_init (inv);
2312 mpz_poly_getcoeff (inv, 0, denom); /* inv <- denom[0] */
2313 mpz_invert (inv, inv, m); /* inv <- denom[0]^-1 */
2314 mpz_poly_mul_mpz(num, num, inv); /* num <- num * inv */
2315 mpz_poly_mod_mpz(num, num, m, NULL); /* num <- num * inv mod m */
2316 mpz_clear (inv);
2317 } else {
2318 mpz_poly g, U, V;
2319 mpz_poly_init (g, 0);
2320 mpz_poly_init (U, 0);
2321 mpz_poly_init (V, 0);
2322 mpz_poly_xgcd_mpz (g, F, denom, U, V, m);
2323 mpz_poly_mul (num, num, V);
2324 mpz_poly_mod_f_mod_mpz (num, F, m, NULL, NULL);
2325 mpz_poly_clear (g);
2326 mpz_poly_clear (U);
2327 mpz_poly_clear (V);
2328 }
2329 mpz_poly_set_zero (denom);
2330 mpz_poly_setcoeff_si (denom, 0, 1);
2331 }
2332
2333
2334 /* Q = P1*P2 mod f, mod m
2335 f is the original algebraic polynomial (non monic but small coefficients)
2336 Coefficients of P1 and P2 need not be reduced mod m.
2337 Coefficients of Q are reduced mod m.
2338 If invf is not NULL, it is 1/m mod lc(f). */
2339 void
mpz_poly_mul_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P1,mpz_poly_srcptr P2,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf,mpz_srcptr invm)2340 mpz_poly_mul_mod_f_mod_mpz(mpz_poly_ptr Q, mpz_poly_srcptr P1, mpz_poly_srcptr P2,
2341 mpz_poly_srcptr f, mpz_srcptr m, mpz_srcptr invf,
2342 mpz_srcptr invm)
2343 {
2344 mpz_poly_notparallel_info().mpz_poly_mul_mod_f_mod_mpz(Q, P1, P2, f, m, invf, invm);
2345 }
2346 template<typename inf>
2347 void
mpz_poly_mul_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P1,mpz_poly_srcptr P2,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf,mpz_srcptr invm)2348 mpz_poly_parallel_interface<inf>::mpz_poly_mul_mod_f_mod_mpz(mpz_poly_ptr Q, mpz_poly_srcptr P1, mpz_poly_srcptr P2,
2349 mpz_poly_srcptr f, mpz_srcptr m, mpz_srcptr invf,
2350 mpz_srcptr invm)
2351 {
2352 int d1 = P1->deg;
2353 int d2 = P2->deg;
2354 int d = d1+d2;
2355 mpz_poly R;
2356
2357 mpz_poly_init(R, d);
2358 #ifdef MPZ_POLY_TIMINGS
2359 if (mpz_fits_sint_p (f->coeff[0])){
2360 START_TIMER;
2361 d = mpz_poly_mul_tc ((inf&)*this, R->coeff, P1->coeff, d1, P2->coeff, d2);
2362 mpz_poly_cleandeg(R, d);
2363 END_TIMER (TIMER_MUL);
2364 // reduce mod f
2365 RESTART_TIMER;
2366 mpz_poly_mod_f_mod_mpz (R, f, m, invf, invm);
2367 END_TIMER (TIMER_RED);
2368 }else
2369 #endif
2370 {
2371 d = mpz_poly_mul_tc ((inf&)*this, R->coeff, P1->coeff, d1, P2->coeff, d2);
2372 mpz_poly_cleandeg(R, d);
2373 // reduce mod f
2374 mpz_poly_mod_f_mod_mpz (R, f, m, invf, invm);
2375 }
2376 mpz_poly_set(Q, R);
2377 mpz_poly_clear(R);
2378 }
2379
2380 /* Q = P1*P2 mod f, assuming f is monic */
2381 void
mpz_poly_mul_mod_f(mpz_poly_ptr Q,mpz_poly_srcptr P1,mpz_poly_srcptr P2,mpz_poly_srcptr f)2382 mpz_poly_mul_mod_f (mpz_poly_ptr Q, mpz_poly_srcptr P1, mpz_poly_srcptr P2,
2383 mpz_poly_srcptr f)
2384 {
2385 mpz_poly_notparallel_info().mpz_poly_mul_mod_f (Q, P1, P2, f);
2386 }
2387 template<typename inf>
2388 void
mpz_poly_mul_mod_f(mpz_poly_ptr Q,mpz_poly_srcptr P1,mpz_poly_srcptr P2,mpz_poly_srcptr f)2389 mpz_poly_parallel_interface<inf>::mpz_poly_mul_mod_f (mpz_poly_ptr Q, mpz_poly_srcptr P1, mpz_poly_srcptr P2,
2390 mpz_poly_srcptr f)
2391 {
2392 mpz_poly_mul(Q,P1,P2);
2393 mpz_poly_div_r_z(Q,Q,f);
2394 }
2395
2396 /* Q = P^2 mod f, mod m
2397 f is the original algebraic polynomial (non monic but small coefficients)
2398 Coefficients of P need not be reduced mod m.
2399 Coefficients of Q are reduced mod m.
2400 If not NULL, invf = 1/m mod lc(f). */
mpz_poly_sqr_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf,mpz_srcptr invm)2401 void mpz_poly_sqr_mod_f_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_poly_srcptr f, mpz_srcptr m, mpz_srcptr invf, mpz_srcptr invm)
2402 {
2403 mpz_poly_notparallel_info().mpz_poly_sqr_mod_f_mod_mpz (Q, P, f, m, invf, invm);
2404 }
2405 template<typename inf>
mpz_poly_sqr_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,mpz_srcptr m,mpz_srcptr invf,mpz_srcptr invm)2406 void mpz_poly_parallel_interface<inf>::mpz_poly_sqr_mod_f_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_poly_srcptr f, mpz_srcptr m, mpz_srcptr invf, mpz_srcptr invm)
2407 {
2408 int d1 = P->deg;
2409 int d = d1 + d1;
2410 mpz_poly R;
2411
2412 mpz_poly_init(R, d);
2413
2414 /* Fast squaring in 2d1+1 squares, i.e., 2d-1 squares.
2415 For d=5, this gives 9 squares. */
2416 // compute timing only if f has short coefficients
2417 #ifdef MPZ_POLY_TIMINGS
2418 if (mpz_fits_sint_p (f->coeff[0])){
2419 START_TIMER;
2420 d = mpz_poly_sqr_tc ((inf&)*this, R->coeff, P->coeff, d1);
2421 mpz_poly_cleandeg(R, d);
2422 END_TIMER (TIMER_SQR);
2423 // reduce mod f
2424 RESTART_TIMER;
2425 mpz_poly_mod_f_mod_mpz (R, f, m, invf, invm);
2426 END_TIMER (TIMER_RED);
2427 }else
2428 #endif
2429 {
2430 d = mpz_poly_sqr_tc ((inf&)*this, R->coeff, P->coeff, d1);
2431 mpz_poly_cleandeg(R, d);
2432 // reduce mod f
2433 mpz_poly_mod_f_mod_mpz (R, f, m, invf, invm);
2434 }
2435
2436 mpz_poly_set(Q, R);
2437 mpz_poly_clear(R);
2438 }
2439
2440 /* Affects the derivative of f to df. Assumes df different from f.
2441 Assumes df has been initialized with degree at least f->deg-1. */
mpz_poly_derivative(mpz_poly_ptr df,mpz_poly_srcptr f)2442 void mpz_poly_derivative(mpz_poly_ptr df, mpz_poly_srcptr f) {
2443 int n;
2444
2445 df->deg = (f->deg <= 0) ? -1 : f->deg - 1;
2446 for (n = 0; n <= f->deg - 1; n++)
2447 mpz_mul_si (df->coeff[n], f->coeff[n + 1], n + 1);
2448 }
2449
2450 /* B = A^n */
mpz_poly_pow_ui(mpz_poly_ptr B,mpz_poly_srcptr A,unsigned long n)2451 void mpz_poly_pow_ui(mpz_poly_ptr B, mpz_poly_srcptr A, unsigned long n)/*{{{*/
2452 {
2453 if (n == 0) {
2454 mpz_poly_set_xi(B, 0);
2455 return;
2456 }
2457 if (A->deg < 0) {
2458 mpz_poly_set_zero(B);
2459 return;
2460 }
2461 if (B == A) {
2462 mpz_poly C;
2463 mpz_poly_init(C, n * A->deg);
2464 mpz_poly_pow_ui(C, A, n);
2465 mpz_poly_swap(B, C);
2466 mpz_poly_clear(C);
2467 return;
2468 }
2469 unsigned long k = ((~0UL)>>1) + 1;
2470 for( ; k > n ; k >>= 1);
2471 mpz_poly_set(B, A);
2472 for( ; k >>= 1 ; ) {
2473 mpz_poly_mul(B, B, B);
2474 if (n & k)
2475 mpz_poly_mul(B, B, A);
2476 }
2477 }/*}}}*/
2478
2479 /* B = A^n mod f, assuming f is monic */
mpz_poly_pow_ui_mod_f(mpz_poly_ptr B,mpz_poly_srcptr A,unsigned long n,mpz_poly_srcptr f)2480 void mpz_poly_pow_ui_mod_f(mpz_poly_ptr B, mpz_poly_srcptr A, unsigned long n, mpz_poly_srcptr f)/*{{{*/
2481 {
2482 if (n == 0) {
2483 mpz_poly_set_xi(B, 0);
2484 return;
2485 }
2486 if (A->deg < 0) {
2487 mpz_poly_set_zero(B);
2488 return;
2489 }
2490 if (B == A || B == f) {
2491 mpz_poly C;
2492 mpz_poly_init(C, f->deg-1);
2493 mpz_poly_pow_ui_mod_f(C, A, n, f);
2494 mpz_poly_swap(B, C);
2495 mpz_poly_clear(C);
2496 return;
2497 }
2498 unsigned long k = ((~0UL)>>1) + 1;
2499 for( ; k > n ; k >>= 1);
2500 mpz_poly_realloc(B, n * A->deg + 1);
2501 mpz_poly_set(B, A);
2502 mpz_poly Q;
2503 mpz_poly_init(Q, 3*f->deg-3);
2504 for( ; k >>= 1 ; ) {
2505 mpz_poly_mul(Q, B, B);
2506 mpz_poly_swap(Q, B);
2507 if (n & k) {
2508 mpz_poly_mul(Q, B, A);
2509 mpz_poly_swap(Q, B);
2510 }
2511 mpz_poly_div_r_z(B, B, f);
2512 }
2513 mpz_poly_clear(Q);
2514 }/*}}}*/
2515
2516 /* Q = P^a mod f, mod p (f is the algebraic polynomial, non monic) */
2517 /* Coefficients of f must be reduced mod m on input
2518 * Coefficients of P need not be reduced mod p.
2519 * Coefficients of Q are reduced mod p.
2520 */
mpz_poly_pow_mod_f_mod_ui(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,mpz_srcptr a,unsigned long p)2521 void mpz_poly_pow_mod_f_mod_ui (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_poly_srcptr f, mpz_srcptr a, unsigned long p)
2522 {
2523 mpz_poly_notparallel_info().mpz_poly_pow_mod_f_mod_ui (Q, P, f, a, p);
2524 }
2525 template<typename inf>
mpz_poly_pow_mod_f_mod_ui(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,mpz_srcptr a,unsigned long p)2526 void mpz_poly_parallel_interface<inf>::mpz_poly_pow_mod_f_mod_ui (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_poly_srcptr f, mpz_srcptr a, unsigned long p)
2527 {
2528 mpz_t m;
2529 mpz_init_set_ui(m, p);
2530 mpz_poly_pow_mod_f_mod_mpz(Q, P, f, a, m);
2531 mpz_clear(m);
2532 }
2533
2534 /* Coefficients of f must be reduced mod m on input
2535 * Coefficients of P need not be reduced mod p.
2536 * Coefficients of Q are reduced mod p.
2537 */
2538 void
mpz_poly_pow_ui_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,unsigned long a,mpz_srcptr p)2539 mpz_poly_pow_ui_mod_f_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_poly_srcptr f,
2540 unsigned long a, mpz_srcptr p)
2541 {
2542 mpz_poly_notparallel_info().mpz_poly_pow_ui_mod_f_mod_mpz(Q, P, f, a, p);
2543 }
2544 template<typename inf>
2545 void
mpz_poly_pow_ui_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,unsigned long a,mpz_srcptr p)2546 mpz_poly_parallel_interface<inf>::mpz_poly_pow_ui_mod_f_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P, mpz_poly_srcptr f,
2547 unsigned long a, mpz_srcptr p)
2548 {
2549 mpz_t az;
2550 mpz_init_set_ui(az, a);
2551 mpz_poly_pow_mod_f_mod_mpz(Q, P, f, az, p);
2552 mpz_clear(az);
2553 }
2554
2555 /* Q = P^a mod f, mod p. Note, p is mpz_t */
2556 /* f may be NULL, in case there is only reduction mod p */
2557 /* Coefficients of f must be reduced mod p on input
2558 * Coefficients of P need not be reduced mod p.
2559 * Coefficients of Q are reduced mod p
2560 */
2561 void
mpz_poly_pow_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,mpz_srcptr a,mpz_srcptr p)2562 mpz_poly_pow_mod_f_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P,
2563 mpz_poly_srcptr f, mpz_srcptr a, mpz_srcptr p)
2564 {
2565 mpz_poly_notparallel_info().mpz_poly_pow_mod_f_mod_mpz(Q, P, f, a, p);
2566 }
2567 template<typename inf>
2568 void
mpz_poly_pow_mod_f_mod_mpz(mpz_poly_ptr Q,mpz_poly_srcptr P,mpz_poly_srcptr f,mpz_srcptr a,mpz_srcptr p)2569 mpz_poly_parallel_interface<inf>::mpz_poly_pow_mod_f_mod_mpz (mpz_poly_ptr Q, mpz_poly_srcptr P,
2570 mpz_poly_srcptr f, mpz_srcptr a, mpz_srcptr p)
2571 {
2572 int k = mpz_sizeinbase(a, 2), l, L = 0, j;
2573 mpz_poly R, *T = NULL;
2574 mpz_t invf;
2575
2576 if (mpz_cmp_ui(a, 0) == 0) {
2577 mpz_poly_set_xi (Q, 0);
2578 return;
2579 }
2580
2581 mpz_poly_init(R, f ? 2*f->deg : -1);
2582
2583 // Initialize R to P
2584 mpz_poly_set(R, P);
2585
2586 /* compute invf = 1/p mod lc(f) */
2587 if (f != NULL)
2588 {
2589 mpz_init (invf);
2590 mpz_invert (invf, p, f->coeff[f->deg]);
2591 }
2592
2593 /* We use base-2^l exponentiation with sliding window,
2594 thus we need to precompute P^2, P^3, ..., P^(2^l-1).
2595 The expected average cost k squarings plus k/(l+1) + 2^(l-1) multiplies.
2596 */
2597
2598 for (l = 1; k / (l + 1) + (1 << (l - 1)) > k / (l + 2) + (1 << l); l++);
2599 /* this gives (roughly) l=1 for k < 8, l=2 for k < 27, l=3 for k < 84,
2600 l=4 for k < 245 */
2601 if (l > 1)
2602 {
2603 L = 1 << (l - 1);
2604 T = (mpz_poly*) malloc (L * sizeof (mpz_poly));
2605 /* we store P^2 in T[0], P^3 in T[1], ..., P^(2^l-1) in T[L-1] */
2606 for (j = 0; j < L; j++)
2607 mpz_poly_init (T[j], f ? 2*f->deg : -1);
2608 mpz_poly_sqr_mod_f_mod_mpz (T[0], R, f, p, invf, NULL); /* P^2 */
2609 mpz_poly_mul_mod_f_mod_mpz (T[1], T[0], R, f, p, invf, NULL); /* P^3 */
2610 for (j = 2; j < L; j++)
2611 mpz_poly_mul_mod_f_mod_mpz (T[j], T[j-1], T[0], f, p, invf, NULL);
2612 }
2613
2614 // Horner
2615 for (k -= 2; k >= 0;)
2616 {
2617 while (k >= 0 && mpz_tstbit (a, k) == 0)
2618 {
2619 mpz_poly_sqr_mod_f_mod_mpz (R, R, f, p, invf, NULL);
2620 k --;
2621 }
2622 if (k < 0)
2623 break;
2624 j = mpz_scan1 (a, (k >= l) ? k - (l - 1) : 0);
2625 /* if l is 1 then j==k*/
2626 ASSERT_ALWAYS(l > 1 || j == k);
2627 /* new window starts at bit k, and ends at bit j <= k */
2628 int e = 0;
2629 while (k >= j)
2630 {
2631 mpz_poly_sqr_mod_f_mod_mpz (R, R, f, p, invf, NULL);
2632 e = 2 * e + mpz_tstbit (a, k);
2633 k --;
2634 }
2635 /* if l is 1 then e == 1 */
2636 ASSERT_ALWAYS(l > 1 || e == 1);
2637 mpz_poly_mul_mod_f_mod_mpz (R, R, (e == 1) ? P : T[e/2], f, p, invf, NULL);
2638 }
2639
2640 mpz_poly_swap(Q, R);
2641 mpz_poly_clear(R);
2642 if (f != NULL)
2643 mpz_clear (invf);
2644 if (l > 1)
2645 {
2646 for (k = 0; k < L; k++)
2647 mpz_poly_clear (T[k]);
2648 free (T);
2649 }
2650 }
2651
2652 /* Return a list of polynomials P[0], P[1], ..., P[l] such that
2653 P0 = Q[l-1] + p^K[1]*P[l]
2654 Q[l-1] = Q[l-2] + p^K[2]*P[l-1]
2655 ...
2656 Q[2] = Q[1] + p^K[l-1]*P[2]
2657 Q[1] = Q[0] + p*P[1] where K[l] = 1
2658 Q[0] = P[0]
2659 ...
2660 With all coefficients of P[i] smaller than p^(K[l-i]-K[l-(i-1)]).
2661 Assume K[l]=1, K[l-1]=2, ..., K[i] = 2*K[i+1] or 2*K[i+1]-1.
2662 P0 = P[0] + p*P[1] + p^2*P[2] + ... + p^K[1]*P[l] < p^K[0]
2663 The end of the list is P[l+1]=0.
2664 Assume l > 0.
2665 */
mpz_poly_base_modp_init(mpz_poly_srcptr P0,int p,unsigned long * K,int l)2666 mpz_poly* mpz_poly_base_modp_init (mpz_poly_srcptr P0, int p, unsigned long *K, int l)
2667 {
2668 return mpz_poly_notparallel_info().mpz_poly_base_modp_init (P0, p, K, l);
2669 }
2670 template<typename inf>
2671 mpz_poly*
mpz_poly_base_modp_init(mpz_poly_srcptr P0,int p,unsigned long * K,int l)2672 mpz_poly_parallel_interface<inf>::mpz_poly_base_modp_init (mpz_poly_srcptr P0, int p, unsigned long *K, int l)
2673 {
2674 mpz_poly *P;
2675 int k, i, j;
2676 mpz_t *pk;
2677
2678 ASSERT_ALWAYS (l > 0);
2679 ASSERT_ALWAYS (K[l] == 1);
2680
2681 /* initialize pk[i] = p^K[l-i] for 0 <= i < l */
2682 pk = (mpz_t*) malloc (l * sizeof (mpz_t));
2683 FATAL_ERROR_CHECK (pk == NULL, "not enough memory");
2684 mpz_init_set_ui (pk[0], p);
2685 /* this loop cannot be parallelized, since pk[i] depends on pk[i-1] */
2686 for (i = 1; i < l; i++)
2687 {
2688 mpz_init (pk[i]);
2689 mpz_mul (pk[i], pk[i-1], pk[i-1]);
2690 if (K[l-i] & 1)
2691 {
2692 ASSERT_ALWAYS (K[l-i] == 2 * K[l-i+1] - 1);
2693 mpz_div_ui (pk[i], pk[i], p);
2694 }
2695 else
2696 ASSERT_ALWAYS (K[l-i] == 2 * K[l-i+1]);
2697 }
2698
2699 /* now decompose P0: we need P[0], P[1] for factor p, P[2] for p^2,
2700 ..., P[l] for p^K[1], and one for the end of list,
2701 thus l+2 polynomials */
2702 P = (mpz_poly*) malloc ((l + 2) * sizeof(mpz_poly));
2703 FATAL_ERROR_CHECK (P == NULL, "not enough memory");
2704 #ifdef HAVE_OPENMP
2705 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2706 #endif
2707 for (i = 0; i < l + 2; i++)
2708 mpz_poly_init (P[i], P0->deg);
2709 /* P[l+1] is initialized to 0 by mpz_poly_init */
2710
2711 /* initialize P[k], and put remainder in P[k-1] */
2712 k = l;
2713 #ifdef HAVE_OPENMP
2714 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2715 #endif
2716 for (i = 0; i <= P0->deg; i++)
2717 mpz_tdiv_qr (P[k]->coeff[i], P[k-1]->coeff[i], P0->coeff[i], pk[k-1]);
2718 mpz_poly_cleandeg (P[k], P0->deg);
2719
2720 /* now go down */
2721 for (j = l-1; j >= 1; j--)
2722 {
2723 /* reduce P[j] into P[j] and P[j-1] */
2724 #ifdef HAVE_OPENMP
2725 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2726 #endif
2727 for (i = 0; i <= P0->deg; i++)
2728 mpz_tdiv_qr (P[j]->coeff[i], P[j-1]->coeff[i], P[j]->coeff[i],
2729 pk[j-1]);
2730 mpz_poly_cleandeg (P[j], P0->deg);
2731 }
2732 mpz_poly_cleandeg (P[0], P0->deg);
2733
2734 #ifdef HAVE_OPENMP
2735 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2736 #endif
2737 for (i = 0; i < l; i++)
2738 mpz_clear (pk[i]);
2739 free (pk);
2740
2741 return P;
2742 }
2743
2744 /* a <- a + pk*P[k] */
mpz_poly_base_modp_lift(mpz_poly_ptr a,mpz_poly * P,int k,mpz_srcptr pk)2745 void mpz_poly_base_modp_lift (mpz_poly_ptr a, mpz_poly *P, int k, mpz_srcptr pk)
2746 {
2747 mpz_poly_notparallel_info().mpz_poly_base_modp_lift (a, P, k, pk);
2748 }
2749 template<typename inf>
mpz_poly_base_modp_lift(mpz_poly_ptr a,mpz_poly * P,int k,mpz_srcptr pk)2750 void mpz_poly_parallel_interface<inf>::mpz_poly_base_modp_lift (mpz_poly_ptr a, mpz_poly *P, int k, mpz_srcptr pk)
2751 {
2752 /* first check P[k] exists and is not zero */
2753 if (P[k]->deg == -1)
2754 return;
2755
2756 mpz_poly_realloc (a, P[k]->deg + 1);
2757
2758 int imax = (P[k]->deg < a->deg) ? P[k]->deg : a->deg;
2759 #ifdef HAVE_OPENMP
2760 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2761 #endif
2762 for (int i = 0; i <= imax; i++)
2763 mpz_addmul (a->coeff[i], P[k]->coeff[i], pk);
2764
2765 #ifdef HAVE_OPENMP
2766 #pragma omp parallel for if (!std::is_same<inf, mpz_poly_notparallel_info>::value)
2767 #endif
2768 for (int i = imax + 1; i <= P[k]->deg; i++)
2769 mpz_mul (a->coeff[i], P[k]->coeff[i], pk);
2770
2771 mpz_poly_cleandeg (a, (a->deg >= P[k]->deg) ? a->deg : P[k]->deg);
2772 }
2773
2774 void
mpz_poly_base_modp_clear(mpz_poly * P,int l)2775 mpz_poly_base_modp_clear (mpz_poly *P, int l)
2776 {
2777 for (int i = 0; i < l + 2; i++)
2778 mpz_poly_clear (P[i]);
2779 free (P);
2780 }
2781
2782 /* return the maximal size of the coefficients of f in base b */
2783 size_t
mpz_poly_sizeinbase(mpz_poly_srcptr f,int b)2784 mpz_poly_sizeinbase (mpz_poly_srcptr f, int b)
2785 {
2786 size_t S = 0, s;
2787 int i;
2788 int d = f->deg;
2789
2790 for (i = 0; i <= d; i++)
2791 {
2792 s = mpz_sizeinbase (f->coeff[i], b);
2793 if (s > S)
2794 S = s;
2795 }
2796 return S;
2797 }
2798
2799 /* return the maximal limb-size of the coefficients of f */
2800 size_t
mpz_poly_size(mpz_poly_srcptr f)2801 mpz_poly_size (mpz_poly_srcptr f)
2802 {
2803 size_t S = 0, s;
2804 int i;
2805 int d = f->deg;
2806
2807 for (i = 0; i <= d; i++)
2808 {
2809 s = mpz_size (f->coeff[i]);
2810 if (s > S)
2811 S = s;
2812 }
2813 return S;
2814 }
2815
2816 void
mpz_poly_infinity_norm(mpz_ptr in,mpz_poly_srcptr f)2817 mpz_poly_infinity_norm (mpz_ptr in, mpz_poly_srcptr f)
2818 {
2819 if (f->deg == -1) {
2820 mpz_set_ui(in, 0);
2821 } else {
2822 mpz_abs (in, f->coeff[0]);
2823 for (int i = 1; i <= f->deg; i++)
2824 {
2825 if (mpz_cmpabs (f->coeff[i], in) > 0)
2826 mpz_abs (in, f->coeff[i]);
2827 }
2828 }
2829 }
2830
2831 /* return the total size (in bytes) to store the polynomial f */
2832 size_t
mpz_poly_totalsize(mpz_poly_srcptr f)2833 mpz_poly_totalsize (mpz_poly_srcptr f)
2834 {
2835 int i;
2836 size_t s = 0;
2837
2838 for (i = 0; i <= f->deg; i++)
2839 s += mpz_size (f->coeff[i]);
2840 return s * sizeof (mp_limb_t);
2841 }
2842
2843 /* f=gcd(f, g) mod p, with p in mpz_t */
2844 /* clobbers g */
2845 /* Coefficients of f and g need not be reduced mod p on input.
2846 * Coefficients of f are reduced mod p on output */
2847 static void
mpz_poly_gcd_mpz_clobber(mpz_poly_ptr f,mpz_poly_ptr g,mpz_srcptr p)2848 mpz_poly_gcd_mpz_clobber (mpz_poly_ptr f, mpz_poly_ptr g, mpz_srcptr p)
2849 {
2850 /* First reduce mod p */
2851 mpz_poly_mod_mpz(f, f, p, NULL);
2852 mpz_poly_mod_mpz(g, g, p, NULL);
2853 while (g->deg >= 0)
2854 {
2855 mpz_poly_div_r (f, g, p);
2856 /* now deg(f) < deg(g): swap f and g */
2857 mpz_poly_swap (f, g);
2858 }
2859 }
2860
2861 /* f <- gcd(a, b) mod p. */
2862 /* Coefficients of a and b need not be reduced mod p
2863 * Coefficients of f are reduced mod p */
2864 void
mpz_poly_gcd_mpz(mpz_poly_ptr f,mpz_poly_srcptr a,mpz_poly_srcptr b,mpz_srcptr p)2865 mpz_poly_gcd_mpz (mpz_poly_ptr f, mpz_poly_srcptr a, mpz_poly_srcptr b,
2866 mpz_srcptr p)
2867 {
2868 mpz_poly hh;
2869 if (f == b) {
2870 mpz_poly_init(hh, a->deg);
2871 mpz_poly_set(hh, a);
2872 } else {
2873 mpz_poly_init(hh, b->deg);
2874 mpz_poly_set(hh, b);
2875 mpz_poly_set(f, a); /* will do nothing if f = a */
2876 }
2877 mpz_poly_gcd_mpz_clobber(f, hh, p);
2878 mpz_poly_clear(hh);
2879 }
2880
2881
2882 /* Attempt to compute the f=gcd(f, g) mod N, where N is not necessarily a
2883 * prime. If at some point a division fails, this gives a proper factor
2884 * of N that is put in the corresponding argument.
2885 * The return value tells whether the process was successful (1 means
2886 * that no inversion failed, 0 means that a factor was found).
2887 *
2888 * If a factor is found, and if the parameter "factor" is not NULL, then
2889 * the encountered factored is stored there.
2890 *
2891 * WARNING: this function destroys its input.
2892 */
2893 /* Coefficients of f and g need not be reduced mod p on input.
2894 * Coefficients of f are reduced mod p on output */
2895 int
mpz_poly_pseudogcd_mpz(mpz_poly_ptr f,mpz_poly_ptr g,mpz_srcptr N,mpz_ptr factor)2896 mpz_poly_pseudogcd_mpz(mpz_poly_ptr f, mpz_poly_ptr g, mpz_srcptr N, mpz_ptr factor)
2897 {
2898 mpz_poly_mod_mpz(f, f, N, NULL);
2899 mpz_poly_mod_mpz(g, g, N, NULL);
2900 while (g->deg >= 0)
2901 {
2902 int ret = mpz_poly_pseudodiv_r(f, g, N, factor);
2903 if (!ret)
2904 return ret;
2905 /* now deg(f) < deg(g): swap f and g */
2906 mpz_poly_swap (f, g);
2907 }
2908 // success: all inversions mod N worked.
2909 return 1;
2910 }
2911
2912
2913 /* computes d = gcd(f, g) = u*f + v*g mod p, with p in mpz_t */
2914 /* Coefficients of f and g need not be reduced mod p.
2915 * Coefficients of d, u, v are reduced mod p */
2916 void
mpz_poly_xgcd_mpz(mpz_poly_ptr d,mpz_poly_srcptr f,mpz_poly_srcptr g,mpz_poly_ptr u,mpz_poly_ptr v,mpz_srcptr p)2917 mpz_poly_xgcd_mpz (mpz_poly_ptr d, mpz_poly_srcptr f, mpz_poly_srcptr g, mpz_poly_ptr u, mpz_poly_ptr v, mpz_srcptr p)
2918 {
2919 mpz_poly q, tmp;
2920 mpz_poly gg;
2921
2922 if (f->deg < g->deg) {
2923 mpz_poly_xgcd_mpz(d, g, f, v, u, p);
2924 return;
2925 }
2926 mpz_poly_init(gg, g->alloc);
2927 mpz_poly_set(d, f);
2928 mpz_poly_set(gg, g);
2929 mpz_poly_mod_mpz(d, d, p, NULL);
2930 mpz_poly_mod_mpz(gg, gg, p, NULL);
2931
2932 mpz_poly uu, vv;
2933 mpz_poly_init (uu, 0);
2934 mpz_poly_init (vv, 0);
2935
2936 mpz_poly_set_xi(u, 0);
2937 mpz_poly_set_zero(uu);
2938
2939 mpz_poly_set_xi(vv, 0);
2940 mpz_poly_set_zero(v);
2941
2942 mpz_poly_init(q, d->deg);
2943 mpz_poly_init(tmp, d->deg + gg->deg);
2944
2945 while (gg->deg >= 0)
2946 {
2947
2948 /* q, r := f div g mod p */
2949 mpz_poly_div_qr (q, d, d, gg, p);
2950
2951 /* u := u - q * uu mod p */
2952 mpz_poly_mul(tmp, q, uu);
2953 mpz_poly_sub_mod_mpz(u, u, tmp, p);
2954 mpz_poly_swap (u, uu);
2955
2956 /* v := v - q * vv mod p */
2957 mpz_poly_mul(tmp, q, vv);
2958 mpz_poly_sub_mod_mpz(v, v, tmp, p);
2959 mpz_poly_swap (v, vv);
2960
2961 /* now deg(f) < deg(g): swap f and g */
2962 mpz_poly_swap (d, gg);
2963 }
2964
2965 /* make monic */
2966 mpz_t inv;
2967 if (mpz_cmp_ui(d->coeff[d->deg], 1) != 0)
2968 {
2969 mpz_init(inv);
2970 mpz_invert(inv, d->coeff[0], p);
2971 mpz_poly_mul_mpz(d, d, inv);
2972 mpz_poly_mod_mpz(d, d, p, NULL);
2973 mpz_poly_mul_mpz(u, u, inv);
2974 mpz_poly_mod_mpz(u, u, p, NULL);
2975 mpz_poly_mul_mpz(v, v, inv);
2976 mpz_poly_mod_mpz(v, v, p, NULL);
2977 mpz_clear(inv);
2978 }
2979
2980 mpz_poly_clear(gg);
2981 mpz_poly_clear(uu);
2982 mpz_poly_clear(vv);
2983 mpz_poly_clear(q);
2984 mpz_poly_clear(tmp);
2985 }
2986
2987 /* Homographic transform on polynomials */
2988 /* Put in fij[] the coefficients of f'(i) = F(a0*i+a1, b0*i+b1).
2989 Assumes the coefficients of fij[] are initialized.
2990 */
2991 void
mpz_poly_homography(mpz_poly_ptr Fij,mpz_poly_srcptr F,int64_t H[4])2992 mpz_poly_homography (mpz_poly_ptr Fij, mpz_poly_srcptr F, int64_t H[4])
2993 {
2994 int k, l;
2995 mpz_t *g; /* will contain the coefficients of (b0*i+b1)^l */
2996 mpz_t f0;
2997 mpz_t *f = F->coeff;
2998 int d = F->deg;
2999
3000 mpz_poly_realloc (Fij, d + 1);
3001
3002 mpz_t *fij = Fij->coeff;
3003 for (k = 0; k <= d; k++)
3004 mpz_set (fij[k], f[k]);
3005
3006 Fij->deg = d;
3007
3008 g = (mpz_t*) malloc ((d + 1) * sizeof (mpz_t));
3009 FATAL_ERROR_CHECK (g == NULL, "not enough memory");
3010 for (k = 0; k <= d; k++)
3011 mpz_init (g[k]);
3012 mpz_init (f0);
3013
3014 /* Let h(x) = quo(f(x), x), then F(x,y) = H(x,y)*x + f0*y^d, thus
3015 F(a0*i+a1, b0*i+b1) = H(a0*i+a1, b0*i+b1)*(a0*i+a1) + f0*(b0*i+b1)^d.
3016 We use that formula recursively. */
3017
3018 mpz_set_ui (g[0], 1); /* g = 1 */
3019
3020 for (k = d - 1; k >= 0; k--)
3021 {
3022 /* invariant: we have already translated coefficients of degree > k,
3023 in f[k+1..d], and g = (b0*i+b1)^(d - (k+1)), with coefficients in
3024 g[0..d - (k+1)]:
3025 f[k] <- a1*f[k+1]
3026 ...
3027 f[l] <- a0*f[l]+a1*f[l+1] for k < l < d
3028 ...
3029 f[d] <- a0*f[d] */
3030 mpz_swap (f0, fij[k]); /* save the new constant coefficient */
3031 mpz_mul_si (fij[k], fij[k + 1], H[2]);
3032 for (l = k + 1; l < d; l++)
3033 {
3034 mpz_mul_si (fij[l], fij[l], H[0]);
3035 mpz_addmul_si (fij[l], fij[l + 1], H[2]);
3036 }
3037 mpz_mul_si (fij[d], fij[d], H[0]);
3038
3039 /* now compute (b0*i+b1)^(d-k) from the previous (b0*i+b1)^(d-k-1):
3040 g[d-k] = b0*g[d-k-1]
3041 ...
3042 g[l] = b1*g[l]+b0*g[l-1] for 0 < l < d-k
3043 ...
3044 g[0] = b1*g[0]
3045 */
3046 mpz_mul_si (g[d - k], g[d - k - 1], H[1]);
3047 for (l = d - k - 1; l > 0; l--)
3048 {
3049 mpz_mul_si (g[l], g[l], H[3]);
3050 mpz_addmul_si (g[l], g[l-1], H[1]);
3051 }
3052 mpz_mul_si (g[0], g[0], H[3]);
3053
3054 /* now g has degree d-k, and we add f0*g */
3055 for (l = 0; l <= d-k; l++)
3056 mpz_addmul(fij[l+k], g[l], f0);
3057
3058 }
3059
3060 mpz_clear (f0);
3061 for (k = 0; k <= d; k++)
3062 mpz_clear (g[k]);
3063 free (g);
3064 }
3065
3066 /* v <- |f(i,j)|, where f is homogeneous of degree d */
mpz_poly_homogeneous_eval_siui(mpz_ptr v,mpz_poly_srcptr f,const int64_t i,const uint64_t j)3067 void mpz_poly_homogeneous_eval_siui (mpz_ptr v, mpz_poly_srcptr f, const int64_t i, const uint64_t j)
3068 {
3069 unsigned int k = f->deg;
3070 ASSERT(k > 0);
3071 mpz_set (v, f->coeff[f->deg]);
3072 mpz_mul_si (v, f->coeff[k], i);
3073 cxx_mpz jpow;
3074 mpz_set_uint64 (jpow, j);
3075 mpz_addmul (v, f->coeff[--k], jpow); /* v = i*f[d] + j*f[d-1] */
3076 for (; k-- > 0;)
3077 {
3078 /* this test will be resolved at compile time by most compilers */
3079 if ((uint64_t) ULONG_MAX >= UINT64_MAX)
3080 { /* hardcode since this function is critical in las */
3081 mpz_mul_si (v, v, i);
3082 mpz_mul_ui (jpow, jpow, j);
3083 }
3084 else
3085 {
3086 mpz_mul_int64 (v, v, i);
3087 mpz_mul_uint64 (jpow, jpow, j);
3088 }
3089 mpz_addmul (v, f->coeff[k], jpow);
3090 }
3091 mpz_abs (v, v); /* avoids problems with negative norms */
3092 }
3093
3094 /* put in c the content of f */
3095 void
mpz_poly_content(mpz_ptr c,mpz_poly_srcptr F)3096 mpz_poly_content (mpz_ptr c, mpz_poly_srcptr F)
3097 {
3098 int i;
3099 mpz_t *f = F->coeff;
3100 int d = F->deg;
3101
3102 mpz_set (c, f[0]);
3103 for (i = 1; i <= d; i++)
3104 mpz_gcd (c, c, f[i]);
3105 mpz_abs (c, c);
3106 }
3107
3108 /*
3109 * Compute the pseudo division of a and b such that
3110 * lc(b)^(deg(a) - deg(b) + 1) * a = b * q + r with deg(r) < deg(b).
3111 * See Henri Cohen, "A Course in Computational Algebraic Number Theory",
3112 * for more information.
3113 *
3114 * Assume that deg(a) >= deg(b) and b is not the zero polynomial.
3115 */
mpz_poly_pseudo_division(mpz_poly_ptr q,mpz_poly_ptr r,mpz_poly_srcptr a,mpz_poly_srcptr b)3116 static void mpz_poly_pseudo_division(mpz_poly_ptr q, mpz_poly_ptr r,
3117 mpz_poly_srcptr a, mpz_poly_srcptr b)
3118 {
3119 ASSERT(a->deg >= b->deg);
3120 ASSERT(b->deg != -1);
3121
3122 int m = a->deg;
3123 int n = b->deg;
3124 mpz_t d;
3125 int e;
3126 mpz_poly s;
3127
3128 #ifndef NDEBUG
3129 MAYBE_UNUSED mpz_poly q_tmp;
3130 #endif // NDEBUG
3131
3132 mpz_init(d);
3133 mpz_set(d, mpz_poly_lc(b));
3134
3135 if (q != NULL) {
3136 mpz_poly_set_zero(q);
3137 }
3138
3139 #ifndef NDEBUG
3140 else {
3141 mpz_poly_init(q_tmp, 0);
3142 }
3143 #endif // NDEBUG
3144
3145 mpz_poly_set(r, a);
3146
3147 e = m - n + 1;
3148
3149 while (r->deg >= n) {
3150 mpz_poly_init(s, r->deg - n);
3151 mpz_poly_setcoeff(s, r->deg - n, mpz_poly_lc(r));
3152 if (q != NULL) {
3153 mpz_poly_mul_mpz(q, q, d);
3154 mpz_poly_add(q, s, q);
3155 }
3156
3157 #ifndef NDEBUG
3158 else {
3159 mpz_poly_mul_mpz(q_tmp, q_tmp, d);
3160 mpz_poly_add(q_tmp, s, q_tmp);
3161 }
3162 #endif // NDEBUG
3163
3164 mpz_poly_mul_mpz(r, r, d);
3165 mpz_poly_mul(s, b, s);
3166 mpz_poly_sub(r, r, s);
3167 mpz_poly_clear(s);
3168 e--;
3169 }
3170
3171 ASSERT(e >= 0);
3172
3173 mpz_pow_ui(d, d, (unsigned long int) e);
3174 if (q != NULL) {
3175 mpz_poly_mul_mpz(q, q, d);
3176 }
3177
3178 #ifndef NDEBUG
3179 else {
3180 mpz_poly_mul_mpz(q_tmp, q_tmp, d);
3181 }
3182 #endif // NDEBUG
3183
3184 mpz_poly_mul_mpz(r, r, d);
3185
3186 #ifndef NDEBUG
3187 mpz_poly f, g;
3188 mpz_poly_init(f, a->deg);
3189 mpz_poly_init(g, b->deg);
3190 mpz_poly_set(f, a);
3191 mpz_poly_set(g, b);
3192
3193 mpz_set(d, mpz_poly_lc(g));
3194
3195 ASSERT(m - n + 1 >= 0);
3196
3197 mpz_pow_ui(d, d, (unsigned long int) (m - n + 1));
3198 mpz_poly_mul_mpz(f, f, d);
3199
3200 if (q != NULL) {
3201 mpz_poly_mul(g, g, q);
3202 } else {
3203 mpz_poly_mul(g, g, q_tmp);
3204 }
3205 mpz_poly_add(g, g, r);
3206
3207 ASSERT(mpz_poly_cmp(f, g) == 0);
3208
3209 mpz_poly_clear(f);
3210 mpz_poly_clear(g);
3211 if (q == NULL) {
3212 mpz_poly_clear(q_tmp);
3213 }
3214 #endif // NDEBUG
3215
3216 mpz_clear(d);
3217 }
3218
3219 /*
3220 * Like mpz_poly_pseudo_division, but give only the remainder.
3221 */
mpz_poly_pseudo_remainder(mpz_poly_ptr r,mpz_poly_srcptr a,mpz_poly_srcptr b)3222 static void mpz_poly_pseudo_remainder(mpz_poly_ptr r, mpz_poly_srcptr a,
3223 mpz_poly_srcptr b)
3224 {
3225 mpz_poly_pseudo_division(NULL, r, a, b);
3226 }
3227
3228 /*
3229 * Compute the resultant of p and q and set the resultat in res.
3230 * See Henri Cohen, "A Course in Computational Algebraic Number Theory",
3231 * for more information.
3232 *
3233 * Assume that the polynomials are normalized.
3234 */
mpz_poly_resultant(mpz_ptr res,mpz_poly_srcptr p,mpz_poly_srcptr q)3235 void mpz_poly_resultant(mpz_ptr res, mpz_poly_srcptr p, mpz_poly_srcptr q)
3236 {
3237 if (p->deg == -1 || q->deg == -1) {
3238 mpz_set_ui(res, 0);
3239 return;
3240 }
3241
3242 ASSERT(mpz_cmp_ui(p->coeff[p->deg], 0) != 0);
3243 ASSERT(mpz_cmp_ui(q->coeff[q->deg], 0) != 0);
3244
3245 long int s = 1;
3246 mpz_t g;
3247 mpz_t h;
3248 mpz_t t;
3249 mpz_t tmp;
3250 int d;
3251 mpz_poly r;
3252 mpz_poly a;
3253 mpz_poly b;
3254
3255 mpz_init(g);
3256 mpz_init(h);
3257 mpz_init(t);
3258 mpz_init(tmp);
3259 mpz_poly_init(r, -1);
3260 mpz_poly_init(a, p->deg);
3261 mpz_poly_init(b, q->deg);
3262
3263 mpz_poly_set(a, p);
3264 mpz_poly_set(b, q);
3265
3266 mpz_poly_content(g, a);
3267 mpz_poly_content(h, b);
3268
3269 mpz_poly_divexact_mpz(a, a, g);
3270 mpz_poly_divexact_mpz(b, b, h);
3271
3272 #ifndef NDEBUG
3273 mpz_poly_content(tmp, a);
3274 ASSERT(mpz_cmp_ui(tmp, 1) == 0);
3275 mpz_poly_content(tmp, b);
3276 ASSERT(mpz_cmp_ui(tmp, 1) == 0);
3277 #endif // NDEBUG
3278
3279 mpz_pow_ui(t, g, (unsigned long int) b->deg);
3280 mpz_pow_ui(tmp, h, (unsigned long int) a->deg);
3281 mpz_mul(t, t, tmp);
3282
3283 mpz_set_ui(g, 1);
3284 mpz_set_ui(h, 1);
3285
3286 if (a->deg < b->deg) {
3287 mpz_poly_swap(a, b);
3288
3289 if ((a->deg % 2) == 1 && (b->deg % 2) == 1) {
3290 s = -1;
3291 }
3292 }
3293
3294 while (b->deg > 0) {
3295 d = a->deg - b->deg;
3296
3297 if ((a->deg % 2) == 1 && (b->deg % 2) == 1) {
3298 s = -s;
3299 }
3300
3301 mpz_poly_pseudo_remainder(r, a, b);
3302 mpz_poly_set(a, b);
3303
3304 ASSERT(d >= 0);
3305
3306 mpz_pow_ui(tmp, h, (unsigned long int) d);
3307 mpz_mul(tmp, g, tmp);
3308
3309 mpz_poly_divexact_mpz(b, r, tmp);
3310
3311 mpz_set(g, mpz_poly_lc(a));
3312
3313 #ifdef NDEBUG
3314 if (d == 0) {
3315 ASSERT(mpz_cmp_ui(h, 1) == 0);
3316 }
3317 #endif // NDEBUG
3318 mpz_pow_ui(h, h, (unsigned long int) (d - 1));
3319 mpz_pow_ui(tmp, g, (unsigned long int) d);
3320 mpz_divexact(h, tmp, h);
3321 }
3322
3323 //Prevent an error if b = 0.
3324 if (b->deg == -1) {
3325 mpz_set_ui(res, 0);
3326 } else {
3327 ASSERT(a->deg > 0);
3328 ASSERT(b->deg == 0);
3329
3330 mpz_pow_ui(h, h, (unsigned long int) (a->deg - 1));
3331
3332 ASSERT(a->deg >= 0);
3333
3334 mpz_pow_ui(tmp, b->coeff[0], (unsigned long int) a->deg);
3335 mpz_divexact(h, tmp, h);
3336
3337 mpz_mul_si(t, t, s);
3338 mpz_mul(h, h, t);
3339 mpz_set(res, h);
3340 }
3341
3342 mpz_clear(g);
3343 mpz_clear(h);
3344 mpz_clear(t);
3345 mpz_clear(tmp);
3346 mpz_poly_clear(a);
3347 mpz_poly_clear(b);
3348 mpz_poly_clear(r);
3349 }
3350
mpz_poly_discriminant(mpz_ptr res,mpz_poly_srcptr f)3351 void mpz_poly_discriminant(mpz_ptr res, mpz_poly_srcptr f)
3352 {
3353 mpz_poly df;
3354 mpz_poly_init(df, f->deg);
3355 mpz_poly_derivative(df, f);
3356 mpz_poly_resultant(res, f, df);
3357 ASSERT(mpz_divisible_p(res, mpz_poly_lc(f)));
3358 mpz_divexact(res, res, mpz_poly_lc(f));
3359 mpz_poly_clear(df);
3360 }
3361
3362 /* returns non-zero iff f is square-free in Z[x] */
3363 int
mpz_poly_squarefree_p(mpz_poly_srcptr f)3364 mpz_poly_squarefree_p (mpz_poly_srcptr f)
3365 {
3366 mpz_poly df;
3367 mpz_t res;
3368 int ret;
3369
3370 mpz_poly_init (df, f->deg);
3371 mpz_poly_derivative (df, f);
3372 mpz_init (res);
3373 mpz_poly_resultant (res, f, df);
3374 ret = mpz_cmp_ui (res, 0);
3375 mpz_clear (res);
3376 mpz_poly_clear (df);
3377 return ret;
3378 }
3379
3380 /**
3381 * Quick-and-dirty test if the polynomial f is irreducible over Z.
3382 * This function is extracted from dlpolyselect.c written by PZ
3383 *
3384 * Let p be a prime such that f has a root r modulo p.
3385 * Search by LLL a small linear combination between 1, r, ..., r^(d-1).
3386 * If f is not irreducible, then p will be root of a factor of degree <= d-1,
3387 * which will yield a linear dependency of the same order as the coefficients
3388 * of f, otherwise if f is irreducible the linear dependency will be of order
3389 * p^(1/d).
3390 *
3391 * \return 0 by default, 1 if the poly is irreducible.
3392 *
3393 * this function is without any warranty and at your own risk
3394 */
mpz_poly_is_irreducible_z(mpz_poly_srcptr f)3395 int mpz_poly_is_irreducible_z (mpz_poly_srcptr f)
3396 {
3397 mpz_t p;
3398 int d = f->deg;
3399 int dg = d - 1;
3400 int i, j, nr;
3401 mpz_t a, b, det, r, *roots;
3402 size_t normf;
3403 int ret = 0; // init
3404 mat_Z g;
3405 gmp_randstate_t rstate;
3406
3407 mpz_init (p);
3408 gmp_randinit_default(rstate);
3409
3410 mpz_poly_infinity_norm (p, f);
3411 normf = mpz_sizeinbase (p, 2);
3412 /* The following table might be useful to optimize the value of MARGIN:
3413 degree d infinity_norm(f) optimal MARGIN
3414 3 8 5
3415 4 4 5
3416 */
3417 #define MARGIN 16
3418 /* add some margin bits */
3419 mpz_mul_2exp (p, p, MARGIN);
3420 mpz_pow_ui (p, p, d);
3421
3422 roots = (mpz_t*) malloc (d * sizeof (mpz_t));
3423 for (i = 0; i < d; i++)
3424 mpz_init (roots[i]);
3425
3426 do {
3427 mpz_nextprime (p, p);
3428 nr = mpz_poly_roots_mpz(roots, f, p, rstate);
3429 /* If f has no root mod p and degree <= 3, it is irreducible,
3430 since a degree 2 polynomial can only factor into 1+1 or 2,
3431 and a degree 3 polynomial can only factor into 1+2 or 3. */
3432 if (nr == 0 && d <= 3)
3433 {
3434 ret = 1;
3435 goto clear_and_exit;
3436 }
3437 } while (nr == 0);
3438
3439 g.coeff = (mpz_t **) malloc ((dg + 2)*sizeof(mpz_t*));
3440 g.NumRows = g.NumCols = dg + 1;
3441 for (i = 0; i <= dg + 1; i ++) {
3442 g.coeff[i] = (mpz_t *) malloc ((dg + 2)*sizeof(mpz_t));
3443 for (j = 0; j <= dg + 1; j ++) {
3444 mpz_init (g.coeff[i][j]);
3445 }
3446 }
3447
3448 mpz_init (det);
3449 mpz_init_set_ui (a, 1);
3450 mpz_init_set_ui (b, 1);
3451 mpz_init_set (r, roots[0]);
3452 for (i = 0; i <= dg + 1; i ++) {
3453 for (j = 0; j <= dg + 1; j ++) {
3454 mpz_set_ui (g.coeff[i][j], 0);
3455 }
3456 }
3457
3458 for (i = 1; i <= dg + 1; i++) {
3459 for (j = 1; j <= dg + 1; j++) {
3460 if (i == 1) {
3461 if (j == 1) {
3462 mpz_set (g.coeff[j][i], p);
3463 }
3464 else {
3465 mpz_neg (g.coeff[j][i], r);
3466 mpz_mul (r, r, roots[0]);
3467 }
3468 }
3469 else
3470 mpz_set_ui (g.coeff[j][i], i==j);
3471 }
3472 }
3473
3474 LLL (det, g, NULL, a, b);
3475
3476 for (j = 1; j <= dg + 1; j ++)
3477 {
3478 /* the coefficients of vector j are in g.coeff[j][i], 1 <= i <= dg + 1 */
3479 mpz_abs (a, g.coeff[j][1]);
3480 for (i = 2; i <= dg + 1; i++)
3481 if (mpz_cmpabs (g.coeff[j][i], a) > 0)
3482 mpz_abs (a, g.coeff[j][i]);
3483 /* now a = max (|g.coeff[j][i]|, 1 <= i <= dg+1) */
3484 if (j == 1 || mpz_cmpabs (a, b) < 0)
3485 mpz_set (b, a);
3486 }
3487 /* now b is the smallest infinity norm */
3488 if (mpz_sizeinbase (b, 2) < normf + MARGIN / 2)
3489 ret = 0;
3490 else
3491 ret = 1;
3492
3493 for (i = 0; i <= dg + 1; i ++) {
3494 for (j = 0; j <= dg + 1; j ++)
3495 mpz_clear (g.coeff[i][j]);
3496 free(g.coeff[i]);
3497 }
3498 free (g.coeff);
3499
3500 mpz_clear (det);
3501 mpz_clear (a);
3502 mpz_clear (b);
3503 mpz_clear (r);
3504 clear_and_exit:
3505 for (i = 0; i < d; i++)
3506 mpz_clear (roots[i]);
3507 free (roots);
3508
3509 gmp_randclear(rstate);
3510 mpz_clear (p);
3511
3512 return ret;
3513 }
3514
3515
3516 /* factoring polynomials */
3517
mpz_poly_factor_list_init(mpz_poly_factor_list_ptr l)3518 void mpz_poly_factor_list_init(mpz_poly_factor_list_ptr l)
3519 {
3520 memset(l, 0, sizeof(*l));
3521 }
3522
mpz_poly_factor_list_clear(mpz_poly_factor_list_ptr l)3523 void mpz_poly_factor_list_clear(mpz_poly_factor_list_ptr l)
3524 {
3525 for(int i = 0 ; i < l->alloc ; i++)
3526 mpz_poly_clear(l->factors[i]->f);
3527 free(l->factors);
3528 memset(l, 0, sizeof(*l));
3529 }
3530
mpz_poly_factor_list_flush(mpz_poly_factor_list_ptr l)3531 void mpz_poly_factor_list_flush(mpz_poly_factor_list_ptr l)
3532 {
3533 /* There's a design choice here. We may elect to free everything.
3534 * Instead, we'll simply mark everything as zero, but keep all
3535 * allocated space.
3536 */
3537 for(int i = 0 ; i < l->alloc ; i++)
3538 l->factors[i]->f->deg = -1;
3539 l->size = 0;
3540 }
3541
3542
mpz_poly_factor_list_prepare_write(mpz_poly_factor_list_ptr l,int index)3543 void mpz_poly_factor_list_prepare_write(mpz_poly_factor_list_ptr l, int index)
3544 {
3545 if (index >= l->alloc) {
3546 l->alloc = index + 4 + l->alloc / 4;
3547 l->factors = (mpz_poly_with_m*) realloc(l->factors, l->alloc * sizeof(mpz_poly_with_m));
3548 /* We need to set something. A zero polynomial has NULL storage
3549 * area, so that will do (realloc behaves as needed). */
3550 for(int i = l->size ; i < l->alloc ; i++) {
3551 mpz_poly_init(l->factors[i]->f, -1);
3552 l->factors[i]->m = 0;
3553 }
3554 }
3555 if (l->size <= index)
3556 l->size = index + 1;
3557 }
3558
mpz_poly_factor_list_push(mpz_poly_factor_list_ptr l,mpz_poly_srcptr f,int m)3559 void mpz_poly_factor_list_push(mpz_poly_factor_list_ptr l, mpz_poly_srcptr f, int m)
3560 {
3561 mpz_poly_factor_list_prepare_write(l, l->size);
3562 mpz_poly_set(l->factors[l->size - 1]->f, f);
3563 l->factors[l->size - 1]->m = m;
3564 }
3565
mpz_poly_factor_list_fprintf(FILE * fp,mpz_poly_factor_list_srcptr l)3566 void mpz_poly_factor_list_fprintf(FILE* fp, mpz_poly_factor_list_srcptr l)
3567 {
3568 for (int i = 0 ; i < l->size ; i++){
3569 char * res;
3570 int rc = mpz_poly_asprintf(&res,l->factors[i]->f);
3571 ASSERT_ALWAYS(rc >= 0);
3572 if (i) fprintf(fp, "*");
3573 fprintf(fp, "(%s)^%d", res, l->factors[i]->m);
3574 free(res);
3575 }
3576 fprintf(fp, "\n");
3577 }
3578 /* Squarefree factorization */
3579
3580 /* This auxiliary function almost does the sqf. It fills
3581 * lf->factors[stride*i] (i from 1 to deg(f)) with the factors with
3582 * multiplicity i in f. lf->factors[0] is filled with the product whose
3583 * multiplicity is a multiple of the field characteristic. returns max
3584 * multiplicity stored (multiplied by the stride value).
3585 *
3586 * (stride has an importance for the recursive call, for p small. E.g. on
3587 * f=g^p, we get called with g=f^(1/p) and stride=p).
3588 *
3589 * We make no effort to check that lf is clean on input, which is to be
3590 * guaranteed by the caller (e.g. sufficiently many polynomials, all
3591 * equal to 1 -- or 0, which can easily be identified as something
3592 * unset).
3593 *
3594 * Coefficients of f need not be reduced mod p.
3595 * Coefficients of all polynomials stored in lf are reduced mod p.
3596 */
mpz_poly_factor_sqf_inner(mpz_poly_factor_list_ptr lf,mpz_poly_srcptr f,int stride,mpz_srcptr p)3597 static int mpz_poly_factor_sqf_inner(mpz_poly_factor_list_ptr lf, mpz_poly_srcptr f, int stride, mpz_srcptr p)
3598 {
3599 int r = 0;
3600
3601 mpz_poly g, mi, mi1;
3602 mpz_poly t0,t1, T, tmp;
3603 mpz_poly_init(g, f->deg);
3604 mpz_poly_init(mi, f->deg);
3605 mpz_poly_init(mi1, f->deg);
3606 mpz_poly_init(t0, f->deg);
3607 mpz_poly_init(t1, f->deg);
3608 mpz_poly_init(T, f->deg);
3609 mpz_poly_init(tmp, f->deg);
3610
3611 mpz_poly_derivative(t0, f);
3612 mpz_poly_gcd_mpz(g, f, t0, p);
3613 mpz_poly_divexact(mi, f, g, p);
3614 /* mi is f/gcd(f,f') == all repeated prime factors of f whose
3615 * multiplicity isn't a multiple of the field characteristic.
3616 */
3617
3618 mpz_poly_set_xi(T, 0);
3619 for(int i = 1 ; mi->deg > 0 ; i++) {
3620 /* note the weird argument ordering */
3621 mpz_poly_pow_ui_mod_f_mod_mpz(t0, mi, NULL, i, p);
3622 mpz_poly_divexact(t1, f, t0, p);
3623 /* t1 = all polynomials in mi taken out from f with multiplicity i */
3624 mpz_poly_gcd_mpz(mi1, t1, mi, p);
3625 /* mi1 = almost like mi, but since factors with multiplicity i
3626 * are no longer in t1, there's absent from mi1 too. Whence
3627 * mi/mi1 is exactly the product of factors of multiplicity 1.
3628 */
3629 mpz_poly_factor_list_prepare_write(lf, i * stride);
3630 /* Use tmp so that we don't absurdly keep storage within
3631 * lf->factors */
3632 mpz_poly_divexact(tmp, mi, mi1, p);
3633 mpz_poly_set(lf->factors[i * stride]->f, tmp);
3634 /* multiplicity field still unused at this point */
3635 mpz_poly_pow_ui_mod_f_mod_mpz(t0, lf->factors[i * stride]->f, NULL, i, p);
3636 mpz_poly_mul(T, T, t0);
3637 mpz_poly_mod_mpz(T, T, p, NULL);
3638 mpz_poly_swap(mi, mi1);
3639 r = i * stride;
3640 }
3641
3642 mpz_poly_factor_list_prepare_write(lf, 0);
3643 mpz_poly_divexact(lf->factors[0]->f, f, T, p);
3644
3645 mpz_poly_clear(g);
3646 mpz_poly_clear(tmp);
3647 mpz_poly_clear(mi);
3648 mpz_poly_clear(mi1);
3649 mpz_poly_clear(t0);
3650 mpz_poly_clear(t1);
3651 mpz_poly_clear(T);
3652 return r;
3653 }
3654
3655 /* Fills lf->factors[i] (i from 1 to deg(f)) with product of the factors
3656 * with multiplicity i in f, and to 1 if there are none. lf->factors[0]
3657 * is set to 1. return the largest multiplicity stored. */
3658 /* Coefficients of f0 need not be reduced mod p.
3659 * Coefficients of all polynomials stored in lf are reduced mod p.
3660 */
mpz_poly_factor_sqf(mpz_poly_factor_list_ptr lf,mpz_poly_srcptr f0,mpz_srcptr p)3661 int mpz_poly_factor_sqf(mpz_poly_factor_list_ptr lf, mpz_poly_srcptr f0,
3662 mpz_srcptr p)
3663 {
3664 /* factoring 0 doesn't make sense, really */
3665 ASSERT(f0->deg >= 0);
3666
3667 ASSERT_ALWAYS(mpz_cmp_ui(p, 0) > 0);
3668
3669 /* We'll call mpz_poly_factor_sqf_inner, possibly several times if
3670 * we are in small characteristic.
3671 */
3672 mpz_poly f;
3673 mpz_poly_init(f, f0->deg);
3674 mpz_poly_makemonic_mod_mpz(f, f0, p);
3675 ASSERT(mpz_cmp_ui(mpz_poly_lc(f), 1) == 0);
3676
3677 int m = 0;
3678 // coverity[zero_return]
3679 int pu = mpz_get_ui(p); // see below
3680 /* reset the factor list completely */
3681 mpz_poly_factor_list_flush(lf);
3682
3683 for(int stride = 1 ; ; stride *= pu) {
3684 int r = mpz_poly_factor_sqf_inner(lf, f, stride, p);
3685 if (r > m) m = r;
3686 if (lf->factors[0]->f->deg == 0) {
3687 // if p is LAAAARGE, then of course we'll never have a linear
3688 // polynomial out of sqf_inner, thus we'll break early here.
3689 break;
3690 }
3691 /* divide coefficients */
3692 for(int i = 0 ; i <= lf->factors[0]->f->deg ; i++) {
3693 if (i % pu == 0) {
3694 mpz_set(f->coeff[i / pu], lf->factors[0]->f->coeff[i]);
3695 } else {
3696 ASSERT (mpz_cmp_ui(lf->factors[0]->f->coeff[i], 0) == 0);
3697 }
3698 }
3699 f->deg = lf->factors[0]->f->deg / pu;
3700 mpz_poly_set_xi(lf->factors[0]->f, 0);
3701 }
3702 /* Now make sure that all factors in the factor list are non-zero */
3703 for(int i = 0 ; i < lf->size ; i++) {
3704 if (lf->factors[i]->f->deg < 0) {
3705 mpz_poly_set_xi(lf->factors[i]->f, 0);
3706 }
3707 }
3708 mpz_poly_clear(f);
3709 return m;
3710 }
3711
3712
3713
3714
3715 /* This performs distinct degree factorization */
3716 /* Input polynomial must be squarefree -- otherwise repeated factors
3717 * probably won't show up in the factor list, or maybe at the wrong place
3718 * as parasites. */
3719 /* Returns max degree of factors found (i.e. if the largest factors we
3720 * have are two factors of degree 7, we return 7, not 14). */
3721 /* Coefficients of f0 need not be reduced mod p.
3722 * Coefficients of all polynomials stored in lf are reduced mod p.
3723 */
mpz_poly_factor_ddf_inner(mpz_poly_factor_list_ptr lf,mpz_poly_srcptr f0,mpz_srcptr p,int only_check_irreducible)3724 static int mpz_poly_factor_ddf_inner(mpz_poly_factor_list_ptr lf, mpz_poly_srcptr f0, mpz_srcptr p, int only_check_irreducible)
3725 {
3726 mpz_poly g, gmx, x, tmp;
3727 mpz_poly f;
3728 mpz_poly_init(f, f0->deg);
3729 int i;
3730
3731 /* factoring 0 doesn't make sense, really */
3732 ASSERT(f0->deg >= 0);
3733
3734 mpz_poly_makemonic_mod_mpz(f, f0, p);
3735 ASSERT(mpz_cmp_ui(mpz_poly_lc(f), 1) == 0);
3736
3737 /* reset the factor list completely */
3738 mpz_poly_factor_list_flush(lf);
3739
3740 mpz_poly_init (g, 2 * f->deg - 1);
3741 mpz_poly_init (gmx, 2 * f->deg - 1);
3742 mpz_poly_init (x, 1);
3743 mpz_poly_init (tmp, f->deg);
3744
3745 mpz_poly_set_xi(x, 1);
3746 mpz_poly_set_xi(g, 1);
3747
3748 for (i = 1; i <= f->deg ; ++i) {
3749 if (2 * i > f->deg) {
3750 /* Then we know that the remaining f is irreducible. */
3751 mpz_poly_factor_list_prepare_write(lf, f->deg);
3752 for( ; i < f->deg ; i++) {
3753 /* multiplicity field still unused at this point */
3754 mpz_poly_set_xi(lf->factors[i]->f, 0);
3755 }
3756 /* multiplicity field still unused at this point */
3757 mpz_poly_swap(lf->factors[f->deg]->f, f);
3758 break;
3759 }
3760
3761 /* g <- g^p mod fp */
3762 mpz_poly_pow_mod_f_mod_mpz(g, g, f, p, p);
3763
3764 /* subtract x */
3765 mpz_poly_sub(gmx, g, x);
3766 mpz_poly_mod_mpz(gmx, gmx, p, NULL);
3767
3768 /* lf[i] <- gcd (f, x^(p^i)-x) */
3769 mpz_poly_factor_list_prepare_write(lf, i);
3770 /* multiplicity field still unused at this point */
3771
3772 /* see remark in _sqf regarding the relevance of tmp for storage */
3773 mpz_poly_gcd_mpz(tmp, f, gmx, p);
3774 mpz_poly_divexact(f, f, tmp, p);
3775 mpz_poly_set(lf->factors[i]->f, tmp);
3776
3777 /* Note for a mere irreducibility test: the length of the loop in
3778 * the irreducible case would still be deg(f)/2, and the penalty
3779 * caused by storing factors can be neglected.
3780 */
3781 if (only_check_irreducible && lf->factors[i]->f->deg > 0)
3782 break;
3783
3784 if (f->deg == 0)
3785 break;
3786 }
3787
3788 mpz_poly_clear (g);
3789 mpz_poly_clear (x);
3790 mpz_poly_clear (gmx);
3791 mpz_poly_clear (tmp);
3792 mpz_poly_clear (f);
3793
3794 return i;
3795 }
3796
mpz_poly_factor_ddf(mpz_poly_factor_list_ptr lf,mpz_poly_srcptr f0,mpz_srcptr p)3797 int mpz_poly_factor_ddf(mpz_poly_factor_list_ptr lf, mpz_poly_srcptr f0,
3798 mpz_srcptr p)
3799 {
3800 return mpz_poly_factor_ddf_inner(lf, f0, p, 0);
3801 }
3802
3803 /* Note that this also works for non squarefree polynomials -- the factor
3804 * list returned by mpz_poly_factor_ddf will be rubbish, but the m ==
3805 * f->deg test will tell the truth. */
mpz_poly_is_irreducible(mpz_poly_srcptr f,mpz_srcptr p)3806 int mpz_poly_is_irreducible(mpz_poly_srcptr f, mpz_srcptr p)
3807 {
3808 mpz_poly_factor_list lf;
3809 mpz_poly_factor_list_init(lf);
3810 int m = mpz_poly_factor_ddf_inner(lf, f, p, 1);
3811 mpz_poly_factor_list_clear(lf);
3812 return m == f->deg;
3813 }
3814
3815 /* Naive factorization of polynomials over GF(2). We assume we're always
3816 * dealing with polynomials of degree at most 10, so we're beter off
3817 * simply enumerating potential factors...
3818 */
3819
3820 /*
3821 * Add 1 to f. If the constant term is equal to 1, set this term to 0 and
3822 * propagate the addition of 1 to the next coefficient, and so on.
3823 *
3824 * f: the polynomial on which the addition is computed, the modifications are
3825 * made on f.
3826 */
mpz_poly_add_one_in_F2(mpz_poly_ptr f)3827 static void mpz_poly_add_one_in_F2(mpz_poly_ptr f)
3828 {
3829 ASSERT(f->deg >= 1);
3830
3831 int i = 0;
3832 while (mpz_cmp_ui(f->coeff[i], 1) == 0) {
3833 mpz_poly_setcoeff_si(f, i, 0);
3834 i++;
3835 if (i > f->deg) {
3836 break;
3837 }
3838 }
3839 mpz_poly_setcoeff_si(f, i, 1);
3840 }
3841
3842 /*
3843 * Factorize naively a mpz_poly mod 2.
3844 *
3845 * Return the number of factors found.
3846 */
mpz_poly_factor2(mpz_poly_factor_list_ptr list,mpz_poly_srcptr f,mpz_srcptr p)3847 static int mpz_poly_factor2(mpz_poly_factor_list_ptr list, mpz_poly_srcptr f,
3848 mpz_srcptr p)
3849 {
3850 ASSERT(mpz_cmp_ui(p, 2) == 0);
3851
3852 //make a copy of f.
3853 mpz_poly fcopy;
3854 mpz_poly_init(fcopy, f->deg);
3855 mpz_poly_set(fcopy, f);
3856
3857 //reduce all the coefficient mod p.
3858 mpz_t coeff;
3859 mpz_init(coeff);
3860 for (int i = 0; i <= f->deg; i++) {
3861 mpz_poly_getcoeff(coeff, i, f);
3862 mpz_mod(coeff, coeff, p);
3863 mpz_poly_setcoeff(fcopy, i, coeff);
3864 }
3865
3866 //Purge list.
3867 mpz_poly_factor_list_flush(list);
3868
3869 //If deg(f) in F2 is less than 1, we have the factor.
3870 if (fcopy->deg < 1) {
3871 mpz_clear(coeff);
3872 mpz_poly_clear(fcopy);
3873 ASSERT(list->size == 0);
3874 return list->size;
3875 } else if (fcopy->deg == 1) {
3876 mpz_clear(coeff);
3877 mpz_poly_factor_list_push(list, fcopy, 1);
3878 mpz_poly_clear(fcopy);
3879 ASSERT(list->size == 1);
3880 return list->size;
3881 }
3882
3883 if (mpz_poly_is_irreducible(f, p)) {
3884 //If f is irreducible mod 2, fcopy is the factorisation of f mod 2.
3885 mpz_poly_factor_list_push(list, fcopy, 1);
3886 } else {
3887 //Create the first possible factor.
3888 mpz_poly tmp;
3889 mpz_poly_init(tmp, 1);
3890 mpz_poly_setcoeff_int64(tmp, 1, 1);
3891
3892 //Enumerate all the possible factor of f mod 2.
3893 while (tmp->deg <= fcopy->deg) {
3894 //tmp is a possible factor.
3895 if (mpz_poly_is_irreducible(tmp, p)) {
3896 mpz_poly q;
3897 mpz_poly_init(q, 0);
3898 mpz_poly r;
3899 mpz_poly_init(r, 0);
3900 //Euclidean division of fcopy
3901 mpz_poly_div_qr(q, r, fcopy, tmp, p);
3902 //Power of the possible factor.
3903 unsigned int m = 0;
3904 //While fcopy is divisible by tmp.
3905 while (r->deg == -1) {
3906 //Increase the power of tmp.
3907 m++;
3908 mpz_poly_set(fcopy, q);
3909 if (fcopy->deg == 0 || fcopy->deg == -1) {
3910 //No other possible factor.
3911 break;
3912 }
3913 mpz_poly_div_qr(q, r, fcopy, tmp, p);
3914 }
3915 if (m != 0) {
3916 //Push tmp^m as a factor of f mod 2.
3917 mpz_poly_factor_list_push(list, tmp, m);
3918 }
3919 mpz_poly_clear(q);
3920 mpz_poly_clear(r);
3921 }
3922 //Go to the next possible polynomial in F2.
3923 mpz_poly_add_one_in_F2(tmp);
3924 }
3925 mpz_poly_clear(tmp);
3926 }
3927
3928 #ifndef NDBEBUG
3929 //Verify if the factorisation is good.
3930 mpz_poly_cleandeg(fcopy, -1);
3931 for (int i = 0; i <= f->deg; i++) {
3932 mpz_poly_getcoeff(coeff, i, f);
3933 mpz_mod(coeff, coeff, p);
3934 mpz_poly_setcoeff(fcopy, i, coeff);
3935 }
3936
3937 mpz_poly fmul;
3938 mpz_poly_init(fmul, -1);
3939 mpz_poly_set(fmul, list->factors[0]->f);
3940 for (int j = 1; j < list->factors[0]->m; j++) {
3941 mpz_poly_mul(fmul, fmul, list->factors[0]->f);
3942 }
3943 for (int i = 1; i < list->size ; i++) {
3944 for (int j = 0; j < list->factors[i]->m; j++) {
3945 mpz_poly_mul(fmul, fmul, list->factors[i]->f);
3946 }
3947 }
3948 for (int i = 0; i <= fmul->deg; i++) {
3949 mpz_poly_getcoeff(coeff, i, fmul);
3950 mpz_mod(coeff, coeff, p);
3951 mpz_poly_setcoeff(fmul, i, coeff);
3952 }
3953
3954 ASSERT(mpz_poly_cmp(fcopy, fmul) == 0);
3955
3956 mpz_poly_clear(fmul);
3957 #endif // NDBEBUG
3958
3959 mpz_clear(coeff);
3960 mpz_poly_clear(fcopy);
3961
3962 return list->size;
3963 }
3964
3965 /*
3966 * this tries to split between squares and non-squares -- it's the most
3967 * basic split of course, and the other splits merely randomize on top of
3968 * this. Note that this building block must be changed for characteristic
3969 * two
3970 *
3971 * returns non-zero if a non-trivial or split is obtained.
3972 *
3973 * k is the degree of factors we are looking for.
3974 *
3975 * We split in two parts:
3976 *
3977 * - factors whose roots are squares in GF(p^k).
3978 * - factors whose roots are non squares in GF(p^k).
3979 *
3980 * Note that we do not find the factor X this way; this is to be done by
3981 * the caller.
3982 *
3983 * Obviously, we include some shift, and hope that eventually there is a
3984 * shift that works. Large characteristic is generally happy with some
3985 * translation shift. Small characteristic may need more general shifts.
3986 *
3987 * Coefficients of f0 need not be reduced mod p.
3988 * Coefficients of g[0] and g[1] are reduced mod p.
3989 */
mpz_poly_factor_edf_pre(mpz_poly g[2],mpz_poly_srcptr f,int k,mpz_srcptr p)3990 static void mpz_poly_factor_edf_pre(mpz_poly g[2], mpz_poly_srcptr f, int k,
3991 mpz_srcptr p)
3992 {
3993 int nontrivial = 0;
3994 mpz_poly_set_xi(g[0], 0);
3995 mpz_poly_set_xi(g[1], 0);
3996
3997 ASSERT_ALWAYS(mpz_cmp_ui(p, 0) > 0);
3998
3999 ASSERT_ALWAYS (f->deg > k);
4000
4001 mpz_poly xplusa;
4002 mpz_poly_init(xplusa, 1);
4003
4004 mpz_t half_pk;
4005 mpz_init(half_pk);
4006 mpz_pow_ui(half_pk, p, k);
4007 mpz_fdiv_q_ui(half_pk, half_pk, 2); /* (p^k-1)/2 */
4008
4009 for(unsigned long a = 0 ; ! nontrivial ; a++) {
4010 /* we want to iterate on monic polynomials of degree <= k-1. */
4011 /* In order to bear in mind what happens in large enough
4012 * characteristic, we'll name these polynomials xplusa, although
4013 * it does not have to be x+a (and it can't be restricted to only
4014 * x+a if the characteristic is small -- that does not give
4015 * enough legroom).
4016 */
4017 if (mpz_fits_ulong_p(p)) {
4018 // coverity[zero_return]
4019 unsigned long pz = mpz_get_ui(p);
4020 if (a == 0) {
4021 /* special case, really */
4022 mpz_poly_set_xi(xplusa, 1);
4023 } else {
4024 /* write a in base p, and add 1 */
4025 int i = 0;
4026 for(unsigned long tmp = a ; tmp ; i++, tmp /= pz) {
4027 mpz_poly_setcoeff_ui(xplusa, i, tmp % pz);
4028 }
4029 mpz_poly_setcoeff_ui(xplusa, i, 1);
4030 }
4031 } else {
4032 /* take the polynomial x+a */
4033 mpz_poly_set_xi(xplusa, 1);
4034 mpz_poly_setcoeff_ui(xplusa, 0, a);
4035 }
4036
4037 mpz_poly_pow_mod_f_mod_mpz(g[0], xplusa, f, half_pk, p);
4038
4039 mpz_poly_add_ui(g[1], g[0], 1); /* (x+a)^((p^k-1)/2) + 1 */
4040 mpz_poly_sub_ui(g[0], g[0], 1); /* (x+a)^((p^k-1)/2) - 1 */
4041
4042 mpz_poly_mod_mpz(g[0], g[0], p, NULL);
4043 mpz_poly_mod_mpz(g[1], g[1], p, NULL);
4044
4045 mpz_poly_gcd_mpz(g[0], g[0], f, p);
4046 mpz_poly_gcd_mpz(g[1], g[1], f, p);
4047
4048 if (g[0]->deg + g[1]->deg < f->deg) {
4049 /* oh, we're lucky. x+a is a factor ! */
4050 int s = g[0]->deg > g[1]->deg;
4051 /* multiply g[s] by (x+a) */
4052 mpz_poly_mul_mod_f_mod_mpz(g[s], g[s], xplusa, f, p, NULL, NULL);
4053 }
4054 ASSERT(g[0]->deg + g[1]->deg == f->deg);
4055 ASSERT(g[0]->deg % k == 0);
4056 ASSERT(g[1]->deg % k == 0);
4057
4058 nontrivial += g[0]->deg != 0 && g[0]->deg != f->deg;
4059 nontrivial += g[1]->deg != 0 && g[1]->deg != f->deg;
4060 }
4061 mpz_clear(half_pk);
4062 mpz_poly_clear(xplusa);
4063 }
4064
4065 /* This factors f, and for each factor q found, store q in lf.
4066 * Return the number of distinct factors found. */
4067 /* Coefficients of f need not be reduced mod p.
4068 * Coefficients of all polynomials stored in lf are reduced mod p.
4069 */
mpz_poly_factor_edf_inner(mpz_poly_factor_list_ptr lf,mpz_poly_srcptr f,int k,mpz_srcptr p,gmp_randstate_t rstate)4070 static int mpz_poly_factor_edf_inner(mpz_poly_factor_list_ptr lf, mpz_poly_srcptr f, int k, mpz_srcptr p, gmp_randstate_t rstate)
4071 {
4072 if (f->deg == k) {
4073 mpz_poly_factor_list_push(lf, f, 1);
4074 return 1;
4075 }
4076 if (f->deg == 0) {
4077 return 0;
4078 }
4079
4080 mpz_poly h[2];
4081
4082 mpz_poly_init(h[0], f->deg);
4083 mpz_poly_init(h[1], f->deg);
4084
4085 mpz_poly_factor_edf_pre(h, f, k, p);
4086
4087 int n = 0;
4088
4089 n += mpz_poly_factor_edf_inner(lf, h[0], k, p, rstate);
4090 mpz_poly_clear(h[0]);
4091
4092 n += mpz_poly_factor_edf_inner(lf, h[1], k, p, rstate);
4093 mpz_poly_clear(h[1]);
4094
4095 return n;
4096 }
4097
4098 // returns f0->deg / d
4099 /* Coefficients of f need not be reduced mod p.
4100 * Coefficients of all polynomials stored in lf are reduced mod p.
4101 */
mpz_poly_factor_edf(mpz_poly_factor_list_ptr lf,mpz_poly_srcptr f,int k,mpz_srcptr p,gmp_randstate_t rstate)4102 int mpz_poly_factor_edf(mpz_poly_factor_list_ptr lf, mpz_poly_srcptr f, int k, mpz_srcptr p, gmp_randstate_t rstate)
4103 {
4104 mpz_poly_factor_list_flush(lf);
4105
4106 if (mpz_cmp_ui(p, 2) == 0) {
4107 /* we need some other code for edf. Currently we have very naive
4108 * code, but that's good enough for small degree. */
4109 return mpz_poly_factor2(lf, f, p);
4110 }
4111
4112 int v = mpz_poly_valuation(f);
4113 if (v) {
4114 /* Since our input is square-free, then we expect v==1.
4115 * Furthermore, k prescribes the extension field where the
4116 * expected roots live, thus for 0 it should really be 1. */
4117 ASSERT_ALWAYS(v == 1 && k == 1);
4118 mpz_poly_factor_list_prepare_write(lf, lf->size);
4119 mpz_poly_set_xi(lf->factors[lf->size-1]->f, 1);
4120
4121 mpz_poly f1;
4122 mpz_poly_init(f1, f->deg - 1);
4123 mpz_poly_div_xi(f1, f, v);
4124 int n = 1 + mpz_poly_factor_edf_inner(lf, f1, k, p, rstate);
4125 mpz_poly_clear(f1);
4126 return n;
4127 }
4128
4129 int ret = mpz_poly_factor_edf_inner(lf, f, k, p, rstate);
4130 return ret;
4131 }
4132
4133 typedef int (*sortfunc_t) (const void *, const void *);
4134
mpz_poly_with_m_cmp(const mpz_poly_with_m * a,const mpz_poly_with_m * b)4135 static int mpz_poly_with_m_cmp(
4136 const mpz_poly_with_m * a,
4137 const mpz_poly_with_m * b)
4138 {
4139 int r = mpz_poly_cmp((*a)->f, (*b)->f);
4140 if (r) return r;
4141 return ((*a)->m > (*b)->m) - ((*b)->m > (*a)->m);
4142 }
4143
4144
4145 /* putting it all together */
4146 /* Coefficients of f need not be reduced mod p.
4147 * Coefficients of all polynomials stored in lf are reduced mod p.
4148 */
mpz_poly_factor(mpz_poly_factor_list lf,mpz_poly_srcptr f,mpz_srcptr p,gmp_randstate_t rstate)4149 int mpz_poly_factor(mpz_poly_factor_list lf, mpz_poly_srcptr f, mpz_srcptr p, gmp_randstate_t rstate)
4150 {
4151 mpz_poly_factor_list sqfs, ddfs, edfs;
4152 mpz_poly_factor_list_init(sqfs);
4153 mpz_poly_factor_list_init(ddfs);
4154 mpz_poly_factor_list_init(edfs);
4155
4156 mpz_poly_factor_list_flush(lf);
4157
4158 int maxmult = mpz_poly_factor_sqf (sqfs, f, p);
4159 for(int m = 1 ; m <= maxmult ; m++) {
4160 ASSERT_ALWAYS(sqfs->factors[m]->f->deg >= 0);
4161 if (sqfs->factors[m]->f->deg == 0) continue;
4162 int maxdeg = mpz_poly_factor_ddf(ddfs, sqfs->factors[m]->f, p);
4163 for(int k = 1 ; k <= maxdeg ; k++) {
4164 ASSERT_ALWAYS(ddfs->factors[k]->f->deg >= 0);
4165 if(ddfs->factors[k]->f->deg == 0) continue;
4166 mpz_poly_factor_edf(edfs, ddfs->factors[k]->f, k, p, rstate);
4167 for(int j = 0 ; j < edfs->size ; j++) {
4168 /* register this factor, with multiplicity m */
4169 /* cheat a bit... */
4170 mpz_poly_factor_list_prepare_write(lf, lf->size);
4171 mpz_poly_swap(lf->factors[lf->size-1]->f, edfs->factors[j]->f);
4172 mpz_poly_makemonic_mod_mpz(lf->factors[lf->size-1]->f, lf->factors[lf->size-1]->f, p);
4173 lf->factors[lf->size-1]->m = m;
4174 }
4175 }
4176 }
4177 mpz_poly_factor_list_clear(edfs);
4178 mpz_poly_factor_list_clear(ddfs);
4179 mpz_poly_factor_list_clear(sqfs);
4180
4181 /* sort factors by degree and lexicographically */
4182 qsort(lf->factors, lf->size, sizeof(mpz_poly_with_m), (sortfunc_t) &mpz_poly_with_m_cmp);
4183
4184 return lf->size;
4185 }
4186
mpz_poly_number_of_real_roots(mpz_poly_srcptr f)4187 int mpz_poly_number_of_real_roots(mpz_poly_srcptr f)
4188 {
4189 /* This is coded in usp.c, with an interface pretty different from
4190 * what we have here.
4191 *
4192 * 0.0 in usp.c means: find a bound by yourself.
4193 */
4194 return numberOfRealRoots(f->coeff, f->deg, 0.0, 0, NULL);
4195 }
4196
mpz_poly_factor_list_lift(mpz_poly_factor_list_ptr fac,mpz_poly_srcptr f,mpz_srcptr ell,mpz_srcptr ell2)4197 int mpz_poly_factor_list_lift(mpz_poly_factor_list_ptr fac, mpz_poly_srcptr f, mpz_srcptr ell, mpz_srcptr ell2)
4198 {
4199 mpz_poly f1; /* f - the product of its factors mod ell */
4200
4201 mpz_poly_init(f1, -1);
4202 mpz_poly_set(f1, f);
4203
4204 /* Lift all factors. Take g0 h0 unitary, g1 h1 of lesser
4205 * degree.
4206 * want (g0+ell*g1) * (h0 + ell*h1) = f
4207 * g1 * h0 + h1 * g0 = f1 = (f - g0 * h0) / ell
4208 *
4209 * say a*g0 + b*h0 = 1
4210 *
4211 * a*f1 = a*g1*h0+a*h1*g0 = h1 mod h0
4212 * b*f1 = b*g1*h0+b*h1*g0 = g1 mod g0
4213 *
4214 */
4215 mpz_poly_set_xi(f1, 0);
4216 for(int i = 0 ; i < fac->size ; i++) {
4217 mpz_poly_srcptr g0 = fac->factors[i]->f;
4218 mpz_poly_mul_mod_f_mod_mpz(f1, f1, g0, 0, ell2, NULL, NULL);
4219 }
4220 mpz_poly_sub_mod_mpz(f1, f, f1, ell2);
4221 mpz_poly_divexact_mpz(f1, f1, ell);
4222
4223 for(int i = 0 ; i < fac->size ; i++) {
4224 mpz_poly g1, d, a, b, h0;
4225 mpz_poly_ptr g = fac->factors[i]->f;
4226 mpz_poly_srcptr g0 = g; /* alias */
4227 mpz_poly_init(g1, g0->deg - 1);
4228 mpz_poly_init(h0, f->deg - g0->deg);
4229 mpz_poly_init(d, 0);
4230 mpz_poly_init(a, f->deg - g0->deg - 1);
4231 mpz_poly_init(b, g0->deg - 1);
4232 if (fac->factors[i]->m != 1) {
4233 fprintf(stderr, "Ramified ell not supported\n");
4234 exit(EXIT_FAILURE);
4235 }
4236 ASSERT_ALWAYS(mpz_cmp_ui(mpz_poly_lc(g), 1) == 0);
4237 /* compute h0 = product of other factors */
4238 mpz_poly_divexact(h0, f, g0, ell);
4239
4240 /* say a*g0 + b*h0 = 1 */
4241 mpz_poly_xgcd_mpz(d, g0, h0, a, b, ell);
4242 ASSERT_ALWAYS(d->deg == 0);
4243 ASSERT_ALWAYS(mpz_cmp_ui(d->coeff[0], 1) == 0);
4244
4245 /* b*f1 = b*g1*h0+b*h1*g0 = g1 mod g0 */
4246 mpz_poly_mul_mod_f_mod_mpz(g1, f1, b, g0, ell, NULL, NULL);
4247
4248 /* now update g */
4249 mpz_poly_mul_mpz(g1, g1, ell);
4250 mpz_poly_add(g, g, g1);
4251
4252 mpz_poly_clear(g1);
4253 mpz_poly_clear(a);
4254 mpz_poly_clear(b);
4255 mpz_poly_clear(d);
4256 mpz_poly_clear(h0);
4257 }
4258
4259 mpz_poly_clear(f1);
4260
4261 return 1;
4262 }
4263
mpz_poly_factor_and_lift_padically(mpz_poly_factor_list_ptr fac,mpz_poly_srcptr f,mpz_srcptr ell,int prec,gmp_randstate_t rstate)4264 int mpz_poly_factor_and_lift_padically(mpz_poly_factor_list_ptr fac, mpz_poly_srcptr f, mpz_srcptr ell, int prec, gmp_randstate_t rstate)
4265 {
4266 // this is a false positive
4267 // coverity[exception_thrown]
4268 ASSERT_ALWAYS(mpz_cmp_ui(mpz_poly_lc(f), 1) == 0);
4269
4270 mpz_poly_factor(fac, f, ell, rstate);
4271 mpz_t ellx;
4272 mpz_init_set(ellx, ell);
4273
4274 /* keep for a rainy day: compute the list of prime powers we want to
4275 * pass by. (the mpz_poly_factor_list_lift function is happy to take
4276 * ell^m and ell^n, with n being 2m or 2m-1). */
4277 ASSERT_ALWAYS(prec == 2);
4278 mpz_mul(ellx, ell, ell);
4279 mpz_poly_factor_list_lift(fac, f, ell, ellx);
4280 mpz_clear(ellx);
4281
4282 return 1;
4283 }
4284
print_poly(std::string const & var) const4285 std::string cxx_mpz_poly::print_poly(std::string const& var) const
4286 {
4287 std::ostringstream os;
4288 if (x->deg < 0) os << "0";
4289 for(int i = 0 ; i <= x->deg ; i++) {
4290 int r = mpz_cmp_ui(x->coeff[i], 0);
4291 if (r == 0) continue;
4292 if (r > 0 && os.str().size())
4293 os << "+";
4294 if (i == 0) {
4295 os << x->coeff[i];
4296 } else {
4297 if (mpz_cmp_ui(x->coeff[i], -1) == 0) {
4298 os << "-";
4299 } else if (mpz_cmp_ui(x->coeff[i], 1) != 0) {
4300 os << x->coeff[i] << "*";
4301 }
4302 os << var;
4303 if (i > 1) os << "^" << i;
4304 }
4305
4306 }
4307 return os.str();
4308 }
4309
4310 /* functions for Joux--Lercier and Generalized Joux--Lercier */
4311 /**
4312 * \brief set the (mpz_t) coefficients of f from ::counter
4313 * \param[out] f polynomial
4314 * \param[out] max_abs_coeffs largest absolute value of coefficients of f
4315 * \param[out] next_counter the next counter to try after the present one, larger than counter+1 sometimes
4316 * \param[in] counter counter storing the coefficients of f
4317 * \param[in] bound max absolute value of coefficients of f
4318 *
4319 * \return 1 if the poly is valid (content = 1, not a duplicate, and +/-1 is not a root)
4320 * (in fact the value returned is != 0) and in this case,
4321 * max_abs_coeffs is set to the largest absolute value of the coefficients of f
4322 * \return 0 if the poly corresponding to the counter is a duplicate, and in that case,
4323 * max_abs_coeffs is set to an error_code (poly duplicate, +/- 1 root, content != 1...)
4324 *
4325 * Given ::counter, compute the coefficients of ::f.
4326 * Assume that the leading coefficient of f is > 0, the next one is >= 0, and the last one is not 0
4327 * 1 <= f[deg] <= bound
4328 * 0 <= f[deg-1] <= bound
4329 * -bound <= f[i] <= bound for 0 < i < deg-1
4330 * no other test is made: you need to check after if the poly is square-free, irreducible, etc.
4331 */
mpz_poly_setcoeffs_counter(mpz_poly_ptr f,int * max_abs_coeffs,unsigned long * next_counter,int deg,unsigned long counter,unsigned int bound)4332 int mpz_poly_setcoeffs_counter(mpz_poly_ptr f, int* max_abs_coeffs, unsigned long *next_counter, int deg, unsigned long counter, unsigned int bound){
4333 unsigned int i;
4334 unsigned long idx = counter;
4335 int j;
4336 int *fint, ok = 1;
4337 //unsigned long idx_next_poly_ok = idx;
4338 int error_code = 0; // because I want to know what is the pb
4339 #define POLY_EQUIV_INV_X -1 // the poly is the same as (+/-)f(1/x)
4340 #define POLY_EQUIV_MINUS_X -2 // the poly is the same as (+/-)f(-x)
4341 #define POLY_EQUIV_MINUS_COEFFS -3
4342 #define POLY_ROOT_ONE -4
4343 #define POLY_ROOT_MINUS_ONE -5
4344 #define POLY_CONTENT -6
4345
4346 fint = (int *) malloc ((deg + 1)*sizeof(int));
4347 // by default the next counter is counter+1
4348 *next_counter = counter+1;
4349
4350 /* compute polynomial f and fint of index idx */
4351 /* assume that f was already initialized with mpz_poly_init(f, deg) */
4352 f->deg = deg;
4353
4354 /* we take 1 <= f[deg] <= bound */
4355 fint[deg] = 1 + (idx % bound);
4356 idx = idx / bound;
4357 /* we take 0 <= f[deg-1] <= bound */
4358 fint[deg-1] = idx % (bound + 1);
4359 idx = idx / (bound + 1);
4360 for (i = deg-2; i > 0; i --)
4361 {
4362 /* we take -bound <= f[i] <= bound */
4363 fint[i] = (idx % (2 * bound + 1)) - bound;
4364 idx = idx / (2 * bound + 1);
4365 }
4366
4367 /* we take -bound <= f[0] <= bound, f[0] <> 0,
4368 which makes 2*bound possible values */
4369 ASSERT(idx < 2 * bound);
4370 fint[0] = (idx < bound) ? idx - bound : idx - (bound - 1);
4371
4372 /* since f and the reversed polynomial are equivalent, we can assume
4373 |f[deg]| < |f[0]| or (|f[deg]| = |f[0]| and |f[deg-1]| < |f[1]|) or ... */
4374
4375 /* other point of view
4376 ok = 1;
4377 j = 0;
4378 while ((abs(fint[deg-j]) == abs(fint[j])) && (2*j < deg)){
4379 j++;
4380 }
4381 ok = ((j*2 >= deg) || (abs(fint[deg-j]) < abs(fint[j])));
4382 */
4383 ok = 1;
4384 /* out of the 85176 raw polynomials of degree 4 for bound=6,
4385 the following test discards 41106, i.e., about 48% */
4386 for (int i = 0; 2 * i < deg; i++)
4387 {
4388 if (abs(fint[deg-i]) != abs(fint[i]))
4389 {
4390 /* we want |f[deg-i]| < |f[i]| */
4391 ok = abs(fint[deg-i]) < abs(fint[i]);
4392 break;
4393 }
4394 }
4395 if(!ok){
4396 error_code = POLY_EQUIV_INV_X; // the poly is an equivalent to (+/-)x^d*f(1/x)
4397 }
4398 if(abs(fint[deg]) >= abs(fint[0]) && (bound > 1)){
4399 // next valid poly: the next one is an increment of the leading coefficient.
4400 // but either leading coeff = |constant coeff|, and incrementing by one will lead to
4401 // leading coeff > |constant coeff|, and this is not a valid poly,
4402 // or we already are in the case:
4403 // leading coeff > |constant coeff|. In both cases,
4404 // since the leading coefficient is > 0, it means:
4405 // set the leading coeff to 1 and increment the next coefficient.
4406 *next_counter = counter - (counter % bound) + bound;
4407 // then, what if f[0] = +/- 1?
4408 if(abs(fint[0]) == 1){
4409 // means that setting ld=1 might not be enough: what if f[d-1] > |f[1]| now ?
4410 // in that case, counter++ is not enough because f[d]=1 is the only possibility,
4411 // so the next counter we are looking for is with f[d-1]++
4412 if(abs(fint[deg-1]+1) > abs(fint[1])){
4413 unsigned long mod_j, mod_k;
4414 // setting ld=1 then incrementing the second high deg coeff is not enough
4415 idx = *next_counter;
4416 // set the second high deg coeff to 0
4417 *next_counter = idx - (idx % (bound*(bound+1))) + (idx % bound);
4418 // and increment the third high deg coeff
4419 *next_counter += bound*(bound+1);
4420 j = 2;
4421 mod_j = bound*(bound+1)*(2*bound+1);
4422 mod_k = mod_j*(2*bound+1);
4423 while ((deg-j > j) && (fint[j-1] == 0)) {
4424 //setting the deg-j+1 coeff to 0 and incrementing the next deg-j coeff migh not be enough
4425 if (abs(fint[deg-j]+1) > abs(fint[j])){
4426 if ((fint[deg-j]+1) < fint[j]){// negative values
4427 //set fint[deg-j] to fint[j]
4428 idx = *next_counter;
4429 *next_counter = idx - (idx % mod_j) + (-abs(fint[j])+bound)*mod_j;
4430 }else{//(fint[deg-j]+1) is too large anyway: set it to its minimal value which is -|fint[j]| and do fint[d-j-1]++
4431 // set fint[deg-j] to -|fint[j]| and
4432 // fint[deg-j-1]++
4433 idx = *next_counter;
4434 *next_counter = idx - (idx % mod_j) + (-abs(fint[j])+bound)*mod_j + mod_k;
4435 }
4436 }
4437 j++;
4438 mod_j = mod_k;
4439 mod_k *= (2*bound+1);
4440 }// end while
4441 }
4442 }
4443 }// end of the computation of the next valid non-duplicate counter
4444
4445 /* Since f(x) is equivalent to (-1)^deg*f(-x), if f[deg-1] = 0, then the
4446 largest i = deg-3, deg-5, ..., such that f[i] <> 0 should have f[i] > 0.
4447 Out of the 44070 remaining polynomials for degree 4 and bound = 6, this test
4448 discards 3276, i.e., about 7.4% */
4449 if (ok && fint[deg-1] == 0)
4450 {
4451 for (int i = deg - 3; i >= 0; i -= 2)
4452 {
4453 if (fint[i])
4454 {
4455 ok = fint[i] > 0;
4456 break;
4457 }
4458 }
4459 }
4460 if((!ok) && (error_code == 0)){
4461 error_code = POLY_EQUIV_MINUS_X; // the poly is an equivalent to (-1)^deg*f(-x)
4462 }
4463
4464 /* If |f[i]| = |f[deg-i]| for all i, then [f[deg], f[deg-1], ..., f[1], f[0]]
4465 is equivalent to [s*f[0], s*t*f[1], s*t^2*f[2], ...], where
4466 s = sign(f[0]), and s*t^i is the sign of f[i] where i is the smallest
4467 odd index > 0 such that f[i] <> 0.
4468 Out of the 40794 remaining polynomials for degree 4 and bound = 6, this test
4469 discards 468, i.e., about 1.1% */
4470 if (ok && fint[deg] == abs(fint[0])) /* f[deg] > 0 */
4471 {
4472 int s = (fint[0] > 0) ? 1 : -1, t = 0, i;
4473 for (i = 1; i <= deg; i++)
4474 {
4475 if (2 * i < deg && abs(fint[deg-i]) != abs(fint[i]))
4476 break;
4477 if (t == 0 && fint[i] != 0 && (i & 1))
4478 t = (fint[i] > 0) ? s : -s;
4479 }
4480 if (2 * i >= deg) /* |f[i]| = |f[deg-i]| for all i */
4481 {
4482 /* if t=0, then all odd coefficients are zero, but since
4483 |f[deg-i]| = |f[i]| this can only occur for deg even, but then
4484 we can set t to 1, since t only affects the odd coefficients */
4485 if (t == 0)
4486 t = 1;
4487 for (i = 0; i <= deg; i++)
4488 {
4489 if (fint[deg-i] != s * fint[i])
4490 {
4491 ok = fint[deg-i] > s * fint[i];
4492 break;
4493 }
4494 s = s * t;
4495 }
4496 }
4497 }
4498 if((!ok) && (error_code == 0)){
4499 error_code = POLY_EQUIV_MINUS_COEFFS;
4500 }
4501
4502 /* Out of the 40326 remaining polynomials for degree 4 and bound = 6, this test
4503 discards 3480, i.e., about 8.6% */
4504 if (ok){
4505 /* check if +-1 is a root of f (very common): compute the sum of the coefficients, and the alterned sum: it should be != 0 */
4506 // evaluating at 1 means sum the coefficients
4507 int sum_even_coeffs = 0;
4508 int sum_odd_coeffs = 0;
4509 for(j=0; j<=deg; j += 2){
4510 sum_even_coeffs += fint[j];
4511 }
4512 for(j=1; j<=deg; j += 2){
4513 sum_odd_coeffs += fint[j];
4514 }
4515 ok = (sum_even_coeffs + sum_odd_coeffs) != 0;
4516 if (!ok){
4517 error_code = POLY_ROOT_ONE;
4518 }else{// eval at -1: alterning sum of coefficients
4519 ok = (sum_even_coeffs - sum_odd_coeffs) != 0;
4520 if (!ok){
4521 error_code = POLY_ROOT_MINUS_ONE;
4522 }
4523 }
4524 }
4525
4526 /* set mpz_poly */
4527 f->deg = deg;
4528 for (j = 0; j <= deg; j ++)
4529 mpz_set_si (f->coeff[j], fint[j]);
4530
4531 /* Out of the 36846 remaining polynomials for degree 4 and bound = 6, this test
4532 discards 1640, i.e., about 4.5% */
4533 if (ok){
4534 /* content test */
4535 mpz_t content;
4536 mpz_init (content);
4537 mpz_poly_content (content, f);
4538 ok = mpz_cmp_ui (content, 1) == 0; /* duplicate with f/t */
4539 if (ok == 0){
4540 error_code = POLY_CONTENT;
4541 }
4542 mpz_clear (content);
4543 }
4544
4545 // compute the max absolute value of coefficients,
4546 // usefull for computing the lognorm after
4547 if(ok){
4548 *max_abs_coeffs = fint[0]; // this is positive anyway
4549 for(j=0; j <= deg; j++){
4550 if ((fint[j] < 0) && (*max_abs_coeffs < -fint[j])){
4551 *max_abs_coeffs = -fint[j];
4552 }else{// fint[i] >= 0
4553 if (*max_abs_coeffs < fint[j]){
4554 *max_abs_coeffs = fint[j];
4555 }
4556 }
4557 }
4558 }else{
4559 *max_abs_coeffs = error_code;
4560 }
4561
4562 free(fint);
4563 return ok;
4564
4565 #undef POLY_EQUIV_INV_X
4566 #undef POLY_EQUIV_MINUS_X
4567 #undef POLY_EQUIV_MINUS_COEFFS
4568 #undef POLY_ROOT_ONE
4569 #undef POLY_ROOT_MINUS_ONE
4570 #undef POLY_CONTENT
4571 }
4572
4573 /**
4574 return the total number of polys f that satisfy:
4575 deg(f) = deg exactly (leading coefficient != 0)
4576 |f_i| <= bound: the coefficients are bounded by bound
4577 f_deg > 0: leading coeff strictly positive
4578 f_{deg-1} > 0
4579 f_0 != 0: constant coeff non-zero
4580
4581 This corresponds to the number of polynomials that can be enumerated with the function
4582 mpz_poly_setcoeffs_counter
4583 */
mpz_poly_cardinality(int deg,unsigned int bound)4584 unsigned long mpz_poly_cardinality(int deg, unsigned int bound){
4585 /* we take 1 <= f[d] <= bound */
4586 /* we take 0 <= f[d-1] <= bound */
4587 /* we take -bound <= f[i] <= bound for d-2 >= i > 0 */
4588 /* we take -bound <= f[0] < bound, f[0] <> 0,
4589 which makes 2*bound possible values */
4590 unsigned long number_polys=0;
4591 int i;
4592 if(deg >= 3){
4593 number_polys = bound*(bound+1);
4594 for (i = deg-2; i > 0; i --){
4595 number_polys *= 2*bound + 1;
4596 }
4597 number_polys *= 2*bound;
4598 }
4599 return number_polys;
4600 }
4601
4602 /**
4603 * return the counter in basis ::bound corresponding to f
4604 *
4605 */
mpz_poly_getcounter(mpz_poly_ptr f,unsigned int bound)4606 unsigned long mpz_poly_getcounter(mpz_poly_ptr f, unsigned int bound){
4607 unsigned int counter;
4608 int i;
4609 // leading coeff: 1 <= f->coeff[deg] <= bound
4610 counter = mpz_get_ui(f->coeff[f->deg]);
4611 counter *= bound;
4612 // next leading coeff: 0 <= f->coeff[deg-1] <= bound
4613 counter += mpz_get_ui(f->coeff[f->deg -1]);
4614 counter *= (bound+1);
4615 // next coeffs: -bound <= f->coeff[i] <= bound
4616 for(i=f->deg-2; i > 0; i--){
4617 counter += mpz_get_si(f->coeff[i]) + bound;
4618 counter *= 2*bound + 1;
4619 }
4620 if(mpz_sgn(f->coeff[0]) < 0){
4621 counter += mpz_get_si(f->coeff[0]) + bound;
4622 }else{// f->coeff[0] > 0
4623 counter += mpz_get_ui(f->coeff[0]) + bound - 1;
4624 }
4625 return counter;
4626 }
4627
mpz_poly_setcoeffs_counter_print_error_code(int error_code)4628 void mpz_poly_setcoeffs_counter_print_error_code(int error_code){
4629 switch(error_code){
4630 case -1: printf("-1: f <-> +/- x^d f(1/x) \n"); break;
4631 case -2: printf("-2: f <-> +/- f(-x) \n"); break;
4632 case -3: printf("-3: f <-> another one with permuted/sign coeffs\n"); break;
4633 case -4: printf("-4: f(1) = 0\n"); break;
4634 case -5: printf("-5: f(-1) = 0\n"); break;
4635 case -6: printf("-6: content(f) > 1\n"); break;
4636 default: printf(" 0: undetermined error.\n");
4637 }
4638 }
4639
4640
4641 /* TODO: I wonder whether this could be expanded to do the parsing of the
4642 * fantastic galois actions that we have here and there... */
4643
4644 /* This structure has only two public functions: tokenize and parse */
4645 struct poly_parser {
4646
4647 struct parse_error: public std::exception {
whatpoly_parser::parse_error4648 const char * what() const noexcept override { return "parse error"; }
4649 };
4650
4651 private:
4652 enum expression_token {
4653 LEFT_PAREN,
4654 RIGHT_PAREN,
4655 PLUS,
4656 MINUS,
4657 TIMES,
4658 POWER,
4659 POSITIVE_INTEGER,
4660 LITERAL
4661 };
4662 std::vector<expression_token> tokens;
4663 std::vector<char> literals;
4664 std::vector<cxx_mpz> integers;
4665
4666 std::vector<expression_token>::const_iterator ctok;
4667 std::vector<char>::const_iterator clit;
4668 std::vector<cxx_mpz>::const_iterator cint;
4669
nextpoly_parser4670 inline void next() { if (ctok != tokens.end()) ctok++; }
testpoly_parser4671 inline bool test(expression_token s) { return ctok != tokens.end() && *ctok == s; }
4672
acceptpoly_parser4673 bool accept(expression_token s) {
4674 if (!test(s)) return false;
4675 next();
4676 return true;
4677 }
4678
expectpoly_parser4679 int expect(expression_token s) {
4680 if (accept(s))
4681 return 1;
4682 throw parse_error();
4683 return 0;
4684 }
4685
exponentpoly_parser4686 unsigned long exponent() {
4687 if (accept(POWER)) {
4688 expect(POSITIVE_INTEGER);
4689 cxx_mpz e = *cint++;
4690 while (accept(POWER)) {
4691 expect(POSITIVE_INTEGER);
4692 if (!mpz_fits_ulong_p(*cint)) throw parse_error();
4693 unsigned long ei = mpz_get_ui(*cint++);
4694 mpz_pow_ui(e, e, ei);
4695 }
4696 if (!mpz_fits_ulong_p(e)) throw parse_error();
4697 return mpz_get_ui(e);
4698 } else {
4699 return 1;
4700 }
4701 }
4702
parse_factorpoly_parser4703 cxx_mpz_poly parse_factor() {
4704 cxx_mpz_poly p;
4705 if (accept(LITERAL)) {
4706 clit++;
4707 mpz_poly_set_xi(p, exponent());
4708 } else if (accept(POSITIVE_INTEGER)) {
4709 mpz_poly_set_mpz(p, *cint++);
4710 } else if (accept(LEFT_PAREN)) {
4711 mpz_poly_swap(p, parse_expression());
4712 expect(RIGHT_PAREN);
4713 } else {
4714 throw parse_error();
4715 }
4716 unsigned long e = exponent();
4717 if (e != 1)
4718 mpz_poly_pow_ui(p, p, e);
4719 return p;
4720 }
4721
parse_termpoly_parser4722 cxx_mpz_poly parse_term() {
4723 cxx_mpz_poly p = parse_factor();
4724 for( ; accept(TIMES) ; )
4725 mpz_poly_mul(p, p, parse_factor());
4726 return p;
4727 }
4728
parse_expressionpoly_parser4729 cxx_mpz_poly parse_expression() {
4730 cxx_mpz_poly p;
4731 if (test(PLUS)) {
4732 next();
4733 p = parse_term();
4734 } else if (!test(MINUS)) {
4735 p = parse_term();
4736 }
4737
4738 for(;;) {
4739 if (test(PLUS)) {
4740 next();
4741 mpz_poly_add(p, p, parse_term());
4742 } else if (test(MINUS)) {
4743 next();
4744 mpz_poly_sub(p, p, parse_term());
4745 } else
4746 break;
4747 }
4748 return p;
4749 }
4750 public:
parsepoly_parser4751 cxx_mpz_poly parse() {
4752 for(auto const & l : literals)
4753 if (l != literals.front()) throw parse_error();
4754 cxx_mpz_poly p = parse_expression();
4755 if (ctok != tokens.end())
4756 throw parse_error();
4757 return p;
4758 }
4759
tokenizepoly_parser4760 bool tokenize(std::istream& is) {
4761 tokens.clear();
4762 literals.clear();
4763 integers.clear();
4764 for( ; !is.eof() ; ) {
4765 int c;
4766 for(;;is.get()) {
4767 c = is.peek();
4768 if (is.eof() || !isspace(c)) break;
4769 }
4770 /* c is the next non-whitespace character */
4771 if (is.eof()) { break;
4772 } else if (c == '+') { is.get(); tokens.push_back(PLUS);
4773 } else if (c == '-') { is.get(); tokens.push_back(MINUS);
4774 } else if (c == '*') { is.get(); tokens.push_back(TIMES);
4775 } else if (c == '(') { is.get(); tokens.push_back(LEFT_PAREN);
4776 } else if (c == ')') { is.get(); tokens.push_back(RIGHT_PAREN);
4777 } else if (c == '^') { is.get(); tokens.push_back(POWER);
4778 } else if (isdigit(c)) {
4779 /* gmp's mpz parser really wants only an mpz, nothing
4780 * else. We have to collect digits first.
4781 */
4782 std::string s;
4783 for(;!is.eof() && isdigit(c);is.get(), c=is.peek()) {
4784 s += c;
4785 }
4786 cxx_mpz z;
4787 mpz_set_str(z, s.c_str(), 0);
4788
4789 integers.push_back(z);
4790 tokens.push_back(POSITIVE_INTEGER);
4791 } else if (isalpha(c)) {
4792 is.get();
4793 literals.push_back(c);
4794 tokens.push_back(LITERAL);
4795 }
4796 };
4797 ctok = tokens.begin();
4798 clit = literals.begin();
4799 cint = integers.begin();
4800 return true;
4801 }
4802 };
4803
operator >>(std::istream & in,cxx_mpz_poly & f)4804 std::istream& operator>>(std::istream& in, cxx_mpz_poly & f)
4805 {
4806 std::string line;
4807 for(;;in.get()) {
4808 int c = in.peek();
4809 if (in.eof() || !isspace(c)) break;
4810 }
4811 if (!getline(in, line)) return in;
4812 std::istringstream is(line);
4813
4814 poly_parser P;
4815 P.tokenize(is);
4816
4817 try {
4818 f = P.parse();
4819 } catch (poly_parser::parse_error const & p) {
4820 in.setstate(std::ios_base::failbit);
4821 return in;
4822 }
4823
4824 return in;
4825 }
4826
operator <<(std::ostream & o,cxx_mpz_poly const & f)4827 std::ostream& operator<<(std::ostream& o, cxx_mpz_poly const & f) {
4828 return o << f.print_poly(std::string("x"));
4829 }
4830
4831 template struct mpz_poly_parallel_interface<mpz_poly_notparallel_info>;
4832 template struct mpz_poly_parallel_interface<mpz_poly_parallel_info>;
4833