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