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 #include "fq_nmod_mpoly.h"
14 
nmod_mpolyd_ctx_init(nmod_mpolyd_ctx_t dctx,slong nvars)15 void nmod_mpolyd_ctx_init(nmod_mpolyd_ctx_t dctx, slong nvars)
16 {
17     slong i;
18 
19     dctx->nvars = nvars;
20     dctx->perm = (slong *) flint_malloc(nvars*sizeof(slong));
21     for (i = 0; i < nvars; i++)
22     {
23         dctx->perm[i] = i;
24     }
25 }
26 
nmod_mpolyd_ctx_clear(nmod_mpolyd_ctx_t dctx)27 void nmod_mpolyd_ctx_clear(nmod_mpolyd_ctx_t dctx)
28 {
29     flint_free(dctx->perm);
30 }
31 
nmod_mpolyd_init(nmod_mpolyd_t poly,slong nvars)32 void nmod_mpolyd_init(nmod_mpolyd_t poly, slong nvars)
33 {
34     slong i;
35 
36     poly->nvars = nvars;
37     poly->degb_alloc = nvars;
38     poly->deg_bounds = (slong *) flint_malloc(poly->degb_alloc*sizeof(slong));
39     for (i = 0; i < nvars; i++)
40     {
41         poly->deg_bounds[i] = WORD(1);
42     }
43     poly->coeff_alloc = WORD(16);
44     poly->coeffs = (mp_limb_t *) flint_malloc(poly->coeff_alloc*sizeof(mp_limb_t));
45     for (i = 0; i < poly->coeff_alloc; i++)
46     {
47         poly->coeffs[i] = UWORD(0);
48     }
49 }
50 
nmod_mpolyd_fit_length(nmod_mpolyd_t poly,slong len)51 void nmod_mpolyd_fit_length(nmod_mpolyd_t poly, slong len) {
52     if (poly->coeff_alloc < len) {
53 /*flint_printf("realloc %wd -> %wd\n",poly->coeff_alloc, len);*/
54         poly->coeffs = (mp_limb_t *) flint_realloc(poly->coeffs, len*sizeof(mp_limb_t));
55         poly->coeff_alloc = len;
56     }
57 }
58 
nmod_mpolyd_set_nvars(nmod_mpolyd_t poly,slong nvars)59 void nmod_mpolyd_set_nvars(nmod_mpolyd_t poly, slong nvars) {
60 
61     poly->nvars = nvars;
62     if (poly->degb_alloc < nvars) {
63         poly->deg_bounds = (slong *) flint_realloc(poly->deg_bounds, nvars*sizeof(slong));
64         poly->degb_alloc = nvars;
65     }
66 }
67 
nmod_mpolyd_zero(nmod_mpolyd_t poly)68 void nmod_mpolyd_zero(nmod_mpolyd_t poly)
69 {
70     slong i;
71 
72     for (i = 0; i < poly->nvars; i++)
73     {
74         poly->deg_bounds[i] = WORD(1);
75     }
76     poly->coeffs[0] = UWORD(0);
77 }
78 
nmod_mpolyd_clear(nmod_mpolyd_t poly)79 void nmod_mpolyd_clear(nmod_mpolyd_t poly)
80 {
81     flint_free(poly->deg_bounds);
82     flint_free(poly->coeffs);
83     poly->deg_bounds = NULL;
84     poly->coeffs = NULL;
85 }
86 
87 
nmod_mpolyd_set_degbounds(nmod_mpolyd_t A,slong * bounds)88 int nmod_mpolyd_set_degbounds(nmod_mpolyd_t A, slong * bounds)
89 {
90     slong i;
91     int success = 0;
92     slong degb_prod;
93 
94     degb_prod = 1;
95     for (i = 0; i < A->nvars; i++)
96     {
97         ulong hi;
98         A->deg_bounds[i] = bounds[i];
99         umul_ppmm(hi, degb_prod, degb_prod, A->deg_bounds[i]);
100         if (hi != WORD(0) || degb_prod < 0)
101         {
102             goto done;
103         }
104     }
105 
106     success = 1;
107     nmod_mpolyd_fit_length(A, degb_prod);
108 
109 done:
110     return success;
111 }
112 
nmod_mpolyd_set_degbounds_perm(nmod_mpolyd_t A,const nmod_mpolyd_ctx_t dctx,slong * bounds)113 int nmod_mpolyd_set_degbounds_perm(nmod_mpolyd_t A, const nmod_mpolyd_ctx_t dctx, slong * bounds)
114 {
115     slong i;
116     int success = 0;
117     const slong * perm = dctx->perm;
118     slong degb_prod;
119 
120     degb_prod = 1;
121     for (i = 0; i < A->nvars; i++)
122     {
123         ulong hi;
124         A->deg_bounds[i] = bounds[perm[i]];
125         umul_ppmm(hi, degb_prod, degb_prod, A->deg_bounds[i]);
126         if (hi != WORD(0) || degb_prod < 0)
127         {
128             goto done;
129         }
130     }
131 
132     success = 1;
133     nmod_mpolyd_fit_length(A, degb_prod);
134 
135 done:
136     return success;
137 }
138 
139 
140 /*
141     m is the number of variables in A
142 */
nmod_mpoly_to_nmod_mpolyd_perm_deflate(nmod_mpolyd_t A,slong m,const nmod_mpoly_t B,const slong * perm,const ulong * shift,const ulong * stride,const ulong * degree,const nmod_mpoly_ctx_t ctx)143 void nmod_mpoly_to_nmod_mpolyd_perm_deflate(nmod_mpolyd_t A, slong m,
144               const nmod_mpoly_t B, const slong * perm, const ulong * shift,
145         const ulong * stride, const ulong * degree, const nmod_mpoly_ctx_t ctx)
146 {
147     slong n = ctx->minfo->nvars;
148     slong degb_prod;
149     slong i, k, l, N;
150     ulong * Bexp;
151     TMP_INIT;
152 
153     FLINT_ASSERT(m <= n);
154     FLINT_ASSERT(B->bits <= FLINT_BITS);
155     FLINT_ASSERT(B->length > 0);
156 
157     nmod_mpolyd_set_nvars(A, m);
158 
159     TMP_START;
160     Bexp = (ulong *) TMP_ALLOC(n*sizeof(slong));
161 
162     degb_prod = WORD(1);
163     for (k = 0; k < m; k++)
164     {
165         l = perm[k];
166         FLINT_ASSERT(stride[l] != UWORD(0));
167         FLINT_ASSERT((degree[l] - shift[l]) % stride[l] == UWORD(0));
168         A->deg_bounds[k] = (degree[l] - shift[l])/stride[l] + 1;
169         degb_prod *= A->deg_bounds[k];
170         /* we should not be converting something whose dense size overflows */
171         FLINT_ASSERT(degb_prod > 0);
172         FLINT_ASSERT(degb_prod >= A->deg_bounds[k]);
173     }
174 
175     nmod_mpolyd_fit_length(A, degb_prod);
176     for (i = 0; i < degb_prod; i++)
177     {
178         A->coeffs[i] = UWORD(0);
179     }
180 
181     N = mpoly_words_per_exp(B->bits, ctx->minfo);
182     for (i = 0; i < B->length; i++)
183     {
184         slong off = 0;
185         mpoly_get_monomial_ui(Bexp, B->exps + N*i, B->bits, ctx->minfo);
186         for (k = 0; k < m; k++)
187         {
188             l = perm[k];
189             FLINT_ASSERT(stride[l] != UWORD(0));
190             FLINT_ASSERT(((Bexp[l] - shift[l]) % stride[l]) == UWORD(0));
191             FLINT_ASSERT((Bexp[l] - shift[l])/stride[l] < A->deg_bounds[k]);
192             off = (Bexp[l] - shift[l])/stride[l] + A->deg_bounds[k]*off;
193         }
194         A->coeffs[off] = B->coeffs[i];
195     }
196 
197     TMP_END;
198 }
199 
200 
nmod_mpoly_from_nmod_mpolyd_perm_inflate(nmod_mpoly_t A,flint_bitcnt_t Abits,const nmod_mpoly_ctx_t ctx,const nmod_mpolyd_t B,const slong * perm,const ulong * shift,const ulong * stride)201 void nmod_mpoly_from_nmod_mpolyd_perm_inflate(nmod_mpoly_t A,
202          flint_bitcnt_t Abits, const nmod_mpoly_ctx_t ctx, const nmod_mpolyd_t B,
203                  const slong * perm, const ulong * shift, const ulong * stride)
204 {
205     slong off;
206     slong n = ctx->minfo->nvars;
207     slong m = B->nvars;
208     slong Alen;
209     slong i, j, l, k, N;
210     slong perm_nontrivial;
211     ulong topmask;
212     ulong * exps, * pcurexp, * pexps;
213     TMP_INIT;
214 
215     FLINT_ASSERT(m <= n);
216     FLINT_ASSERT(Abits <= FLINT_BITS);
217 
218     perm_nontrivial = n - m;
219 
220     /* we are going to push back terms manually */
221     Alen = 0;
222     nmod_mpoly_zero(A, ctx);
223     nmod_mpoly_fit_bits(A, Abits, ctx);
224     A->bits = Abits;
225 
226     N = mpoly_words_per_exp(Abits, ctx->minfo);
227 
228     TMP_START;
229 
230     /* find exponent vector for all variables in B */
231     pexps = (ulong *) TMP_ALLOC(N*m*sizeof(ulong));
232     for (k = 0; k < m; k++)
233     {
234         l = perm[k];
235         perm_nontrivial |= l - k;
236         mpoly_gen_monomial_sp(pexps + k*N, l, Abits, ctx->minfo);
237         mpoly_monomial_mul_ui(pexps + k*N, pexps + k*N, N, stride[l]);
238     }
239 
240     /* get most significant exponent in pcurexp and its vector in exps */
241     pcurexp = (ulong *) TMP_ALLOC(N*sizeof(ulong));
242     exps = (ulong *) TMP_ALLOC(m*sizeof(ulong));
243     off = WORD(1);
244     for (j = 0; j < m; j++)
245     {
246         off *= B->deg_bounds[j];
247     }
248     FLINT_ASSERT(off <= B->coeff_alloc);
249     off--;
250     mpoly_set_monomial_ui(pcurexp, shift, Abits, ctx->minfo);
251     i = off;
252     for (k = m - 1; k >= 0; k--)
253     {
254         exps[k] = i % B->deg_bounds[k];
255         i = i / B->deg_bounds[k];
256         mpoly_monomial_madd(pcurexp, pcurexp, exps[k], pexps + N*k, N);
257     }
258 
259     /* scan down through the exponents */
260     topmask = 0;
261 
262     for (; off >= 0; off--)
263     {
264         if (B->coeffs[off] != UWORD(0))
265         {
266             _nmod_mpoly_fit_length(&A->coeffs, &A->exps, &A->alloc, Alen + 1, N);
267             A->coeffs[Alen] = B->coeffs[off];
268             mpoly_monomial_set(A->exps + N*Alen, pcurexp, N);
269             topmask |= pcurexp[N - 1];
270             Alen++;
271         }
272 
273         k = m - 1;
274         do {
275             --exps[k];
276             if ((slong)(exps[k]) < WORD(0))
277             {
278                 FLINT_ASSERT(off == 0 || k > 0);
279                 FLINT_ASSERT(exps[k] == -UWORD(1));
280                 exps[k] = B->deg_bounds[k] - 1;
281                 mpoly_monomial_madd(pcurexp, pcurexp, exps[k], pexps + N*k, N);
282             }
283             else
284             {
285                 mpoly_monomial_sub(pcurexp, pcurexp, pexps + N*k, N);
286                 break;
287             }
288         } while (--k >= 0);
289     }
290     _nmod_mpoly_set_length(A, Alen, ctx);
291 
292     /* sort the terms if needed */
293     if (ctx->minfo->ord != ORD_LEX || perm_nontrivial != WORD(0))
294     {
295         slong msb;
296         mpoly_get_cmpmask(pcurexp, N, Abits, ctx->minfo);
297         if (topmask != WORD(0))
298         {
299             count_leading_zeros(msb, topmask);
300             msb = (FLINT_BITS - 1)^msb;
301         }
302         else
303         {
304             msb = -WORD(1);
305         }
306         if (N == 1)
307         {
308             if (msb >= WORD(0))
309             {
310                 _nmod_mpoly_radix_sort1(A, 0, A->length,
311                                                    msb, pcurexp[0], topmask);
312             }
313         }
314         else
315         {
316             _nmod_mpoly_radix_sort(A, 0, A->length,
317                                         (N - 1)*FLINT_BITS + msb, N, pcurexp);
318         }
319     }
320 
321     TMP_END;
322 }
323 
324 
325 /*
326     convert B to A assuming degree bounds have been set in A
327 */
nmod_mpoly_convert_to_nmod_mpolyd_degbound(nmod_mpolyd_t A,const nmod_mpolyd_ctx_t dctx,const nmod_mpoly_t B,const nmod_mpoly_ctx_t ctx)328 void nmod_mpoly_convert_to_nmod_mpolyd_degbound(nmod_mpolyd_t A,
329                                 const nmod_mpolyd_ctx_t dctx,
330                               const nmod_mpoly_t B, const nmod_mpoly_ctx_t ctx)
331 {
332     slong degb_prod;
333     slong i, j, N;
334     ulong * exps;
335     const slong * perm = dctx->perm;
336     slong nvars = ctx->minfo->nvars;
337     TMP_INIT;
338 
339     FLINT_ASSERT(A->nvars == nvars);
340     FLINT_ASSERT(B->bits <= FLINT_BITS);
341 
342     degb_prod = WORD(1);
343     for (i = 0; i < nvars; i++)
344     {
345         degb_prod *= A->deg_bounds[i];
346     }
347 
348     for (i = 0; i < degb_prod; i++)
349     {
350         A->coeffs[i] = UWORD(0);
351     }
352 
353     TMP_START;
354     exps = (ulong *) TMP_ALLOC(nvars*sizeof(ulong));
355     N = mpoly_words_per_exp(B->bits, ctx->minfo);
356 
357     for (i = 0; i < B->length; i++)
358     {
359         slong off;
360 
361         mpoly_get_monomial_ui(exps, B->exps + N*i, B->bits, ctx->minfo);
362         off = 0;
363         for (j = 0; j < nvars; j++)
364         {
365             off = exps[perm[j]] + A->deg_bounds[j]*off;
366         }
367         A->coeffs[off] =  B->coeffs[i];
368     }
369 
370     TMP_END;
371 }
372 
373 /*
374     convert B to A - sets degree bounds in A
375 */
nmod_mpoly_convert_to_nmod_mpolyd(nmod_mpolyd_t A,const nmod_mpolyd_ctx_t dctx,const nmod_mpoly_t B,const nmod_mpoly_ctx_t ctx)376 void nmod_mpoly_convert_to_nmod_mpolyd(
377                             nmod_mpolyd_t A, const nmod_mpolyd_ctx_t dctx,
378                           const nmod_mpoly_t B, const nmod_mpoly_ctx_t ctx)
379 {
380     slong degb_prod;
381     slong i, j, N;
382     slong * exps;
383     const slong * perm = dctx->perm;
384     slong nvars = ctx->minfo->nvars;
385     TMP_INIT;
386 
387     nmod_mpolyd_set_nvars(A, ctx->minfo->nvars);
388 
389     FLINT_ASSERT(B->bits <= FLINT_BITS);
390 
391     if (B->length == 0)
392     {
393         nmod_mpolyd_zero(A);
394         return;
395     }
396 
397     TMP_START;
398     exps = (slong *) TMP_ALLOC(ctx->minfo->nvars*sizeof(slong));
399 
400     nmod_mpoly_degrees_si(exps, B, ctx);
401     degb_prod = WORD(1);
402     for (i = 0; i < nvars; i++)
403     {
404         A->deg_bounds[i] = exps[perm[i]] + 1;
405         degb_prod *= A->deg_bounds[i];
406     }
407 
408     nmod_mpolyd_fit_length(A, degb_prod);
409     for (i = 0; i < degb_prod; i++)
410     {
411         A->coeffs[i] = UWORD(0);
412     }
413 
414     N = mpoly_words_per_exp(B->bits, ctx->minfo);
415     for (i = 0; i < B->length; i++)
416     {
417         slong off = 0;
418 
419         mpoly_get_monomial_ui((ulong *)exps, B->exps + N*i, B->bits, ctx->minfo);
420         for (j = 0; j < nvars; j++)
421         {
422             off = exps[perm[j]] + A->deg_bounds[j]*off;
423         }
424 
425         A->coeffs[off] = B->coeffs[i];
426     }
427 
428     TMP_END;
429 }
430 
431 /*
432     Convert B to A
433 */
nmod_mpoly_convert_from_nmod_mpolyd(nmod_mpoly_t A,const nmod_mpoly_ctx_t ctx,const nmod_mpolyd_t B,const nmod_mpolyd_ctx_t dctx)434 void nmod_mpoly_convert_from_nmod_mpolyd(nmod_mpoly_t A, const nmod_mpoly_ctx_t ctx,
435                            const nmod_mpolyd_t B, const nmod_mpolyd_ctx_t dctx)
436 {
437     slong off, j, k, N;
438     slong bits, nvars = ctx->minfo->nvars;
439     slong Alen;
440     slong * perm = dctx->perm;
441     slong perm_nontrivial = 0;
442     ulong topmask;
443     ulong * exps, * pcurexp, * pexps;
444     TMP_INIT;
445 
446     FLINT_ASSERT(nvars == B->nvars);
447 
448     TMP_START;
449     exps = (ulong *) TMP_ALLOC(nvars*sizeof(ulong));
450 
451     /* find bits needed for the result */
452     off = 1;
453     for (j = 0; j < nvars; j++)
454     {
455         off *= B->deg_bounds[j];
456         exps[perm[j]] = B->deg_bounds[j] - 1;
457         perm_nontrivial |= j ^ perm[j];
458     }
459 
460     FLINT_ASSERT(off <= B->coeff_alloc);
461 
462     bits = mpoly_exp_bits_required_ui(exps, ctx->minfo);
463     bits = mpoly_fix_bits(bits, ctx->minfo);
464     N = mpoly_words_per_exp(bits, ctx->minfo);
465 
466     /* we are going to push back terms manually */
467     Alen = 0;
468     nmod_mpoly_zero(A, ctx);
469     nmod_mpoly_fit_bits(A, bits, ctx);
470     A->bits = bits;
471 
472     /* find exponent vector for all variables */
473     pexps = (ulong *) TMP_ALLOC(N*nvars*sizeof(ulong));
474     for (k = 0; k < nvars; k++)
475     {
476         for (j = 0; j < nvars; j++)
477             exps[perm[j]] = (j == k);
478         mpoly_set_monomial_ui(pexps + k*N, exps, bits, ctx->minfo);
479     }
480 
481     /* get most significant exponent in exps and its vector in ptempexp */
482     off--;
483     pcurexp = (ulong *) TMP_ALLOC(N*sizeof(ulong));
484     mpoly_monomial_zero(pcurexp, N);
485     k = off;
486     for (j = nvars - 1; j >= 0; j--)
487     {
488         exps[j] = k % B->deg_bounds[j];
489         k = k / B->deg_bounds[j];
490         mpoly_monomial_madd_inplace_mp(pcurexp, exps[j], pexps + N*j, N);
491     }
492 
493     /* scan down through the exponents */
494     topmask = 0;
495     for (; off >= 0; off--)
496     {
497         if (B->coeffs[off] != UWORD(0))
498         {
499             _nmod_mpoly_fit_length(&A->coeffs, &A->exps, &A->alloc, Alen + 1, N);
500             A->coeffs[Alen] = B->coeffs[off];
501             mpoly_monomial_set(A->exps + N*Alen, pcurexp, N);
502             topmask |= (A->exps + N*Alen)[N - 1];
503             Alen++;
504         }
505 
506         j = nvars - 1;
507         do {
508             --exps[j];
509             if ((slong)(exps[j]) < WORD(0))
510             {
511                 FLINT_ASSERT(off == 0 || j > 0);
512                 FLINT_ASSERT(exps[j] == -UWORD(1));
513                 exps[j] = B->deg_bounds[j] - 1;
514                 mpoly_monomial_madd_inplace_mp(pcurexp, exps[j], pexps + N*j, N);
515             } else
516             {
517                 mpoly_monomial_sub_mp(pcurexp, pcurexp, pexps + N*j, N);
518                 break;
519             }
520         } while (--j >= 0);
521     }
522     _nmod_mpoly_set_length(A, Alen, ctx);
523 
524     /* sort the exponents if needed */
525     if (ctx->minfo->ord != ORD_LEX || perm_nontrivial != WORD(0))
526     {
527         slong msb;
528         mpoly_get_cmpmask(pcurexp, N, bits, ctx->minfo);
529         if (topmask != WORD(0))
530         {
531             count_leading_zeros(msb, topmask);
532             msb = (FLINT_BITS - 1)^msb;
533         } else
534         {
535             msb = -WORD(1);
536         }
537         if (N == 1) {
538             if (msb >= WORD(0))
539             {
540                 _nmod_mpoly_radix_sort1(A, 0, A->length,
541                                                    msb, pcurexp[0], topmask);
542             }
543         } else {
544             _nmod_mpoly_radix_sort(A, 0, A->length,
545                                         (N - 1)*FLINT_BITS + msb, N, pcurexp);
546         }
547     }
548 
549     TMP_END;
550 }
551 
552 
nmod_mpolyd_print(nmod_mpolyd_t poly)553 void nmod_mpolyd_print(nmod_mpolyd_t poly)
554 {
555 
556     int first = 0;
557     slong i, j;
558     slong degb_prod;
559 
560     degb_prod = WORD(1);
561     for (j = 0; j < poly->nvars; j++) {
562         degb_prod *= poly->deg_bounds[j];
563     }
564 
565     first = 1;
566     for (i = 0; i < degb_prod; i++) {
567         ulong k = i;
568 
569         if (poly->coeffs[i] == 0)
570             continue;
571 
572         if (!first)
573             printf(" + ");
574 
575         flint_printf("%wu", poly->coeffs[i]);
576 
577         for (j = poly->nvars - 1; j >= 0; j--)
578         {
579             ulong m = poly->deg_bounds[j];
580             ulong e = k % m;
581             k = k / m;
582             flint_printf("*x%wd^%wd", j, e);
583         }
584         FLINT_ASSERT(k == 0);
585         first = 0;
586     }
587 
588     if (first)
589         flint_printf("0");
590 }
591 
nmod_mpolyd_length(const nmod_mpolyd_t A)592 slong nmod_mpolyd_length(const nmod_mpolyd_t A)
593 {
594     slong i, j, degb_prod;
595 
596     degb_prod = WORD(1);
597     for (j = 0; j < A->nvars; j++)
598         degb_prod *= A->deg_bounds[j];
599 
600     for (i = degb_prod; i > 0; i--)
601     {
602         if (A->coeffs[i - 1] != UWORD(0))
603             break;
604     }
605 
606     return i;
607 }
608 
nmod_mpolyd_last_degree(const nmod_mpolyd_t A,const nmodf_ctx_t fctx)609 slong nmod_mpolyd_last_degree(const nmod_mpolyd_t A, const nmodf_ctx_t fctx)
610 {
611     slong i, j, Plen, degree;
612     slong degb_prod, degb_last=0;
613 
614     degb_prod = WORD(1);
615     for (j = 0; j < A->nvars; j++) {
616         degb_last = A->deg_bounds[j];
617         degb_prod *= degb_last;
618     }
619 
620     degree = -1;
621     for (i = 0; i < degb_prod; i += degb_last)
622     {
623         mp_limb_t * P = A->coeffs + i;
624         Plen = degb_last;
625         while (P[Plen-1] == 0)
626         {
627             Plen --;
628             if (Plen == 0)
629                 break;
630         }
631         degree = FLINT_MAX(degree, Plen - 1);
632         if (degree + 1 == degb_last)
633             return degree;
634     }
635     return degree;
636 }
637 
nmod_mpoly_convert_to_fq_nmod_mpolyd(fq_nmod_mpolyd_t poly1,const fq_nmod_mpolyd_ctx_t dctx,const nmod_mpoly_t poly2,const nmod_mpoly_ctx_t ctx)638 void nmod_mpoly_convert_to_fq_nmod_mpolyd(
639                        fq_nmod_mpolyd_t poly1, const fq_nmod_mpolyd_ctx_t dctx,
640                           const nmod_mpoly_t poly2, const nmod_mpoly_ctx_t ctx)
641 {
642     slong degb_prod;
643     slong i, j, N;
644     slong * exps;
645     const slong * perm = dctx->perm;
646     slong nvars = ctx->minfo->nvars;
647     TMP_INIT;
648 
649     fq_nmod_mpolyd_set_nvars(poly1, ctx->minfo->nvars);
650 
651     FLINT_ASSERT(poly2->bits <= FLINT_BITS);
652 
653     if (poly2->length == 0)
654     {
655         fq_nmod_mpolyd_zero(poly1, dctx->fqctx);
656         return;
657     }
658 
659     TMP_START;
660     exps = (slong *) TMP_ALLOC(ctx->minfo->nvars*sizeof(slong));
661 
662     nmod_mpoly_degrees_si(exps, poly2, ctx);
663     degb_prod = WORD(1);
664     for (i = 0; i < nvars; i++)
665     {
666         poly1->deg_bounds[i] = exps[perm[i]] + 1;
667         degb_prod *= poly1->deg_bounds[i];
668     }
669 
670     fq_nmod_mpolyd_fit_length(poly1, degb_prod, dctx->fqctx);
671     for (i = 0; i < degb_prod; i++)
672     {
673         fq_nmod_zero(poly1->coeffs + i, dctx->fqctx);
674     }
675 
676     N = mpoly_words_per_exp(poly2->bits, ctx->minfo);
677     for (i = 0; i < poly2->length; i++)
678     {
679         slong off = 0;
680 
681         mpoly_get_monomial_ui((ulong *)exps, poly2->exps + N*i,
682                                                       poly2->bits, ctx->minfo);
683         for (j = 0; j < nvars; j++)
684         {
685             off = exps[perm[j]] + poly1->deg_bounds[j]*off;
686         }
687         fq_nmod_set_ui(poly1->coeffs + off, poly2->coeffs[i], dctx->fqctx);
688     }
689 
690     TMP_END;
691 }
692 
693 
nmod_mpoly_convert_from_fq_nmod_mpolyd(nmod_mpoly_t A,const nmod_mpoly_ctx_t ctx,const fq_nmod_mpolyd_t B,const fq_nmod_mpolyd_ctx_t dctx)694 void nmod_mpoly_convert_from_fq_nmod_mpolyd(
695                                nmod_mpoly_t A, const nmod_mpoly_ctx_t ctx,
696                      const fq_nmod_mpolyd_t B, const fq_nmod_mpolyd_ctx_t dctx)
697 {
698     slong i, j;
699     slong degb_prod;
700     slong * perm = dctx->perm;
701     ulong * exps;
702     TMP_INIT;
703 
704     FLINT_ASSERT(ctx->minfo->nvars == B->nvars);
705 
706     degb_prod = WORD(1);
707     for (j = 0; j < B->nvars; j++) {
708         degb_prod *= B->deg_bounds[j];
709     }
710 
711     TMP_START;
712     exps = (ulong *) TMP_ALLOC(B->nvars*sizeof(ulong));
713 
714     nmod_mpoly_zero(A, ctx);
715     for (i = 0; i < degb_prod; i++) {
716         ulong k = i;
717 
718         if (fq_nmod_is_zero(B->coeffs + i, dctx->fqctx))
719             continue;
720 
721         for (j = B->nvars - 1; j >= 0; j--)
722         {
723             ulong m = B->deg_bounds[j];
724             ulong e = k % m;
725             k = k / m;
726             exps[perm[j]] = e;
727         }
728         FLINT_ASSERT(k == 0);
729 
730         /* need special function to convert F_q element to F_p element */
731         for (j=1; j < (B->coeffs + i)->length; j++) {
732             FLINT_ASSERT((B->coeffs + i)->coeffs[j] == 0);
733         }
734         nmod_mpoly_set_term_ui_ui(A, (B->coeffs + i)->coeffs[0], exps, ctx);
735     }
736 
737     TMP_END;
738 }
739