1 /*
2     Copyright (C) 2018 Daniel Schultz
3 
4     This file is part of FLINT.
5 
6     FLINT is free software: you can redistribute it and/or modify it under
7     the terms of the GNU Lesser General Public License (LGPL) as published
8     by the Free Software Foundation; either version 2.1 of the License, or
9     (at your option) any later version.  See <http://www.gnu.org/licenses/>.
10 */
11 
12 #include "nmod_mpoly.h"
13 
14 
nmod_mpolyu_init(nmod_mpolyu_t A,flint_bitcnt_t bits,const nmod_mpoly_ctx_t ctx)15 void nmod_mpolyu_init(nmod_mpolyu_t A, flint_bitcnt_t bits,
16                                                     const nmod_mpoly_ctx_t ctx)
17 {
18     A->coeffs = NULL;
19     A->exps = NULL;
20     A->alloc = 0;
21     A->length = 0;
22     A->bits = bits;
23 }
24 
25 
nmod_mpolyu_clear(nmod_mpolyu_t A,const nmod_mpoly_ctx_t uctx)26 void nmod_mpolyu_clear(nmod_mpolyu_t A, const nmod_mpoly_ctx_t uctx)
27 {
28     slong i;
29     for (i = 0; i < A->alloc; i++)
30         nmod_mpoly_clear(A->coeffs + i, uctx);
31     flint_free(A->coeffs);
32     flint_free(A->exps);
33 }
34 
35 
nmod_mpolyu_swap(nmod_mpolyu_t A,nmod_mpolyu_t B,const nmod_mpoly_ctx_t uctx)36 void nmod_mpolyu_swap(nmod_mpolyu_t A, nmod_mpolyu_t B,
37                                                    const nmod_mpoly_ctx_t uctx)
38 {
39    nmod_mpolyu_struct t = *A;
40    *A = *B;
41    *B = t;
42 }
43 
nmod_mpolyu_zero(nmod_mpolyu_t A,const nmod_mpoly_ctx_t uctx)44 void nmod_mpolyu_zero(nmod_mpolyu_t A, const nmod_mpoly_ctx_t uctx)
45 {
46     A->length = 0;
47 }
48 
nmod_mpolyu_is_one(nmod_mpolyu_t A,const nmod_mpoly_ctx_t uctx)49 int nmod_mpolyu_is_one(nmod_mpolyu_t A, const nmod_mpoly_ctx_t uctx)
50 {
51     if (A->length != 1 || A->exps[0] != UWORD(0))
52         return 0;
53 
54     return nmod_mpoly_is_one(A->coeffs + 0, uctx);
55 }
56 
nmod_mpolyu_print_pretty(const nmod_mpolyu_t poly,const char ** x,const nmod_mpoly_ctx_t ctx)57 void nmod_mpolyu_print_pretty(const nmod_mpolyu_t poly,
58                                    const char ** x, const nmod_mpoly_ctx_t ctx)
59 {
60     slong i;
61     if (poly->length == 0)
62         flint_printf("0");
63     for (i = 0; i < poly->length; i++)
64     {
65         if (i != 0)
66             flint_printf(" + ");
67         flint_printf("(");
68         nmod_mpoly_print_pretty(poly->coeffs + i,x,ctx);
69         flint_printf(")*X^%wd",poly->exps[i]);
70     }
71 }
72 
nmod_mpolyu_fit_length(nmod_mpolyu_t A,slong length,const nmod_mpoly_ctx_t uctx)73 void nmod_mpolyu_fit_length(nmod_mpolyu_t A, slong length,
74                                                    const nmod_mpoly_ctx_t uctx)
75 {
76     slong i;
77     slong old_alloc = A->alloc;
78     slong new_alloc = FLINT_MAX(length, 2*A->alloc);
79 
80     if (length > old_alloc)
81     {
82         if (old_alloc == 0)
83         {
84             A->exps = (ulong *) flint_malloc(new_alloc*sizeof(ulong));
85             A->coeffs = (nmod_mpoly_struct *) flint_malloc(
86                                           new_alloc*sizeof(nmod_mpoly_struct));
87         } else
88         {
89             A->exps = (ulong *) flint_realloc(A->exps,
90                                                       new_alloc*sizeof(ulong));
91             A->coeffs = (nmod_mpoly_struct *) flint_realloc(A->coeffs,
92                                           new_alloc*sizeof(nmod_mpoly_struct));
93         }
94 
95         for (i = old_alloc; i < new_alloc; i++)
96         {
97             nmod_mpoly_init(A->coeffs + i, uctx);
98             nmod_mpoly_fit_bits(A->coeffs + i, A->bits, uctx);
99             (A->coeffs + i)->bits = A->bits;
100         }
101         A->alloc = new_alloc;
102     }
103 }
104 
nmod_mpolyu_one(nmod_mpolyu_t A,const nmod_mpoly_ctx_t uctx)105 void nmod_mpolyu_one(nmod_mpolyu_t A, const nmod_mpoly_ctx_t uctx)
106 {
107     nmod_mpolyu_fit_length(A, WORD(1), uctx);
108     A->exps[0] = UWORD(0);
109     nmod_mpoly_one(A->coeffs + 0, uctx);
110     A->length = WORD(1);
111 }
112 
113 /* if the coefficient doesn't exist, a new one is created (and set to zero) */
_nmod_mpolyu_get_coeff(nmod_mpolyu_t A,ulong pow,const nmod_mpoly_ctx_t uctx)114 nmod_mpoly_struct * _nmod_mpolyu_get_coeff(nmod_mpolyu_t A,
115                                         ulong pow, const nmod_mpoly_ctx_t uctx)
116 {
117     slong i, j;
118     nmod_mpoly_struct * xk;
119 
120     for (i = 0; i < A->length && A->exps[i] >= pow; i++)
121     {
122         if (A->exps[i] == pow)
123         {
124             return A->coeffs + i;
125         }
126     }
127 
128     nmod_mpolyu_fit_length(A, A->length + 1, uctx);
129 
130     for (j = A->length; j > i; j--)
131     {
132         A->exps[j] = A->exps[j - 1];
133         nmod_mpoly_swap(A->coeffs + j, A->coeffs + j - 1, uctx);
134     }
135 
136     A->length++;
137     A->exps[i] = pow;
138     xk = A->coeffs + i;
139     xk->length = 0;
140     FLINT_ASSERT(xk->bits == A->bits);
141 
142     return xk;
143 }
144 
145 
146 typedef struct
147 {
148     volatile slong index;
149 #if HAVE_PTHREAD
150     pthread_mutex_t mutex;
151 #endif
152     slong length;
153     nmod_mpoly_struct * coeffs;
154     const nmod_mpoly_ctx_struct * ctx;
155 }
156 _sort_arg_struct;
157 
158 typedef _sort_arg_struct _sort_arg_t[1];
159 
160 
_worker_sort(void * varg)161 static void _worker_sort(void * varg)
162 {
163     _sort_arg_struct * arg = (_sort_arg_struct *) varg;
164     slong i;
165 
166 get_next_index:
167 
168 #if HAVE_PTHREAD
169     pthread_mutex_lock(&arg->mutex);
170 #endif
171     i = arg->index;
172     arg->index++;
173 #if HAVE_PTHREAD
174     pthread_mutex_unlock(&arg->mutex);
175 #endif
176 
177     if (i >= arg->length)
178         goto cleanup;
179 
180     nmod_mpoly_sort_terms(arg->coeffs + i, arg->ctx);
181 
182     goto get_next_index;
183 
184 cleanup:
185 
186     return;
187 }
188 
189 /*
190     Convert B to A using the variable permutation perm.
191     The uctx (m vars) should be the context of the coefficients of A.
192     The ctx (n vars) should be the context of B.
193 
194     operation on each term:
195 
196     for 0 <= k < m + 1
197         l = perm[k]
198         Aexp[k] = (Bexp[l] - shift[l])/stride[l]
199 
200     the most significant main variable uses k = 0
201     the coefficients of A use variables k = 1 ... m
202 */
nmod_mpoly_to_mpolyu_perm_deflate_threaded_pool(nmod_mpolyu_t A,const nmod_mpoly_ctx_t uctx,const nmod_mpoly_t B,const nmod_mpoly_ctx_t ctx,const slong * perm,const ulong * shift,const ulong * stride,const thread_pool_handle * handles,slong num_handles)203 void nmod_mpoly_to_mpolyu_perm_deflate_threaded_pool(
204     nmod_mpolyu_t A,
205     const nmod_mpoly_ctx_t uctx,
206     const nmod_mpoly_t B,
207     const nmod_mpoly_ctx_t ctx,
208     const slong * perm,
209     const ulong * shift,
210     const ulong * stride,
211     const thread_pool_handle * handles,
212     slong num_handles)
213 {
214     slong i, j, k, l;
215     slong n = ctx->minfo->nvars;
216     slong m = uctx->minfo->nvars;
217     slong NA, NB;
218     ulong * uexps;
219     ulong * Bexps;
220     nmod_mpoly_struct * Ac;
221     TMP_INIT;
222 
223     FLINT_ASSERT(A->bits <= FLINT_BITS);
224     FLINT_ASSERT(B->bits <= FLINT_BITS);
225     FLINT_ASSERT(m + 1 <= n);
226 
227     TMP_START;
228 
229     uexps = (ulong *) TMP_ALLOC((m + 1)*sizeof(fmpz));
230     Bexps = (ulong *) TMP_ALLOC(n*sizeof(fmpz));
231 
232     nmod_mpolyu_zero(A, uctx);
233 
234     NA = mpoly_words_per_exp(A->bits, uctx->minfo);
235     NB = mpoly_words_per_exp(B->bits, ctx->minfo);
236 
237     for (j = 0; j < B->length; j++)
238     {
239         mpoly_get_monomial_ui(Bexps, B->exps + NB*j, B->bits, ctx->minfo);
240         for (k = 0; k < m + 1; k++)
241         {
242             l = perm[k];
243             FLINT_ASSERT(stride[l] != UWORD(0));
244             FLINT_ASSERT(((Bexps[l] - shift[l]) % stride[l]) == UWORD(0));
245             uexps[k] = (Bexps[l] - shift[l]) / stride[l];
246         }
247         Ac = _nmod_mpolyu_get_coeff(A, uexps[0], uctx);
248         FLINT_ASSERT(Ac->bits == A->bits);
249 
250         nmod_mpoly_fit_length(Ac, Ac->length + 1, uctx);
251         Ac->coeffs[Ac->length] = B->coeffs[j];
252         mpoly_set_monomial_ui(Ac->exps + NA*Ac->length, uexps + 1, A->bits, uctx->minfo);
253         Ac->length++;
254     }
255 
256     if (num_handles > 0)
257     {
258         _sort_arg_t arg;
259 
260 #if HAVE_PTHREAD
261 	pthread_mutex_init(&arg->mutex, NULL);
262 #endif
263 	arg->index = 0;
264         arg->coeffs = A->coeffs;
265         arg->length = A->length;
266         arg->ctx = uctx;
267 
268         for (i = 0; i < num_handles; i++)
269         {
270             thread_pool_wake(global_thread_pool, handles[i], 0, _worker_sort, arg);
271         }
272         _worker_sort(arg);
273         for (i = 0; i < num_handles; i++)
274         {
275             thread_pool_wait(global_thread_pool, handles[i]);
276         }
277 
278 #if HAVE_PTHREAD
279         pthread_mutex_destroy(&arg->mutex);
280 #endif
281     }
282     else
283     {
284         for (i = 0; i < A->length; i++)
285         {
286             nmod_mpoly_sort_terms(A->coeffs + i, uctx);
287         }
288     }
289 
290     TMP_END;
291 }
292 
293 /*
294     Convert B to A using the variable permutation vector perm.
295     This function inverts nmod_mpoly_to_mpolyu_perm_deflate.
296     A will be constructed with bits = Abits.
297 
298     operation on each term:
299 
300         for 0 <= l < n
301             Aexp[l] = shift[l]
302 
303         for 0 <= k < m + 1
304             l = perm[k]
305             Aexp[l] += scale[l]*Bexp[k]
306 */
nmod_mpoly_from_mpolyu_perm_inflate(nmod_mpoly_t A,flint_bitcnt_t Abits,const nmod_mpoly_ctx_t ctx,const nmod_mpolyu_t B,const nmod_mpoly_ctx_t uctx,const slong * perm,const ulong * shift,const ulong * stride)307 void nmod_mpoly_from_mpolyu_perm_inflate(
308     nmod_mpoly_t A, flint_bitcnt_t Abits,
309     const nmod_mpoly_ctx_t ctx,
310     const nmod_mpolyu_t B,
311     const nmod_mpoly_ctx_t uctx,
312     const slong * perm,
313     const ulong * shift,
314     const ulong * stride)
315 {
316     slong n = ctx->minfo->nvars;
317     slong m = uctx->minfo->nvars;
318     slong i, j, k, l;
319     slong NA, NB;
320     slong Alen;
321     mp_limb_t * Acoeff;
322     ulong * Aexp;
323     slong Aalloc;
324     ulong * uexps;
325     ulong * Aexps;
326     TMP_INIT;
327 
328     FLINT_ASSERT(B->length > 0);
329     FLINT_ASSERT(Abits <= FLINT_BITS);
330     FLINT_ASSERT(B->bits <= FLINT_BITS);
331     FLINT_ASSERT(m + 1 <= n);
332     TMP_START;
333 
334     uexps = (ulong *) TMP_ALLOC((m + 1)*sizeof(ulong));
335     Aexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
336 
337     NA = mpoly_words_per_exp(Abits, ctx->minfo);
338     NB = mpoly_words_per_exp(B->bits, uctx->minfo);
339 
340     nmod_mpoly_fit_bits(A, Abits, ctx);
341     A->bits = Abits;
342 
343     Acoeff = A->coeffs;
344     Aexp = A->exps;
345     Aalloc = A->alloc;
346     Alen = 0;
347     for (i = 0; i < B->length; i++)
348     {
349         nmod_mpoly_struct * Bc = B->coeffs + i;
350         _nmod_mpoly_fit_length(&Acoeff, &Aexp, &Aalloc, Alen + Bc->length, NA);
351         FLINT_ASSERT(Bc->bits == B->bits);
352 
353         for (j = 0; j < Bc->length; j++)
354         {
355             Acoeff[Alen + j] = Bc->coeffs[j];
356             mpoly_get_monomial_ui(uexps + 1, Bc->exps + NB*j, Bc->bits, uctx->minfo);
357             uexps[0] = B->exps[i];
358             for (l = 0; l < n; l++)
359             {
360                 Aexps[l] = shift[l];
361             }
362             for (k = 0; k < m + 1; k++)
363             {
364                 l = perm[k];
365                 Aexps[l] += stride[l]*uexps[k];
366             }
367             mpoly_set_monomial_ui(Aexp + NA*(Alen + j), Aexps, Abits, ctx->minfo);
368         }
369         Alen += Bc->length;
370     }
371     A->coeffs = Acoeff;
372     A->exps = Aexp;
373     A->alloc = Aalloc;
374     _nmod_mpoly_set_length(A, Alen, ctx);
375 
376     nmod_mpoly_sort_terms(A, ctx);
377     TMP_END;
378 }
379 
380 
nmod_mpolyu_shift_right(nmod_mpolyu_t A,ulong s)381 void nmod_mpolyu_shift_right(nmod_mpolyu_t A, ulong s)
382 {
383     slong i;
384     for (i = 0; i < A->length; i++)
385     {
386         FLINT_ASSERT(A->exps[i] >= s);
387         A->exps[i] -= s;
388     }
389 }
390 
nmod_mpolyu_shift_left(nmod_mpolyu_t A,ulong s)391 void nmod_mpolyu_shift_left(nmod_mpolyu_t A, ulong s)
392 {
393     slong i;
394     for (i = 0; i < A->length; i++)
395     {
396         A->exps[i] += s;
397     }
398 }
399 
nmod_mpolyu_scalar_mul_nmod(nmod_mpolyu_t A,mp_limb_t c,const nmod_mpoly_ctx_t ctx)400 void nmod_mpolyu_scalar_mul_nmod(nmod_mpolyu_t A, mp_limb_t c,
401                                                     const nmod_mpoly_ctx_t ctx)
402 {
403     slong i, j;
404 
405     for (i = 0; i < A->length; i++)
406     {
407         for (j = 0; j < (A->coeffs + i)->length; j++)
408         {
409             (A->coeffs + i)->coeffs[j] = nmod_mul((A->coeffs + i)->coeffs[j],
410                                                          c, ctx->ffinfo->mod);
411         }
412     }
413 }
414 
415 
nmod_mpolyu_set(nmod_mpolyu_t A,const nmod_mpolyu_t B,const nmod_mpoly_ctx_t uctx)416 void nmod_mpolyu_set(nmod_mpolyu_t A, const nmod_mpolyu_t B,
417                                                    const nmod_mpoly_ctx_t uctx)
418 {
419     slong i;
420     nmod_mpoly_struct * Acoeff, * Bcoeff;
421     ulong * Aexp, * Bexp;
422     slong Alen, Blen;
423 
424     Alen = 0;
425     Blen = B->length;
426     nmod_mpolyu_fit_length(A, Blen, uctx);
427     Acoeff = A->coeffs;
428     Bcoeff = B->coeffs;
429     Aexp = A->exps;
430     Bexp = B->exps;
431 
432     for (i = 0; i < Blen; i++)
433     {
434         nmod_mpoly_set(Acoeff + Alen, Bcoeff + i, uctx);
435         Aexp[Alen++] = Bexp[i];
436     }
437     Alen = Blen;
438 
439     /* demote remaining coefficients */
440     for (i = Alen; i < A->length; i++)
441     {
442         nmod_mpoly_clear(Acoeff + i, uctx);
443         nmod_mpoly_init(Acoeff + i, uctx);
444     }
445     A->length = Alen;
446 }
447 
448 
449 
nmod_mpoly_cvtfrom_poly_notmain(nmod_mpoly_t A,nmod_poly_t a,slong var,const nmod_mpoly_ctx_t ctx)450 void nmod_mpoly_cvtfrom_poly_notmain(nmod_mpoly_t A, nmod_poly_t a,
451                                          slong var, const nmod_mpoly_ctx_t ctx)
452 {
453     slong i;
454     slong k;
455     ulong * oneexp;
456     slong N;
457     TMP_INIT;
458     TMP_START;
459 
460     FLINT_ASSERT(A->bits <= FLINT_BITS);
461 
462     N = mpoly_words_per_exp_sp(A->bits, ctx->minfo);
463 
464     oneexp = (ulong *)TMP_ALLOC(N*sizeof(ulong));
465     mpoly_gen_monomial_sp(oneexp, var, A->bits, ctx->minfo);
466 
467     nmod_mpoly_fit_length(A, nmod_poly_length(a), ctx);
468 
469     k = 0;
470     for (i = nmod_poly_length(a) - 1; i >= 0; i--)
471     {
472         mp_limb_t c = nmod_poly_get_coeff_ui(a, i);
473         if (c != UWORD(0))
474         {
475             A->coeffs[k] = c;
476             mpoly_monomial_mul_ui(A->exps + N*k, oneexp, N, i);
477             k++;
478         }
479     }
480     A->length = k;
481     TMP_END;
482 }
483 /*
484     Set "A" to "a" where "a" is a polynomial in a non-main variable "var"
485 */
nmod_mpolyu_cvtfrom_poly_notmain(nmod_mpolyu_t A,nmod_poly_t a,slong var,const nmod_mpoly_ctx_t ctx)486 void nmod_mpolyu_cvtfrom_poly_notmain(nmod_mpolyu_t A, nmod_poly_t a,
487                                          slong var, const nmod_mpoly_ctx_t ctx)
488 {
489     nmod_mpolyu_fit_length(A, 1, ctx);
490     A->exps[0] = 0;
491     nmod_mpoly_cvtfrom_poly_notmain(A->coeffs + 0, a, var, ctx);
492     A->length = !nmod_mpoly_is_zero(A->coeffs + 0, ctx);
493 }
494 
495 
496 
497 /*
498     Assuming that "A" depends only on the main variable,
499     convert it to a poly "a".
500 */
nmod_mpolyu_cvtto_poly(nmod_poly_t a,nmod_mpolyu_t A,const nmod_mpoly_ctx_t ctx)501 void nmod_mpolyu_cvtto_poly(nmod_poly_t a, nmod_mpolyu_t A,
502                                                     const nmod_mpoly_ctx_t ctx)
503 {
504     slong i;
505     nmod_poly_zero(a);
506     for (i = 0; i < A->length; i++)
507     {
508         FLINT_ASSERT((A->coeffs + i)->length == 1);
509         FLINT_ASSERT(mpoly_monomial_is_zero((A->coeffs + i)->exps,
510                       mpoly_words_per_exp((A->coeffs + i)->bits, ctx->minfo)));
511         nmod_poly_set_coeff_ui(a, A->exps[i], (A->coeffs + i)->coeffs[0]);
512     }
513 }
514 
515 /*
516     Convert a poly "a" to "A" in the main variable,
517 */
nmod_mpolyu_cvtfrom_poly(nmod_mpolyu_t A,nmod_poly_t a,const nmod_mpoly_ctx_t ctx)518 void nmod_mpolyu_cvtfrom_poly(nmod_mpolyu_t A, nmod_poly_t a,
519                                                     const nmod_mpoly_ctx_t ctx)
520 {
521     slong i;
522     slong k;
523     slong N = mpoly_words_per_exp(A->bits, ctx->minfo);
524 
525     nmod_mpolyu_zero(A, ctx);
526     k = 0;
527     for (i = nmod_poly_length(a) - 1; i >= 0; i--)
528     {
529         mp_limb_t c = nmod_poly_get_coeff_ui(a, i);
530         if (c != UWORD(0))
531         {
532             nmod_mpolyu_fit_length(A, k + 1, ctx);
533             A->exps[k] = i;
534             nmod_mpoly_fit_length(A->coeffs + k, 1, ctx);
535             nmod_mpoly_fit_bits(A->coeffs + k, A->bits, ctx);
536             (A->coeffs + k)->bits = A->bits;
537             (A->coeffs + k)->coeffs[0] = c;
538             (A->coeffs + k)->length = 1;
539             mpoly_monomial_zero((A->coeffs + k)->exps + N*0, N);
540             k++;
541         }
542     }
543     A->length = k;
544 }
545 
546 
nmod_mpolyu_msub(nmod_mpolyu_t R,nmod_mpolyu_t A,nmod_mpolyu_t B,nmod_mpoly_t c,slong e,const nmod_mpoly_ctx_t ctx)547 void nmod_mpolyu_msub(nmod_mpolyu_t R, nmod_mpolyu_t A, nmod_mpolyu_t B,
548                            nmod_mpoly_t c, slong e, const nmod_mpoly_ctx_t ctx)
549 {
550     slong i, j, k;
551     nmod_mpoly_t T;
552 
553     nmod_mpolyu_fit_length(R, A->length + B->length, ctx);
554 
555     nmod_mpoly_init(T, ctx);
556 
557     i = j = k = 0;
558     while (i < A->length || j < B->length)
559     {
560         if (i < A->length && (j >= B->length || A->exps[i] > B->exps[j] + e))
561         {
562             /* only A ok */
563             nmod_mpoly_set(R->coeffs + k, A->coeffs + i, ctx);
564             R->exps[k] = A->exps[i];
565             k++;
566             i++;
567         }
568         else if (j < B->length && (i >= A->length || B->exps[j] + e > A->exps[i]))
569         {
570             /* only B ok */
571             nmod_mpoly_mul(R->coeffs + k, B->coeffs + j, c, ctx);
572             nmod_mpoly_neg(R->coeffs + k, R->coeffs + k, ctx);
573             R->exps[k] = B->exps[j] + e;
574             k++;
575             j++;
576         }
577         else if (i < A->length && j < B->length && (A->exps[i] == B->exps[j] + e))
578         {
579             nmod_mpoly_mul(T, B->coeffs + j, c, ctx);
580             nmod_mpoly_sub(R->coeffs + k, A->coeffs + i, T, ctx);
581             R->exps[k] = A->exps[i];
582             k += !nmod_mpoly_is_zero(R->coeffs + k, ctx);
583             i++;
584             j++;
585         } else
586         {
587             FLINT_ASSERT(0);
588         }
589     }
590 
591     nmod_mpoly_clear(T, ctx);
592     R->length = k;
593 }
594 
595 /*
596     A = B / c and preserve the bit packing
597 */
nmod_mpolyu_divexact_mpoly(nmod_mpolyu_t A,nmod_mpolyu_t B,nmod_mpoly_t c,const nmod_mpoly_ctx_t ctx)598 void nmod_mpolyu_divexact_mpoly(nmod_mpolyu_t A, nmod_mpolyu_t B,
599                                     nmod_mpoly_t c, const nmod_mpoly_ctx_t ctx)
600 {
601     slong i;
602     slong len;
603     slong N;
604     flint_bitcnt_t exp_bits;
605     nmod_mpoly_struct * poly1, * poly2, * poly3;
606     ulong * cmpmask;
607     TMP_INIT;
608 
609     TMP_START;
610 
611     exp_bits = B->bits;
612     FLINT_ASSERT(A->bits == B->bits);
613     FLINT_ASSERT(A->bits == c->bits);
614 
615     nmod_mpolyu_fit_length(A, B->length, ctx);
616 
617     N = mpoly_words_per_exp(exp_bits, ctx->minfo);
618     cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
619     mpoly_get_cmpmask(cmpmask, N, exp_bits, ctx->minfo);
620 
621     for (i = 0; i < B->length; i++)
622     {
623         poly1 = A->coeffs + i;
624         poly2 = B->coeffs + i;
625         poly3 = c;
626 
627         nmod_mpoly_fit_length(poly1, poly2->length/poly3->length + 1, ctx);
628         nmod_mpoly_fit_bits(poly1, exp_bits, ctx);
629         poly1->bits = exp_bits;
630 
631         len = _nmod_mpoly_divides_monagan_pearce(&poly1->coeffs, &poly1->exps,
632                             &poly1->alloc, poly2->coeffs, poly2->exps, poly2->length,
633                               poly3->coeffs, poly3->exps, poly3->length, exp_bits, N,
634                                                   cmpmask, ctx->ffinfo);
635         FLINT_ASSERT(len > 0);
636 
637         _nmod_mpoly_set_length(poly1, len, ctx);
638 
639         A->exps[i] = B->exps[i];
640     }
641     A->length = B->length;
642     TMP_END;
643 }
644 
nmod_mpolyu_divexact_mpoly_inplace(nmod_mpolyu_t A,nmod_mpoly_t c,const nmod_mpoly_ctx_t ctx)645 void nmod_mpolyu_divexact_mpoly_inplace(nmod_mpolyu_t A, nmod_mpoly_t c,
646                                                     const nmod_mpoly_ctx_t ctx)
647 {
648     slong i, N, len;
649     flint_bitcnt_t bits;
650     ulong * cmpmask;
651     nmod_mpoly_t t;
652     TMP_INIT;
653 
654     FLINT_ASSERT(c->length > 0);
655 
656     if (nmod_mpoly_is_ui(c, ctx))
657     {
658         if (c->coeffs[0] == 1)
659             return;
660 
661         for (i = 0; i < A->length; i++)
662         {
663             nmod_mpoly_struct * Ai = A->coeffs + i;
664             _nmod_vec_scalar_mul_nmod(Ai->coeffs, Ai->coeffs, Ai->length,
665                    nmod_inv(c->coeffs[0], ctx->ffinfo->mod), ctx->ffinfo->mod);
666         }
667 
668         return;
669     }
670 
671     bits = A->bits;
672     FLINT_ASSERT(bits == c->bits);
673 
674     nmod_mpoly_init3(t, 0, bits, ctx);
675 
676     N = mpoly_words_per_exp(bits, ctx->minfo);
677 
678     TMP_START;
679 
680     cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
681     mpoly_get_cmpmask(cmpmask, N, bits, ctx->minfo);
682 
683     for (i = A->length - 1; i >= 0; i--)
684     {
685         nmod_mpoly_struct * poly1 = t;
686         nmod_mpoly_struct * poly2 = A->coeffs + i;
687         nmod_mpoly_struct * poly3 = c;
688 
689         FLINT_ASSERT(poly2->bits == bits);
690 
691         len = _nmod_mpoly_divides_monagan_pearce(&poly1->coeffs, &poly1->exps,
692                             &poly1->alloc, poly2->coeffs, poly2->exps, poly2->length,
693                               poly3->coeffs, poly3->exps, poly3->length, bits, N,
694                                                   cmpmask, ctx->ffinfo);
695         FLINT_ASSERT(len > 0);
696         poly1->length = len;
697         nmod_mpoly_swap(poly2, poly1, ctx);
698     }
699 
700     TMP_END;
701 
702     nmod_mpoly_clear(t, ctx);
703 }
704 
705 
706 /*
707     A = B * c and preserve the bit packing
708 */
nmod_mpolyu_mul_mpoly(nmod_mpolyu_t A,nmod_mpolyu_t B,nmod_mpoly_t c,const nmod_mpoly_ctx_t ctx)709 void nmod_mpolyu_mul_mpoly(nmod_mpolyu_t A, nmod_mpolyu_t B,
710                                     nmod_mpoly_t c, const nmod_mpoly_ctx_t ctx)
711 {
712     slong i;
713     slong len;
714     slong N;
715     flint_bitcnt_t exp_bits;
716     nmod_mpoly_struct * poly1, * poly2, * poly3;
717     ulong * cmpmask;
718     TMP_INIT;
719 
720     TMP_START;
721 
722     exp_bits = B->bits;
723     FLINT_ASSERT(A->bits == B->bits);
724     FLINT_ASSERT(A->bits == c->bits);
725 
726     nmod_mpolyu_fit_length(A, B->length, ctx);
727 
728     N = mpoly_words_per_exp(exp_bits, ctx->minfo);
729     cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
730     mpoly_get_cmpmask(cmpmask, N, exp_bits, ctx->minfo);
731 
732     for (i = 0; i < B->length; i++)
733     {
734         poly1 = A->coeffs + i;
735         poly2 = B->coeffs + i;
736         poly3 = c;
737 
738         nmod_mpoly_fit_length(poly1, poly2->length/poly3->length + 1, ctx);
739         nmod_mpoly_fit_bits(poly1, exp_bits, ctx);
740         poly1->bits = exp_bits;
741 
742         len = _nmod_mpoly_mul_johnson(&poly1->coeffs, &poly1->exps,
743                        &poly1->alloc, poly2->coeffs, poly2->exps, poly2->length,
744                         poly3->coeffs, poly3->exps, poly3->length, exp_bits, N,
745                                                   cmpmask, ctx->ffinfo);
746 
747         FLINT_ASSERT(len > 0);
748         _nmod_mpoly_set_length(poly1, len, ctx);
749         A->exps[i] = B->exps[i];
750     }
751     A->length = B->length;
752     TMP_END;
753 }
754 
755 
nmod_mpolyu_mul_mpoly_inplace(nmod_mpolyu_t A,nmod_mpoly_t c,const nmod_mpoly_ctx_t ctx)756 void nmod_mpolyu_mul_mpoly_inplace(nmod_mpolyu_t A, nmod_mpoly_t c,
757                                                     const nmod_mpoly_ctx_t ctx)
758 {
759     slong i;
760     slong len;
761     slong N;
762     flint_bitcnt_t bits;
763     ulong * cmpmask;
764     nmod_mpoly_t t;
765     TMP_INIT;
766 
767     FLINT_ASSERT(c->length > 0);
768 
769     if (nmod_mpoly_is_ui(c, ctx))
770     {
771         if (c->coeffs[0] == 1)
772             return;
773 
774         for (i = 0; i < A->length; i++)
775         {
776             nmod_mpoly_struct * Ai = A->coeffs + i;
777             _nmod_vec_scalar_mul_nmod(Ai->coeffs, Ai->coeffs, Ai->length,
778                                                c->coeffs[0], ctx->ffinfo->mod);
779         }
780 
781         return;
782     }
783 
784     bits = A->bits;
785     FLINT_ASSERT(bits == c->bits);
786 
787     nmod_mpoly_init3(t, 0, bits, ctx);
788 
789     N = mpoly_words_per_exp(bits, ctx->minfo);
790 
791     TMP_START;
792 
793     cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
794     mpoly_get_cmpmask(cmpmask, N, bits, ctx->minfo);
795 
796     for (i = A->length - 1; i >= 0; i--)
797     {
798         nmod_mpoly_struct * poly1 = t;
799         nmod_mpoly_struct * poly2 = A->coeffs + i;
800         nmod_mpoly_struct * poly3 = c;
801 
802         FLINT_ASSERT(poly2->bits == bits);
803 
804         len = _nmod_mpoly_mul_johnson(&poly1->coeffs, &poly1->exps,
805                        &poly1->alloc, poly2->coeffs, poly2->exps, poly2->length,
806                         poly3->coeffs, poly3->exps, poly3->length, bits, N,
807                                                   cmpmask, ctx->ffinfo);
808 
809         FLINT_ASSERT(len > 0);
810         poly1->length = len;
811         nmod_mpoly_swap(poly2, poly1, ctx);
812     }
813 
814     TMP_END;
815 
816     nmod_mpoly_clear(t, ctx);
817 }
818 
819 
820 
nmod_mpolyu_content_mpoly_threaded_pool(nmod_mpoly_t g,const nmod_mpolyu_t A,const nmod_mpoly_ctx_t ctx,const thread_pool_handle * handles,slong num_handles)821 int nmod_mpolyu_content_mpoly_threaded_pool(
822     nmod_mpoly_t g,
823     const nmod_mpolyu_t A,
824     const nmod_mpoly_ctx_t ctx,
825     const thread_pool_handle * handles,
826     slong num_handles)
827 {
828     slong i, j;
829     int success;
830     flint_bitcnt_t bits = A->bits;
831 
832     FLINT_ASSERT(g->bits == bits);
833 
834     if (A->length < 2)
835     {
836         if (A->length == 0)
837         {
838             nmod_mpoly_zero(g, ctx);
839         }
840         else
841         {
842             nmod_mpoly_make_monic(g, A->coeffs + 0, ctx);
843         }
844 
845         FLINT_ASSERT(g->bits == bits);
846         return 1;
847     }
848 
849     j = 0;
850     for (i = 1; i < A->length; i++)
851     {
852         if ((A->coeffs + i)->length < (A->coeffs + j)->length)
853         {
854             j = i;
855         }
856     }
857 
858     if (j == 0)
859         j = 1;
860 
861     success = _nmod_mpoly_gcd_threaded_pool(g, bits, A->coeffs + 0,
862                                      A->coeffs + j, ctx, handles, num_handles);
863     if (!success)
864         return 0;
865 
866     for (i = 1; i < A->length; i++)
867     {
868         if (i == j)
869             continue;
870 
871         success = _nmod_mpoly_gcd_threaded_pool(g, bits, g,
872                                      A->coeffs + i, ctx, handles, num_handles);
873         FLINT_ASSERT(g->bits == bits);
874         if (!success)
875             return 0;
876     }
877 
878     return 1;
879 }
880