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