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