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 <https://www.gnu.org/licenses/>.
10 */
11
12 #include "nmod_mpoly.h"
13 #include "fq_nmod_mpoly.h"
14 #include "fq_nmod_mpoly_factor.h"
15
16
fq_nmod_mpolyu_is_canonical(const fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t ctx)17 int fq_nmod_mpolyu_is_canonical(const fq_nmod_mpolyu_t A,
18 const fq_nmod_mpoly_ctx_t ctx)
19 {
20 slong i;
21
22 for (i = 0; i < A->length; i++)
23 {
24 if ((slong)(A->exps[i]) < 0)
25 {
26 return 0;
27 }
28
29 if (i > 0 && A->exps[i - 1] <= A->exps[i])
30 {
31 return 0;
32 }
33
34 if (!fq_nmod_mpoly_is_canonical(A->coeffs + i, ctx))
35 {
36 return 0;
37 }
38
39 if (fq_nmod_mpoly_is_zero(A->coeffs + i, ctx))
40 {
41 return 0;
42 }
43 }
44 return 1;
45 }
46
fq_nmod_mpolyu_init(fq_nmod_mpolyu_t A,flint_bitcnt_t bits,const fq_nmod_mpoly_ctx_t ctx)47 void fq_nmod_mpolyu_init(fq_nmod_mpolyu_t A, flint_bitcnt_t bits,
48 const fq_nmod_mpoly_ctx_t ctx)
49 {
50 A->coeffs = NULL;
51 A->exps = NULL;
52 A->alloc = 0;
53 A->length = 0;
54 A->bits = bits;
55 }
56
57
fq_nmod_mpolyu_clear(fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t uctx)58 void fq_nmod_mpolyu_clear(fq_nmod_mpolyu_t A, const fq_nmod_mpoly_ctx_t uctx)
59 {
60 slong i;
61 for (i = 0; i < A->alloc; i++)
62 fq_nmod_mpoly_clear(A->coeffs + i, uctx);
63 flint_free(A->coeffs);
64 flint_free(A->exps);
65 }
66
fq_nmod_mpolyu_zero(fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t uctx)67 void fq_nmod_mpolyu_zero(fq_nmod_mpolyu_t A, const fq_nmod_mpoly_ctx_t uctx)
68 {
69 slong i;
70 for (i = 0; i < A->alloc; i++) {
71 fq_nmod_mpoly_clear(A->coeffs + i, uctx);
72 fq_nmod_mpoly_init(A->coeffs + i, uctx);
73 }
74 A->length = 0;
75 }
76
fq_nmod_mpolyu_is_one(fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t uctx)77 int fq_nmod_mpolyu_is_one(fq_nmod_mpolyu_t A, const fq_nmod_mpoly_ctx_t uctx)
78 {
79 if (A->length != 1 || A->exps[0] != UWORD(0))
80 return 0;
81
82 return fq_nmod_mpoly_is_one(A->coeffs + 0, uctx);
83 }
84
fq_nmod_mpolyu_print_pretty(const fq_nmod_mpolyu_t poly,const char ** x,const fq_nmod_mpoly_ctx_t ctx)85 void fq_nmod_mpolyu_print_pretty(const fq_nmod_mpolyu_t poly,
86 const char ** x, const fq_nmod_mpoly_ctx_t ctx)
87 {
88 slong i;
89 if (poly->length == 0)
90 flint_printf("0");
91 for (i = 0; i < poly->length; i++)
92 {
93 if (i != 0)
94 flint_printf(" + ");
95 flint_printf("(");
96 fq_nmod_mpoly_print_pretty(poly->coeffs + i,x,ctx);
97 flint_printf(")*X^%wd",poly->exps[i]);
98 }
99 }
100
fq_nmod_mpolyu_fit_length(fq_nmod_mpolyu_t A,slong length,const fq_nmod_mpoly_ctx_t uctx)101 void fq_nmod_mpolyu_fit_length(fq_nmod_mpolyu_t A, slong length,
102 const fq_nmod_mpoly_ctx_t uctx)
103 {
104 slong i;
105 slong old_alloc = A->alloc;
106 slong new_alloc = FLINT_MAX(length, 2*A->alloc);
107
108 if (length > old_alloc)
109 {
110 A->exps = (ulong *) flint_realloc(A->exps, new_alloc*sizeof(ulong));
111 A->coeffs = (fq_nmod_mpoly_struct *) flint_realloc(A->coeffs,
112 new_alloc*sizeof(fq_nmod_mpoly_struct));
113
114 for (i = old_alloc; i < new_alloc; i++)
115 fq_nmod_mpoly_init3(A->coeffs + i, 0, A->bits, uctx);
116
117 A->alloc = new_alloc;
118 }
119 }
120
fq_nmod_mpolyu_one(fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t uctx)121 void fq_nmod_mpolyu_one(fq_nmod_mpolyu_t A, const fq_nmod_mpoly_ctx_t uctx)
122 {
123 fq_nmod_mpolyu_fit_length(A, 1, uctx);
124 A->exps[0] = 0;
125 fq_nmod_mpoly_one(A->coeffs + 0, uctx);
126 A->length = 1;
127 }
128
129
fq_nmod_mpolyu_degrees_si(slong * degs,const fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t ctx)130 void fq_nmod_mpolyu_degrees_si(
131 slong * degs,
132 const fq_nmod_mpolyu_t A,
133 const fq_nmod_mpoly_ctx_t ctx)
134 {
135 slong i, j;
136 flint_bitcnt_t bits = A->bits;
137 slong N = mpoly_words_per_exp_sp(bits, ctx->minfo);
138 ulong * pmax, mask;
139 TMP_INIT;
140
141 FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
142
143 if (A->length < 1)
144 {
145 for (j = 0; j < ctx->minfo->nvars; j++)
146 degs[j] = -1;
147 }
148
149 TMP_START;
150
151 mask = mpoly_overflow_mask_sp(bits);
152
153 pmax = (ulong *) TMP_ALLOC(N*sizeof(ulong));
154 mpoly_monomial_zero(pmax, N);
155
156 for (i = 0; i < A->length; i++)
157 {
158 ulong * Aiexps = A->coeffs[i].exps;
159 FLINT_ASSERT(A->coeffs[i].bits == bits);
160
161 for (j = 0; j < A->coeffs[i].length; j++)
162 mpoly_monomial_max(pmax, pmax, Aiexps + N*j, bits, N, mask);
163 }
164
165 mpoly_unpack_vec_ui((ulong *) degs, pmax, bits, ctx->minfo->nvars, 1);
166
167 for (i = 0; i < ctx->minfo->nvars/2; i++)
168 SLONG_SWAP(degs[i], degs[ctx->minfo->nvars - i - 1]);
169
170 TMP_END;
171 }
172
fq_nmod_mpolyu_repack_bits_inplace(fq_nmod_mpolyu_t A,flint_bitcnt_t bits,const fq_nmod_mpoly_ctx_t ctx)173 void fq_nmod_mpolyu_repack_bits_inplace(
174 fq_nmod_mpolyu_t A,
175 flint_bitcnt_t bits,
176 const fq_nmod_mpoly_ctx_t ctx)
177 {
178 slong i;
179
180 if (bits == A->bits)
181 return;
182
183 A->bits = bits;
184
185 for (i = 0; i < A->alloc; i++)
186 fq_nmod_mpoly_repack_bits_inplace(A->coeffs + i, bits, ctx);
187 }
188
189
190 /* if the coefficient doesn't exist, a new one is created (and set to zero) */
_fq_nmod_mpolyu_get_coeff(fq_nmod_mpolyu_t A,ulong pow,const fq_nmod_mpoly_ctx_t uctx)191 fq_nmod_mpoly_struct * _fq_nmod_mpolyu_get_coeff(fq_nmod_mpolyu_t A,
192 ulong pow, const fq_nmod_mpoly_ctx_t uctx)
193 {
194 slong i, j;
195 fq_nmod_mpoly_struct * xk;
196
197 for (i = 0; i < A->length && A->exps[i] >= pow; i++)
198 {
199 if (A->exps[i] == pow)
200 {
201 return A->coeffs + i;
202 }
203 }
204
205 fq_nmod_mpolyu_fit_length(A, A->length + 1, uctx);
206
207 for (j = A->length; j > i; j--)
208 {
209 A->exps[j] = A->exps[j - 1];
210 fq_nmod_mpoly_swap(A->coeffs + j, A->coeffs + j - 1, uctx);
211 }
212
213 A->length++;
214 A->exps[i] = pow;
215 xk = A->coeffs + i;
216 xk->length = 0;
217 FLINT_ASSERT(xk->bits == A->bits);
218
219 return xk;
220 }
221
222
223
224 /*
225 Convert B to A using the variable permutation perm.
226 The uctx should be the context of the coefficients of A.
227 The ctx should be the context of B.
228
229 operation on each term:
230
231 for 0 <= k <= m
232 l = perm[k]
233 Aexp[k] = (Bexp[l] - shift[l])/stride[l]
234 */
fq_nmod_mpoly_to_mpolyu_perm_deflate(fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t uctx,const fq_nmod_mpoly_t B,const fq_nmod_mpoly_ctx_t ctx,const slong * perm,const ulong * shift,const ulong * stride)235 void fq_nmod_mpoly_to_mpolyu_perm_deflate(
236 fq_nmod_mpolyu_t A,
237 const fq_nmod_mpoly_ctx_t uctx,
238 const fq_nmod_mpoly_t B,
239 const fq_nmod_mpoly_ctx_t ctx,
240 const slong * perm,
241 const ulong * shift,
242 const ulong * stride)
243 {
244 slong d = fq_nmod_ctx_degree(ctx->fqctx);
245 slong i, j, k, l;
246 slong n = ctx->minfo->nvars;
247 slong m = uctx->minfo->nvars;
248 slong NA, NB;
249 ulong * uexps;
250 ulong * Bexps;
251 fq_nmod_mpoly_struct * Ac;
252 TMP_INIT;
253
254 FLINT_ASSERT(A->bits <= FLINT_BITS);
255 FLINT_ASSERT(B->bits <= FLINT_BITS);
256 FLINT_ASSERT(m + 1 <= n);
257
258 TMP_START;
259
260 FLINT_ASSERT(fq_nmod_mpoly_is_canonical(B, ctx));
261
262 uexps = (ulong *) TMP_ALLOC((m + 1)*sizeof(ulong));
263 Bexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
264
265 fq_nmod_mpolyu_zero(A, uctx);
266
267 NA = mpoly_words_per_exp(A->bits, uctx->minfo);
268 NB = mpoly_words_per_exp(B->bits, ctx->minfo);
269
270 for (j = 0; j < B->length; j++)
271 {
272 mpoly_get_monomial_ui(Bexps, B->exps + NB*j, B->bits, ctx->minfo);
273 for (k = 0; k < m + 1; k++)
274 {
275 l = perm[k];
276 FLINT_ASSERT(stride[l] != UWORD(0));
277 FLINT_ASSERT(((Bexps[l] - shift[l]) % stride[l]) == UWORD(0));
278 uexps[k] = (Bexps[l] - shift[l]) / stride[l];
279 }
280 Ac = _fq_nmod_mpolyu_get_coeff(A, uexps[0], uctx);
281 FLINT_ASSERT(Ac->bits == A->bits);
282
283 fq_nmod_mpoly_fit_length(Ac, Ac->length + 1, uctx);
284 _n_fq_set(Ac->coeffs + d*Ac->length, B->coeffs + d*j, d);
285 mpoly_set_monomial_ui(Ac->exps + NA*Ac->length, uexps + 1, A->bits, uctx->minfo);
286 Ac->length++;
287 }
288
289 for (i = 0; i < A->length; i++)
290 fq_nmod_mpoly_sort_terms(A->coeffs + i, uctx);
291
292 TMP_END;
293
294 FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(A, uctx));
295 }
296
297 /*
298 Convert B to A using the variable permutation vector perm.
299 A must be constructed with bits = Abits.
300
301 operation on each term:
302
303 for 0 <= l < n
304 Aexp[l] = shift[l]
305
306 for 0 <= k <= m
307 l = perm[k]
308 Aexp[l] += scale[l]*Bexp[k]
309 */
fq_nmod_mpoly_from_mpolyu_perm_inflate(fq_nmod_mpoly_t A,flint_bitcnt_t Abits,const fq_nmod_mpoly_ctx_t ctx,const fq_nmod_mpolyu_t B,const fq_nmod_mpoly_ctx_t uctx,const slong * perm,const ulong * shift,const ulong * stride)310 void fq_nmod_mpoly_from_mpolyu_perm_inflate(
311 fq_nmod_mpoly_t A, flint_bitcnt_t Abits,
312 const fq_nmod_mpoly_ctx_t ctx,
313 const fq_nmod_mpolyu_t B,
314 const fq_nmod_mpoly_ctx_t uctx,
315 const slong * perm,
316 const ulong * shift,
317 const ulong * stride)
318 {
319 slong d = fq_nmod_ctx_degree(ctx->fqctx);
320 slong n = ctx->minfo->nvars;
321 slong m = uctx->minfo->nvars;
322 slong i, j, k, l;
323 slong NA, NB;
324 slong Alen;
325 mp_limb_t * Acoeff;
326 ulong * Aexp;
327 ulong * uexps;
328 ulong * Aexps;
329 TMP_INIT;
330
331 FLINT_ASSERT(B->length > 0);
332 FLINT_ASSERT(Abits <= FLINT_BITS);
333 FLINT_ASSERT(B->bits <= FLINT_BITS);
334 FLINT_ASSERT(m + 1 <= n);
335 TMP_START;
336
337 uexps = (ulong *) TMP_ALLOC((m + 1)*sizeof(ulong));
338 Aexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
339
340 NA = mpoly_words_per_exp(Abits, ctx->minfo);
341 NB = mpoly_words_per_exp(B->bits, uctx->minfo);
342
343 fq_nmod_mpoly_fit_length_reset_bits(A, B->length, Abits, ctx);
344
345 Acoeff = A->coeffs;
346 Aexp = A->exps;
347 Alen = 0;
348 for (i = 0; i < B->length; i++)
349 {
350 fq_nmod_mpoly_struct * Bc = B->coeffs + i;
351 FLINT_ASSERT(Bc->bits == B->bits);
352
353 _fq_nmod_mpoly_fit_length(&Acoeff, &A->coeffs_alloc, d,
354 &Aexp, &A->exps_alloc, NA, Alen + Bc->length);
355
356 for (j = 0; j < Bc->length; j++)
357 {
358 _n_fq_set(Acoeff + d*(Alen + j), Bc->coeffs + d*j, d);
359 mpoly_get_monomial_ui(uexps + 1, Bc->exps + NB*j, Bc->bits, uctx->minfo);
360 uexps[0] = B->exps[i];
361 for (l = 0; l < n; l++)
362 {
363 Aexps[l] = shift[l];
364 }
365 for (k = 0; k < m + 1; k++)
366 {
367 l = perm[k];
368 Aexps[l] += stride[l]*uexps[k];
369 }
370 mpoly_set_monomial_ui(Aexp + NA*(Alen + j), Aexps, Abits, ctx->minfo);
371 }
372 Alen += Bc->length;
373 }
374 A->coeffs = Acoeff;
375 A->exps = Aexp;
376 A->length = Alen;
377
378 TMP_END;
379
380 fq_nmod_mpoly_sort_terms(A, ctx);
381 }
382
383
384 /*
385 Convert B to A using the variable permutation perm.
386 The uctx should be the context of the coefficients of A.
387 The ctx should be the context of B.
388
389 operation on each term:
390
391 for 0 <= k < m + 2
392 l = perm[k]
393 Aexp[k] = (Bexp[l] - shift[l])/stride[l]
394
395 the most significant main variable uses Aexp[0]
396 the least significant main variable uses Aexp[1]
397 the coefficients of A use variables Aexp[2], ..., Aexp[m + 1]
398 maxexps if it exists is supposed to be a degree bound on B
399 */
fq_nmod_mpoly_to_mpolyuu_perm_deflate(fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t uctx,const fq_nmod_mpoly_t B,const fq_nmod_mpoly_ctx_t ctx,const slong * perm,const ulong * shift,const ulong * stride)400 void fq_nmod_mpoly_to_mpolyuu_perm_deflate(
401 fq_nmod_mpolyu_t A,
402 const fq_nmod_mpoly_ctx_t uctx,
403 const fq_nmod_mpoly_t B,
404 const fq_nmod_mpoly_ctx_t ctx,
405 const slong * perm,
406 const ulong * shift,
407 const ulong * stride)
408 {
409 slong d = fq_nmod_ctx_degree(ctx->fqctx);
410 slong i, j, k, l;
411 slong n = ctx->minfo->nvars;
412 slong m = uctx->minfo->nvars;
413 slong NA, NB;
414 ulong * uexps;
415 ulong * Bexps;
416 fq_nmod_mpoly_struct * Ac;
417 TMP_INIT;
418
419 FLINT_ASSERT(A->bits <= FLINT_BITS);
420 FLINT_ASSERT(B->bits <= FLINT_BITS);
421 FLINT_ASSERT(m + 2 <= n);
422
423 fq_nmod_mpolyu_zero(A, uctx);
424
425 TMP_START;
426
427 uexps = (ulong *) TMP_ALLOC((m + 2)*sizeof(ulong));
428 Bexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
429 NA = mpoly_words_per_exp(A->bits, uctx->minfo);
430 NB = mpoly_words_per_exp(B->bits, ctx->minfo);
431
432 for (j = 0; j < B->length; j++)
433 {
434 mpoly_get_monomial_ui(Bexps, B->exps + NB*j, B->bits, ctx->minfo);
435 for (k = 0; k < m + 2; k++)
436 {
437 l = perm[k];
438 if (stride[l] == 1)
439 {
440 uexps[k] = (Bexps[l] - shift[l]);
441 }
442 else
443 {
444 FLINT_ASSERT(stride[l] != 0);
445 FLINT_ASSERT(((Bexps[l] - shift[l]) % stride[l]) == 0);
446 uexps[k] = (Bexps[l] - shift[l]) / stride[l];
447 }
448 }
449 FLINT_ASSERT(FLINT_BIT_COUNT(uexps[0]) < FLINT_BITS/2);
450 FLINT_ASSERT(FLINT_BIT_COUNT(uexps[1]) < FLINT_BITS/2);
451 Ac = _fq_nmod_mpolyu_get_coeff(A, (uexps[0] << (FLINT_BITS/2)) + uexps[1], uctx);
452 FLINT_ASSERT(Ac->bits == A->bits);
453
454 fq_nmod_mpoly_fit_length(Ac, Ac->length + 1, uctx);
455 _n_fq_set(Ac->coeffs + d*Ac->length, B->coeffs + d*j, d);
456 mpoly_set_monomial_ui(Ac->exps + NA*Ac->length, uexps + 2, A->bits, uctx->minfo);
457 Ac->length++;
458 }
459
460 for (i = 0; i < A->length; i++)
461 fq_nmod_mpoly_sort_terms(A->coeffs + i, uctx);
462
463 TMP_END;
464 }
465
466
467 /*
468 Convert B to A using the variable permutation vector perm.
469 A must be constructed with bits = Abits.
470
471 operation on each term:
472
473 for 0 <= l < n
474 Aexp[l] = shift[l]
475
476 for 0 <= k < m + 2
477 l = perm[k]
478 Aexp[l] += scale[l]*Bexp[k]
479 */
fq_nmod_mpoly_from_mpolyuu_perm_inflate(fq_nmod_mpoly_t A,flint_bitcnt_t Abits,const fq_nmod_mpoly_ctx_t ctx,const fq_nmod_mpolyu_t B,const fq_nmod_mpoly_ctx_t uctx,const slong * perm,const ulong * shift,const ulong * stride)480 void fq_nmod_mpoly_from_mpolyuu_perm_inflate( /* only for 2 main vars */
481 fq_nmod_mpoly_t A,
482 flint_bitcnt_t Abits,
483 const fq_nmod_mpoly_ctx_t ctx,
484 const fq_nmod_mpolyu_t B,
485 const fq_nmod_mpoly_ctx_t uctx,
486 const slong * perm,
487 const ulong * shift,
488 const ulong * stride)
489 {
490 slong d = fq_nmod_ctx_degree(ctx->fqctx);
491 slong n = ctx->minfo->nvars;
492 slong m = uctx->minfo->nvars;
493 slong i, j, k, l;
494 slong NA, NB;
495 slong Alen;
496 mp_limb_t * Acoeff;
497 ulong * Aexp;
498 ulong * uexps;
499 ulong * Aexps;
500 TMP_INIT;
501
502 FLINT_ASSERT(B->length > 0);
503 FLINT_ASSERT(Abits <= FLINT_BITS);
504 FLINT_ASSERT(B->bits <= FLINT_BITS);
505 FLINT_ASSERT(m + 2 <= n);
506 TMP_START;
507
508 uexps = (ulong *) TMP_ALLOC((m + 2)*sizeof(ulong));
509 Aexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
510
511 NA = mpoly_words_per_exp(Abits, ctx->minfo);
512 NB = mpoly_words_per_exp(B->bits, uctx->minfo);
513
514 fq_nmod_mpoly_fit_length_reset_bits(A, B->length, Abits, ctx);
515
516 Acoeff = A->coeffs;
517 Aexp = A->exps;
518 Alen = 0;
519 for (i = 0; i < B->length; i++)
520 {
521 fq_nmod_mpoly_struct * Bc = B->coeffs + i;
522 FLINT_ASSERT(Bc->bits == B->bits);
523
524 _fq_nmod_mpoly_fit_length(&Acoeff, &A->coeffs_alloc, d,
525 &Aexp, &A->exps_alloc, NA, Alen + Bc->length);
526
527 for (j = 0; j < Bc->length; j++)
528 {
529 _n_fq_set(Acoeff + d*(Alen + j), Bc->coeffs + d*j, d);
530 mpoly_get_monomial_ui(uexps + 2, Bc->exps + NB*j, Bc->bits, uctx->minfo);
531 uexps[0] = B->exps[i] >> (FLINT_BITS/2);
532 uexps[1] = B->exps[i] & ((-UWORD(1)) >> (FLINT_BITS - FLINT_BITS/2));
533 for (l = 0; l < n; l++)
534 {
535 Aexps[l] = shift[l];
536 }
537 for (k = 0; k < m + 2; k++)
538 {
539 l = perm[k];
540 Aexps[l] += stride[l]*uexps[k];
541 }
542 mpoly_set_monomial_ui(Aexp + NA*(Alen + j), Aexps, Abits, ctx->minfo);
543 }
544 Alen += Bc->length;
545 }
546 A->coeffs = Acoeff;
547 A->exps = Aexp;
548 _fq_nmod_mpoly_set_length(A, Alen, ctx);
549
550 fq_nmod_mpoly_sort_terms(A, ctx);
551 TMP_END;
552 }
553
554
555
556
557 /** 0 variables *************************************/
558
559
fq_nmod_mpoly_to_mpolyl_perm_deflate(fq_nmod_mpoly_t A,const fq_nmod_mpoly_ctx_t lctx,const fq_nmod_mpoly_t B,const fq_nmod_mpoly_ctx_t ctx,const slong * perm,const ulong * shift,const ulong * stride)560 void fq_nmod_mpoly_to_mpolyl_perm_deflate(
561 fq_nmod_mpoly_t A,
562 const fq_nmod_mpoly_ctx_t lctx,
563 const fq_nmod_mpoly_t B,
564 const fq_nmod_mpoly_ctx_t ctx,
565 const slong * perm,
566 const ulong * shift,
567 const ulong * stride)
568 {
569 slong d;
570 slong j, k, l;
571 slong m = lctx->minfo->nvars;
572 slong n = ctx->minfo->nvars;
573 slong NA, NB;
574 ulong * lexps;
575 ulong * Bexps;
576 TMP_INIT;
577
578 FLINT_ASSERT(A->bits <= FLINT_BITS);
579 FLINT_ASSERT(B->bits <= FLINT_BITS);
580 FLINT_ASSERT(m <= n);
581 TMP_START;
582
583 fq_nmod_mpoly_fit_length(A, B->length, lctx);
584 A->length = B->length;
585
586 lexps = (ulong *) TMP_ALLOC(m*sizeof(ulong));
587 Bexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
588 NA = mpoly_words_per_exp(A->bits, lctx->minfo);
589 NB = mpoly_words_per_exp(B->bits, ctx->minfo);
590
591 d = fq_nmod_ctx_degree(ctx->fqctx);
592 FLINT_ASSERT(d == fq_nmod_ctx_degree(lctx->fqctx));
593 _nmod_vec_set(A->coeffs, B->coeffs, B->length*d);
594
595 for (j = 0; j < B->length; j++)
596 {
597 mpoly_get_monomial_ui(Bexps, B->exps + NB*j, B->bits, ctx->minfo);
598 for (k = 0; k < m; k++)
599 {
600 l = perm[k];
601 if (stride[l] == 1)
602 {
603 lexps[k] = (Bexps[l] - shift[l]);
604 }
605 else
606 {
607 FLINT_ASSERT(stride[l] != 0);
608 FLINT_ASSERT(((Bexps[l] - shift[l]) % stride[l]) == 0);
609 lexps[k] = (Bexps[l] - shift[l]) / stride[l];
610 }
611 }
612
613 mpoly_set_monomial_ui(A->exps + NA*j, lexps, A->bits, lctx->minfo);
614 }
615
616 TMP_END;
617
618 fq_nmod_mpoly_sort_terms(A, lctx);
619
620 FLINT_ASSERT(fq_nmod_mpoly_is_canonical(A, lctx));
621 }
622
623
624 /*
625 Convert B to A using the variable permutation vector perm.
626 A must be constructed with bits = Abits.
627
628 operation on each term:
629
630 for 0 <= l < n
631 Aexp[l] = shift[l]
632
633 for 0 <= k < m + 2
634 l = perm[k]
635 Aexp[l] += scale[l]*Bexp[k]
636 */
fq_nmod_mpoly_from_mpolyl_perm_inflate(fq_nmod_mpoly_t A,flint_bitcnt_t Abits,const fq_nmod_mpoly_ctx_t ctx,const fq_nmod_mpoly_t B,const fq_nmod_mpoly_ctx_t lctx,const slong * perm,const ulong * shift,const ulong * stride)637 void fq_nmod_mpoly_from_mpolyl_perm_inflate(
638 fq_nmod_mpoly_t A,
639 flint_bitcnt_t Abits,
640 const fq_nmod_mpoly_ctx_t ctx,
641 const fq_nmod_mpoly_t B,
642 const fq_nmod_mpoly_ctx_t lctx,
643 const slong * perm,
644 const ulong * shift,
645 const ulong * stride)
646 {
647 slong d;
648 slong n = ctx->minfo->nvars;
649 slong m = lctx->minfo->nvars;
650 slong i, k, l;
651 slong NA, NB;
652 ulong * Bexps;
653 ulong * Aexps;
654 TMP_INIT;
655
656 FLINT_ASSERT(B->length > 0);
657 FLINT_ASSERT(Abits <= FLINT_BITS);
658 FLINT_ASSERT(B->bits <= FLINT_BITS);
659 FLINT_ASSERT(m <= n);
660 TMP_START;
661
662 Bexps = (ulong *) TMP_ALLOC(m*sizeof(ulong));
663 Aexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
664
665 NA = mpoly_words_per_exp(Abits, ctx->minfo);
666 NB = mpoly_words_per_exp(B->bits, lctx->minfo);
667
668 fq_nmod_mpoly_fit_length_reset_bits(A, B->length, Abits, ctx);
669 A->length = B->length;
670
671 d = fq_nmod_ctx_degree(ctx->fqctx);
672 FLINT_ASSERT(d == fq_nmod_ctx_degree(lctx->fqctx));
673 _nmod_vec_set(A->coeffs, B->coeffs, B->length*d);
674
675 for (i = 0; i < B->length; i++)
676 {
677 mpoly_get_monomial_ui(Bexps, B->exps + NB*i, B->bits, lctx->minfo);
678
679 for (l = 0; l < n; l++)
680 {
681 Aexps[l] = shift[l];
682 }
683 for (k = 0; k < m; k++)
684 {
685 l = perm[k];
686 Aexps[l] += stride[l]*Bexps[k];
687 }
688
689 mpoly_set_monomial_ui(A->exps + NA*i, Aexps, Abits, ctx->minfo);
690 }
691
692 TMP_END;
693
694 fq_nmod_mpoly_sort_terms(A, ctx);
695
696 FLINT_ASSERT(fq_nmod_mpoly_is_canonical(A, ctx));
697 }
698
fq_nmod_mpolyu_shift_right(fq_nmod_mpolyu_t A,ulong s)699 void fq_nmod_mpolyu_shift_right(fq_nmod_mpolyu_t A, ulong s)
700 {
701 slong i;
702 for (i = 0; i < A->length; i++)
703 {
704 FLINT_ASSERT(A->exps[i] >= s);
705 A->exps[i] -= s;
706 }
707 }
708
fq_nmod_mpolyu_shift_left(fq_nmod_mpolyu_t A,ulong s)709 void fq_nmod_mpolyu_shift_left(fq_nmod_mpolyu_t A, ulong s)
710 {
711 slong i;
712 for (i = 0; i < A->length; i++)
713 {
714 A->exps[i] += s;
715 }
716 }
717
fq_nmod_mpolyu_scalar_mul_fq_nmod(fq_nmod_mpolyu_t A,fq_nmod_t c,const fq_nmod_mpoly_ctx_t ctx)718 void fq_nmod_mpolyu_scalar_mul_fq_nmod(fq_nmod_mpolyu_t A, fq_nmod_t c,
719 const fq_nmod_mpoly_ctx_t ctx)
720 {
721 slong i;
722 for (i = 0; i < A->length; i++)
723 fq_nmod_mpoly_scalar_mul_fq_nmod(A->coeffs + i, A->coeffs + i, c, ctx);
724 }
725
726
fq_nmod_mpolyu_set(fq_nmod_mpolyu_t A,const fq_nmod_mpolyu_t B,const fq_nmod_mpoly_ctx_t uctx)727 void fq_nmod_mpolyu_set(fq_nmod_mpolyu_t A, const fq_nmod_mpolyu_t B,
728 const fq_nmod_mpoly_ctx_t uctx)
729 {
730 slong i;
731
732 FLINT_ASSERT(A != B);
733 FLINT_ASSERT(fq_nmod_mpolyu_is_canonical(B, uctx));
734
735 fq_nmod_mpolyu_fit_length(A, B->length, uctx);
736 A->length = B->length;
737
738 for (i = 0; i < B->length; i++)
739 {
740 fq_nmod_mpoly_set(A->coeffs + i, B->coeffs + i, uctx);
741 A->exps[i] = B->exps[i];
742 }
743 }
744
745
fq_nmod_mpolyu_divexact_mpoly_inplace(fq_nmod_mpolyu_t A,fq_nmod_mpoly_t c,const fq_nmod_mpoly_ctx_t ctx)746 void fq_nmod_mpolyu_divexact_mpoly_inplace(
747 fq_nmod_mpolyu_t A,
748 fq_nmod_mpoly_t c,
749 const fq_nmod_mpoly_ctx_t ctx)
750 {
751 slong i, j;
752 flint_bitcnt_t bits = A->bits;
753 slong N = mpoly_words_per_exp(bits, ctx->minfo);
754 ulong * cmpmask;
755 fq_nmod_mpoly_t t;
756 TMP_INIT;
757
758 FLINT_ASSERT(bits == c->bits);
759 FLINT_ASSERT(c->length > 0);
760
761 if (fq_nmod_mpoly_is_fq_nmod(c, ctx))
762 {
763 slong d = fq_nmod_ctx_degree(ctx->fqctx);
764 mp_limb_t * inv;
765
766 if (_n_fq_is_one(c->coeffs + d*0, d))
767 return;
768
769 TMP_START;
770
771 inv = (mp_limb_t *) TMP_ALLOC(d*sizeof(mp_limb_t));
772
773 n_fq_inv(inv, c->coeffs + d*0, ctx->fqctx);
774
775 for (i = 0; i < A->length; i++)
776 {
777 fq_nmod_mpoly_struct * Ai = A->coeffs + i;
778 for (j = 0; j < Ai->length; j++)
779 n_fq_mul(Ai->coeffs + d*j, Ai->coeffs + d*j, inv, ctx->fqctx);
780 }
781
782 TMP_END;
783
784 return;
785 }
786
787 fq_nmod_mpoly_init3(t, 0, bits, ctx);
788
789 TMP_START;
790
791 cmpmask = (ulong *) TMP_ALLOC(N*sizeof(ulong));
792 mpoly_get_cmpmask(cmpmask, N, bits, ctx->minfo);
793
794 for (i = A->length - 1; i >= 0; i--)
795 {
796 FLINT_ASSERT(A->coeffs[i].bits == bits);
797 _fq_nmod_mpoly_divides_monagan_pearce(t, A->coeffs[i].coeffs,
798 A->coeffs[i].exps, A->coeffs[i].length, c->coeffs, c->exps,
799 c->length, bits, N, cmpmask, ctx->fqctx);
800 fq_nmod_mpoly_swap(A->coeffs + i, t, ctx);
801 FLINT_ASSERT(A->coeffs[i].length > 0);
802 }
803
804 TMP_END;
805
806 fq_nmod_mpoly_clear(t, ctx);
807 }
808
809
810 /*
811 A = B * c and preserve the bit packing
812 */
fq_nmod_mpolyu_mul_mpoly(fq_nmod_mpolyu_t A,fq_nmod_mpolyu_t B,fq_nmod_mpoly_t c,const fq_nmod_mpoly_ctx_t ctx)813 void fq_nmod_mpolyu_mul_mpoly(
814 fq_nmod_mpolyu_t A,
815 fq_nmod_mpolyu_t B,
816 fq_nmod_mpoly_t c,
817 const fq_nmod_mpoly_ctx_t ctx)
818 {
819 slong i;
820 flint_bitcnt_t bits = B->bits;
821 slong N = mpoly_words_per_exp(bits, ctx->minfo);
822 ulong * cmpmask;
823 TMP_INIT;
824
825 TMP_START;
826
827 FLINT_ASSERT(A != B);
828 FLINT_ASSERT(bits == A->bits);
829 FLINT_ASSERT(bits == B->bits);
830 FLINT_ASSERT(bits == c->bits);
831
832 fq_nmod_mpolyu_fit_length(A, B->length, ctx);
833
834 cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
835 mpoly_get_cmpmask(cmpmask, N, bits, ctx->minfo);
836
837 for (i = 0; i < B->length; i++)
838 {
839 A->exps[i] = B->exps[i];
840 fq_nmod_mpoly_fit_length(A->coeffs + i, B->coeffs[i].length + c->length, ctx);
841 _fq_nmod_mpoly_mul_johnson(A->coeffs + i, c->coeffs, c->exps, c->length,
842 B->coeffs[i].coeffs, B->coeffs[i].exps, B->coeffs[i].length,
843 bits, N, cmpmask, ctx->fqctx);
844 }
845 A->length = B->length;
846
847 TMP_END;
848 }
849
850
fq_nmod_mpolyu_mul_mpoly_inplace(fq_nmod_mpolyu_t A,fq_nmod_mpoly_t c,const fq_nmod_mpoly_ctx_t ctx)851 void fq_nmod_mpolyu_mul_mpoly_inplace(
852 fq_nmod_mpolyu_t A,
853 fq_nmod_mpoly_t c,
854 const fq_nmod_mpoly_ctx_t ctx)
855 {
856 flint_bitcnt_t bits = A->bits;
857 slong N = mpoly_words_per_exp(bits, ctx->minfo);
858 slong i;
859 ulong * cmpmask;
860 fq_nmod_mpoly_t t;
861 TMP_INIT;
862
863 FLINT_ASSERT(bits == c->bits);
864 FLINT_ASSERT(c->length > 0);
865
866 if (fq_nmod_mpoly_is_fq_nmod(c, ctx))
867 {
868 if (n_fq_is_one(c->coeffs + 0, ctx->fqctx))
869 return;
870
871 for (i = 0; i < A->length; i++)
872 fq_nmod_mpoly_scalar_mul_n_fq(A->coeffs + i, A->coeffs + i,
873 c->coeffs + 0, ctx);
874 return;
875 }
876
877 fq_nmod_mpoly_init3(t, 0, bits, ctx);
878
879 TMP_START;
880
881 cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
882 mpoly_get_cmpmask(cmpmask, N, bits, ctx->minfo);
883
884 for (i = A->length - 1; i >= 0; i--)
885 {
886 FLINT_ASSERT(A->coeffs[i].bits == bits);
887 _fq_nmod_mpoly_mul_johnson(t, A->coeffs[i].coeffs,
888 A->coeffs[i].exps, A->coeffs[i].length, c->coeffs, c->exps,
889 c->length, bits, N, cmpmask, ctx->fqctx);
890 fq_nmod_mpoly_swap(A->coeffs + i, t, ctx);
891 FLINT_ASSERT(A->coeffs[i].length > 0);
892 }
893
894 TMP_END;
895
896 fq_nmod_mpoly_clear(t, ctx);
897 }
898
899
fq_nmod_mpolyu_content_mpoly(fq_nmod_mpoly_t g,const fq_nmod_mpolyu_t A,const fq_nmod_mpoly_ctx_t ctx)900 int fq_nmod_mpolyu_content_mpoly(
901 fq_nmod_mpoly_t g,
902 const fq_nmod_mpolyu_t A,
903 const fq_nmod_mpoly_ctx_t ctx)
904 {
905 int success;
906
907 success = _fq_nmod_mpoly_vec_content_mpoly(g, A->coeffs, A->length, ctx);
908 if (!success)
909 fq_nmod_mpoly_zero(g, ctx);
910
911 fq_nmod_mpoly_repack_bits_inplace(g, A->bits, ctx);
912
913 return success;
914 }
915