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 
15 
fq_nmod_mpolyun_init(fq_nmod_mpolyun_t A,flint_bitcnt_t bits,const fq_nmod_mpoly_ctx_t ctx)16 void fq_nmod_mpolyun_init(
17     fq_nmod_mpolyun_t A,
18     flint_bitcnt_t bits,
19     const fq_nmod_mpoly_ctx_t ctx)
20 {
21     A->coeffs = NULL;
22     A->exps = NULL;
23     A->alloc = 0;
24     A->length = 0;
25     A->bits = bits;
26 }
27 
28 
fq_nmod_mpolyun_clear(fq_nmod_mpolyun_t A,const fq_nmod_mpoly_ctx_t ctx)29 void fq_nmod_mpolyun_clear(
30     fq_nmod_mpolyun_t A,
31     const fq_nmod_mpoly_ctx_t ctx)
32 {
33     slong i;
34     for (i = 0; i < A->alloc; i++)
35         fq_nmod_mpolyn_clear(A->coeffs + i, ctx);
36     flint_free(A->coeffs);
37     flint_free(A->exps);
38 }
39 
40 
fq_nmod_mpolyun_is_canonical(const fq_nmod_mpolyun_t A,const fq_nmod_mpoly_ctx_t ctx)41 int fq_nmod_mpolyun_is_canonical(
42     const fq_nmod_mpolyun_t A,
43     const fq_nmod_mpoly_ctx_t ctx)
44 {
45     slong i;
46 
47     if (A->length > A->alloc)
48     {
49         return 0;
50     }
51 
52     for (i = 0; i < A->length; i++)
53     {
54         if (!fq_nmod_mpolyn_is_canonical(A->coeffs + i, ctx))
55         {
56             return 0;
57         }
58 
59         if (i > 0 && A->exps[i - 1] <= A->exps[i])
60         {
61             return 0;
62         }
63     }
64 
65     return 1;
66 }
67 
68 
fq_nmod_mpolyun_print_pretty(const fq_nmod_mpolyun_t poly,const char ** x,const fq_nmod_mpoly_ctx_t ctx)69 void fq_nmod_mpolyun_print_pretty(
70     const fq_nmod_mpolyun_t poly,
71     const char ** x,
72     const fq_nmod_mpoly_ctx_t ctx)
73 {
74     slong i;
75     if (poly->length == 0)
76         flint_printf("0");
77     for (i = 0; i < poly->length; i++)
78     {
79         if (i != 0)
80             flint_printf(" + ");
81         flint_printf("(");
82         fq_nmod_mpolyn_print_pretty(poly->coeffs + i,x,ctx);
83         flint_printf(")*X^%wd",poly->exps[i]);
84     }
85 }
86 
87 
fq_nmod_mpolyun_swap(fq_nmod_mpolyun_t A,fq_nmod_mpolyun_t B)88 void fq_nmod_mpolyun_swap(
89     fq_nmod_mpolyun_t A,
90     fq_nmod_mpolyun_t B)
91 {
92    fq_nmod_mpolyun_struct t = *A;
93    *A = *B;
94    *B = t;
95 }
96 
97 
fq_nmod_mpolyun_zero(fq_nmod_mpolyun_t A,const fq_nmod_mpoly_ctx_t ctx)98 void fq_nmod_mpolyun_zero(
99     fq_nmod_mpolyun_t A,
100     const fq_nmod_mpoly_ctx_t ctx)
101 {
102     slong i;
103     for (i = 0; i < A->alloc; i++) {
104         fq_nmod_mpolyn_clear(A->coeffs + i, ctx);
105         fq_nmod_mpolyn_init(A->coeffs + i, A->bits, ctx);
106     }
107     A->length = 0;
108 }
109 
110 
fq_nmod_mpolyun_fit_length(fq_nmod_mpolyun_t A,slong length,const fq_nmod_mpoly_ctx_t ctx)111 void fq_nmod_mpolyun_fit_length(
112     fq_nmod_mpolyun_t A,
113     slong length,
114     const fq_nmod_mpoly_ctx_t ctx)
115 {
116     slong i;
117     slong old_alloc = A->alloc;
118     slong new_alloc = FLINT_MAX(length, 2*A->alloc);
119 
120     if (length > old_alloc)
121     {
122         if (old_alloc == 0)
123         {
124             A->exps = (ulong *) flint_malloc(new_alloc*sizeof(ulong));
125             A->coeffs = (fq_nmod_mpolyn_struct *) flint_malloc(
126                                       new_alloc*sizeof(fq_nmod_mpolyn_struct));
127         }
128     else
129         {
130             A->exps = (ulong *) flint_realloc(A->exps,
131                                                       new_alloc*sizeof(ulong));
132             A->coeffs = (fq_nmod_mpolyn_struct *) flint_realloc(A->coeffs,
133                                       new_alloc*sizeof(fq_nmod_mpolyn_struct));
134         }
135 
136         for (i = old_alloc; i < new_alloc; i++)
137         {
138             fq_nmod_mpolyn_init(A->coeffs + i, A->bits, ctx);
139         }
140         A->alloc = new_alloc;
141     }
142 }
143 
144 
fq_nmod_mpolyun_one(fq_nmod_mpolyun_t A,const fq_nmod_mpoly_ctx_t ctx)145 void fq_nmod_mpolyun_one(
146     fq_nmod_mpolyun_t A,
147     const fq_nmod_mpoly_ctx_t ctx)
148 {
149     fq_nmod_mpolyun_fit_length(A, 1, ctx);
150     fq_nmod_mpolyn_one(A->coeffs + 0, ctx);
151     A->exps[0] = 0;
152     A->length = 1;
153 }
154 
155 
fq_nmod_mpolyn_is_nonzero_fq_nmod(const fq_nmod_mpolyn_t A,const fq_nmod_mpoly_ctx_t ctx)156 int fq_nmod_mpolyn_is_nonzero_fq_nmod(
157     const fq_nmod_mpolyn_t A,
158     const fq_nmod_mpoly_ctx_t ctx)
159 {
160     slong N;
161 
162     if (A->length != WORD(1))
163     {
164         return 0;
165     }
166 
167     if (fq_nmod_poly_degree(A->coeffs + 0, ctx->fqctx) != 0)
168     {
169         return 0;
170     }
171 
172     N = mpoly_words_per_exp(A->bits, ctx->minfo);
173     return mpoly_monomial_is_zero(A->exps + N*0, N);
174 }
175 
176 
fq_nmod_mpolyun_is_nonzero_fq_nmod(const fq_nmod_mpolyun_t A,const fq_nmod_mpoly_ctx_t ctx)177 int fq_nmod_mpolyun_is_nonzero_fq_nmod(
178     const fq_nmod_mpolyun_t A,
179     const fq_nmod_mpoly_ctx_t ctx)
180 {
181     if (A->length != 1 || A->exps[0] != 0)
182     {
183         return 0;
184     }
185 
186     return fq_nmod_mpolyn_is_nonzero_fq_nmod(A->coeffs + 0, ctx);
187 }
188 
189 
fq_nmod_mpolyn_scalar_mul_fq_nmod(fq_nmod_mpolyn_t A,const fq_nmod_t c,const fq_nmod_mpoly_ctx_t ctx)190 void fq_nmod_mpolyn_scalar_mul_fq_nmod(
191     fq_nmod_mpolyn_t A,
192     const fq_nmod_t c,
193     const fq_nmod_mpoly_ctx_t ctx)
194 {
195     slong i;
196 
197     FLINT_ASSERT(!fq_nmod_is_zero(c, ctx->fqctx));
198 
199     if (fq_nmod_is_one(c, ctx->fqctx))
200         return;
201 
202     for (i = 0; i < A->length; i++)
203     {
204         fq_nmod_poly_scalar_mul_fq_nmod(A->coeffs + i,
205                                         A->coeffs + i, c, ctx->fqctx);
206     }
207 }
208 
fq_nmod_mpolyun_scalar_mul_fq_nmod(fq_nmod_mpolyun_t A,const fq_nmod_t c,const fq_nmod_mpoly_ctx_t ctx)209 void fq_nmod_mpolyun_scalar_mul_fq_nmod(
210     fq_nmod_mpolyun_t A,
211     const fq_nmod_t c,
212     const fq_nmod_mpoly_ctx_t ctx)
213 {
214     slong i, j;
215     FLINT_ASSERT(!fq_nmod_is_zero(c, ctx->fqctx));
216     for (i = 0; i < A->length; i++)
217     {
218         fq_nmod_mpolyn_struct * Ai = A->coeffs + i;
219         for (j = 0; j < Ai->length; j++)
220         {
221             fq_nmod_poly_scalar_mul_fq_nmod(Ai->coeffs + j,
222                                             Ai->coeffs + j, c, ctx->fqctx);
223         }
224     }
225 }
226 
227 
fq_nmod_mpolyun_shift_right(fq_nmod_mpolyun_t A,ulong s)228 void fq_nmod_mpolyun_shift_right(
229     fq_nmod_mpolyun_t A,
230     ulong s)
231 {
232     slong i;
233     for (i = 0; i < A->length; i++)
234     {
235         FLINT_ASSERT(A->exps[i] >= s);
236         A->exps[i] -= s;
237     }
238 }
239 
240 
fq_nmod_mpolyun_shift_left(fq_nmod_mpolyun_t A,ulong s)241 void fq_nmod_mpolyun_shift_left(
242     fq_nmod_mpolyun_t A,
243     ulong s)
244 {
245     slong i;
246     for (i = 0; i < A->length; i++)
247     {
248         A->exps[i] += s;
249         FLINT_ASSERT(A->exps[i] >= s);
250     }
251 }
252 
253 
fq_nmod_mpolyn_mul_poly(fq_nmod_mpolyn_t A,const fq_nmod_mpolyn_t B,const fq_nmod_poly_t c,const fq_nmod_mpoly_ctx_t ctx,fq_nmod_poly_t t)254 void fq_nmod_mpolyn_mul_poly(
255     fq_nmod_mpolyn_t A,
256     const fq_nmod_mpolyn_t B,
257     const fq_nmod_poly_t c,
258     const fq_nmod_mpoly_ctx_t ctx,
259     fq_nmod_poly_t t  /* temp */)
260 {
261     slong i;
262     fq_nmod_poly_struct * Acoeff, * Bcoeff;
263     ulong * Aexp, * Bexp;
264     slong Blen = B->length;
265     slong N;
266 
267     FLINT_ASSERT(A->bits == B->bits);
268     FLINT_ASSERT(A->bits <= FLINT_BITS);
269     FLINT_ASSERT(!fq_nmod_poly_is_zero(c, ctx->fqctx));
270 
271     if (A == B)
272     {
273         Acoeff = A->coeffs;
274         for (i = 0; i < Blen; i++)
275         {
276             fq_nmod_poly_mul(t, Acoeff + i, c, ctx->fqctx);
277             fq_nmod_poly_swap(t, Acoeff + i, ctx->fqctx);
278         }
279     }
280     else
281     {
282         fq_nmod_mpolyn_fit_length(A, Blen, ctx);
283         Acoeff = A->coeffs;
284         Bcoeff = B->coeffs;
285         Aexp = A->exps;
286         Bexp = B->exps;
287 
288         N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
289 
290         for (i = 0; i < Blen; i++)
291         {
292             fq_nmod_poly_mul(Acoeff + i, Bcoeff + i, c, ctx->fqctx);
293             mpoly_monomial_set(Aexp + N*i, Bexp + N*i, N);
294         }
295         A->length = Blen;
296     }
297 }
298 
fq_nmod_mpolyun_mul_poly(fq_nmod_mpolyun_t A,const fq_nmod_mpolyun_t B,const fq_nmod_poly_t c,const fq_nmod_mpoly_ctx_t ctx)299 void fq_nmod_mpolyun_mul_poly(
300     fq_nmod_mpolyun_t A,
301     const fq_nmod_mpolyun_t B,
302     const fq_nmod_poly_t c,
303     const fq_nmod_mpoly_ctx_t ctx)
304 {
305     slong i, Blen;
306     fq_nmod_mpolyn_struct * Acoeff, * Bcoeff;
307     ulong * Aexp, * Bexp;
308     fq_nmod_poly_t t;
309 
310     FLINT_ASSERT(A->bits == B->bits);
311     FLINT_ASSERT(!fq_nmod_poly_is_zero(c, ctx->fqctx));
312 
313     fq_nmod_poly_init(t, ctx->fqctx);
314 
315     Blen = B->length;
316     fq_nmod_mpolyun_fit_length(A, Blen, ctx);
317     Acoeff = A->coeffs;
318     Bcoeff = B->coeffs;
319     Aexp = A->exps;
320     Bexp = B->exps;
321 
322     for (i = 0; i < Blen; i++)
323     {
324         fq_nmod_mpolyn_mul_poly(Acoeff + i, Bcoeff + i, c, ctx, t);
325         Aexp[i] = Bexp[i];
326     }
327     A->length = Blen;
328 
329     fq_nmod_poly_clear(t, ctx->fqctx);
330 }
331 
332 
fq_nmod_mpolyn_divexact_poly(fq_nmod_mpolyn_t A,const fq_nmod_mpolyn_t B,const fq_nmod_poly_t c,const fq_nmod_mpoly_ctx_t ctx,fq_nmod_poly_t q,fq_nmod_poly_t r)333 void fq_nmod_mpolyn_divexact_poly(
334     fq_nmod_mpolyn_t A,
335     const fq_nmod_mpolyn_t B,
336     const fq_nmod_poly_t c,
337     const fq_nmod_mpoly_ctx_t ctx,
338     fq_nmod_poly_t q, /* temp */
339     fq_nmod_poly_t r  /* temp */)
340 {
341     slong i;
342     fq_nmod_poly_struct * Acoeff, * Bcoeff;
343     ulong * Aexp, * Bexp;
344     slong Blen = B->length;
345     slong N;
346 
347     FLINT_ASSERT(A->bits == B->bits);
348     FLINT_ASSERT(A->bits <= FLINT_BITS);
349     FLINT_ASSERT(!fq_nmod_poly_is_zero(c, ctx->fqctx));
350 
351     if (A == B)
352     {
353         Acoeff = A->coeffs;
354         for (i = 0; i < Blen; i++)
355         {
356             fq_nmod_poly_divrem(q, r, Acoeff + i, c, ctx->fqctx);
357             FLINT_ASSERT(fq_nmod_poly_is_zero(r, ctx->fqctx));
358             fq_nmod_poly_swap(q, Acoeff + i, ctx->fqctx);
359         }
360     }
361     else
362     {
363         fq_nmod_mpolyn_fit_length(A, Blen, ctx);
364         Acoeff = A->coeffs;
365         Bcoeff = B->coeffs;
366         Aexp = A->exps;
367         Bexp = B->exps;
368 
369         N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
370 
371         for (i = 0; i < Blen; i++)
372         {
373             fq_nmod_poly_divrem(Acoeff + i, r, Bcoeff + i, c, ctx->fqctx);
374             FLINT_ASSERT(fq_nmod_poly_is_zero(r, ctx->fqctx));
375             mpoly_monomial_set(Aexp + N*i, Bexp + N*i, N);
376         }
377         A->length = Blen;
378     }
379 }
380 
fq_nmod_mpolyun_divexact_poly(fq_nmod_mpolyun_t A,const fq_nmod_mpolyun_t B,const fq_nmod_poly_t c,const fq_nmod_mpoly_ctx_t ctx)381 void fq_nmod_mpolyun_divexact_poly(
382     fq_nmod_mpolyun_t A,
383     const fq_nmod_mpolyun_t B,
384     const fq_nmod_poly_t c,
385     const fq_nmod_mpoly_ctx_t ctx)
386 {
387     slong i, Blen;
388     fq_nmod_mpolyn_struct * Acoeff, * Bcoeff;
389     ulong * Aexp, * Bexp;
390     fq_nmod_poly_t q, r;
391 
392     FLINT_ASSERT(A->bits == B->bits);
393     FLINT_ASSERT(!fq_nmod_poly_is_zero(c, ctx->fqctx));
394 
395     fq_nmod_poly_init(q, ctx->fqctx);
396     fq_nmod_poly_init(r, ctx->fqctx);
397 
398     Blen = B->length;
399     fq_nmod_mpolyun_fit_length(A, Blen, ctx);
400     Acoeff = A->coeffs;
401     Bcoeff = B->coeffs;
402     Aexp = A->exps;
403     Bexp = B->exps;
404 
405     for (i = 0; i < Blen; i++)
406     {
407         fq_nmod_mpolyn_divexact_poly(Acoeff + i, Bcoeff + i, c, ctx, q, r);
408         Aexp[i] = Bexp[i];
409     }
410     A->length = Blen;
411 
412     fq_nmod_poly_clear(q, ctx->fqctx);
413     fq_nmod_poly_clear(r, ctx->fqctx);
414 }
415 
416 
fq_nmod_mpolyn_content_poly(fq_nmod_poly_t g,fq_nmod_mpolyn_t B,const fq_nmod_mpoly_ctx_t ctx)417 void fq_nmod_mpolyn_content_poly(
418     fq_nmod_poly_t g,
419     fq_nmod_mpolyn_t B,
420     const fq_nmod_mpoly_ctx_t ctx)
421 {
422     slong i;
423     fq_nmod_poly_t t;
424 
425     fq_nmod_poly_zero(g, ctx->fqctx);
426     fq_nmod_poly_init(t, ctx->fqctx);
427 
428     for (i = 0; i < B->length; i++)
429     {
430         fq_nmod_poly_gcd(t, g, B->coeffs + i, ctx->fqctx);
431         fq_nmod_poly_swap(t, g, ctx->fqctx);
432         if (fq_nmod_poly_degree(g, ctx->fqctx) == 0)
433             break;
434     }
435 
436     fq_nmod_poly_clear(t, ctx->fqctx);
437 }
438 
fq_nmod_mpolyun_content_poly(fq_nmod_poly_t g,fq_nmod_mpolyun_t B,const fq_nmod_mpoly_ctx_t ctx)439 void fq_nmod_mpolyun_content_poly(
440     fq_nmod_poly_t g,
441     fq_nmod_mpolyun_t B,
442     const fq_nmod_mpoly_ctx_t ctx)
443 {
444     slong i, j;
445     fq_nmod_poly_t t;
446 
447     fq_nmod_poly_zero(g, ctx->fqctx);
448     fq_nmod_poly_init(t, ctx->fqctx);
449 
450     for (i = 0; i < B->length; i++)
451     {
452         for (j = 0; j < (B->coeffs + i)->length; j++)
453         {
454             fq_nmod_poly_gcd(t, g, (B->coeffs + i)->coeffs + j, ctx->fqctx);
455             fq_nmod_poly_swap(t, g, ctx->fqctx);
456             if (fq_nmod_poly_degree(g, ctx->fqctx) == 0)
457                 break;
458         }
459     }
460 
461     fq_nmod_poly_clear(t, ctx->fqctx);
462 }
463 
464 
fq_nmod_mpoly_to_mpolyn_perm_deflate(fq_nmod_mpolyn_t A,const fq_nmod_mpoly_ctx_t nctx,const fq_nmod_mpoly_t B,const fq_nmod_mpoly_ctx_t ctx,const slong * perm,const ulong * shift,const ulong * stride)465 void fq_nmod_mpoly_to_mpolyn_perm_deflate(
466     fq_nmod_mpolyn_t A,
467     const fq_nmod_mpoly_ctx_t nctx,
468     const fq_nmod_mpoly_t B,
469     const fq_nmod_mpoly_ctx_t ctx,
470     const slong * perm,
471     const ulong * shift,
472     const ulong * stride)
473 {
474     slong j, k, l;
475     slong NA = mpoly_words_per_exp_sp(A->bits, nctx->minfo);
476     slong NB = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
477     slong n = ctx->minfo->nvars;
478     slong m = nctx->minfo->nvars;
479     ulong * Bexps;
480     slong * offs, * shifts;
481     fq_nmod_mpoly_t T;
482     TMP_INIT;
483 
484     FLINT_ASSERT(m <= n);
485 
486     TMP_START;
487     Bexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
488 
489     offs   = (slong *) TMP_ALLOC(m*sizeof(ulong));
490     shifts = (slong *) TMP_ALLOC(m*sizeof(ulong));
491     for (k = 0; k < m; k++)
492     {
493         mpoly_gen_offset_shift_sp(offs + k, shifts + k, k, A->bits, nctx->minfo);
494     }
495 
496     fq_nmod_mpoly_init3(T, B->length, A->bits, nctx);
497     T->length = B->length;
498     for (j = 0; j < B->length; j++)
499     {
500         mpoly_get_monomial_ui(Bexps, B->exps + NB*j, B->bits, ctx->minfo);
501         fq_nmod_set(T->coeffs + j, B->coeffs + j, ctx->fqctx);
502         mpoly_monomial_zero(T->exps + NA*j, NA);
503         for (k = 0; k < m; k++)
504         {
505             l = perm[k];
506             (T->exps + NA*j)[offs[k]] += ((Bexps[l] - shift[l]) / stride[l]) << shifts[k];
507         }
508     }
509 
510     fq_nmod_mpoly_sort_terms(T, nctx);
511 
512     fq_nmod_mpoly_cvtto_mpolyn(A, T, nctx->minfo->nvars - 1, nctx);
513 
514     fq_nmod_mpoly_clear(T, nctx);
515 
516     TMP_END;
517 }
518 
fq_nmod_mpoly_from_mpolyn_perm_inflate(fq_nmod_mpoly_t A,flint_bitcnt_t Abits,const fq_nmod_mpoly_ctx_t ctx,const fq_nmod_mpolyn_t B,const fq_nmod_mpoly_ctx_t nctx,const slong * perm,const ulong * shift,const ulong * stride)519 void fq_nmod_mpoly_from_mpolyn_perm_inflate(
520     fq_nmod_mpoly_t A,
521     flint_bitcnt_t Abits,
522     const fq_nmod_mpoly_ctx_t ctx,
523     const fq_nmod_mpolyn_t B,
524     const fq_nmod_mpoly_ctx_t nctx,
525     const slong * perm,
526     const ulong * shift,
527     const ulong * stride)
528 {
529     slong n = ctx->minfo->nvars;
530     slong m = nctx->minfo->nvars;
531     slong i, h, k, l;
532     slong NA, NB;
533     slong Alen;
534     fq_nmod_struct * Acoeff;
535     ulong * Aexp;
536     slong Aalloc;
537     ulong * Bexps;
538     ulong * Aexps, * tAexp, * tAgexp;
539     TMP_INIT;
540 
541     FLINT_ASSERT(B->length > 0);
542     FLINT_ASSERT(Abits <= FLINT_BITS);
543     FLINT_ASSERT(B->bits <= FLINT_BITS);
544     FLINT_ASSERT(m <= n);
545     TMP_START;
546 
547     Bexps = (ulong *) TMP_ALLOC(m*sizeof(ulong));
548     Aexps = (ulong *) TMP_ALLOC(n*sizeof(ulong));
549 
550     NA = mpoly_words_per_exp(Abits, ctx->minfo);
551     NB = mpoly_words_per_exp(B->bits, nctx->minfo);
552 
553     tAexp = (ulong *) TMP_ALLOC(NA*sizeof(ulong));
554     tAgexp = (ulong *) TMP_ALLOC(NA*sizeof(ulong));
555     mpoly_gen_monomial_sp(tAgexp, perm[m - 1], Abits, ctx->minfo);
556     for (i = 0; i < NA; i++)
557         tAgexp[i] *= stride[perm[m - 1]];
558 
559     fq_nmod_mpoly_fit_bits(A, Abits, ctx);
560     A->bits = Abits;
561 
562     Acoeff = A->coeffs;
563     Aexp = A->exps;
564     Aalloc = A->alloc;
565     Alen = 0;
566     for (i = 0; i < B->length; i++)
567     {
568         mpoly_get_monomial_ui(Bexps, B->exps + NB*i, B->bits, nctx->minfo);
569         FLINT_ASSERT(Bexps[m - 1] == 0);
570         for (l = 0; l < n; l++)
571         {
572             Aexps[l] = shift[l];
573         }
574         for (k = 0; k < m; k++)
575         {
576             l = perm[k];
577             Aexps[l] += stride[l]*Bexps[k];
578         }
579 
580         mpoly_set_monomial_ui(tAexp, Aexps, Abits, ctx->minfo);
581 
582         h = (B->coeffs + i)->length;
583         _fq_nmod_mpoly_fit_length(&Acoeff, &Aexp, &Aalloc, Alen + h, NA, ctx->fqctx);
584         for (h--; h >= 0; h--)
585         {
586             fq_nmod_struct * c = (B->coeffs + i)->coeffs + h;
587             if (fq_nmod_is_zero(c, ctx->fqctx))
588                 continue;
589             mpoly_monomial_madd(Aexp + NA*Alen, tAexp, h, tAgexp, NA);
590             fq_nmod_set(Acoeff + Alen, c, ctx->fqctx);
591             Alen++;
592         }
593     }
594     A->coeffs = Acoeff;
595     A->exps = Aexp;
596     A->alloc = Aalloc;
597     A->length = Alen;
598 
599     fq_nmod_mpoly_sort_terms(A, ctx);
600     TMP_END;
601 }
602 
603 
fq_nmod_mpolyn_lastdeg(fq_nmod_mpolyn_t A,const fq_nmod_mpoly_ctx_t ctx)604 slong fq_nmod_mpolyn_lastdeg(
605     fq_nmod_mpolyn_t A,
606     const fq_nmod_mpoly_ctx_t ctx)
607 {
608     slong i;
609     slong deg = -WORD(1);
610 
611     for (i = 0; i < A->length; i++)
612     {
613         deg = FLINT_MAX(deg, fq_nmod_poly_degree(A->coeffs + i, ctx->fqctx));
614     }
615 
616     return deg;
617 }
618 
fq_nmod_mpolyun_lastdeg(fq_nmod_mpolyun_t A,const fq_nmod_mpoly_ctx_t ctx)619 slong fq_nmod_mpolyun_lastdeg(
620     fq_nmod_mpolyun_t A,
621     const fq_nmod_mpoly_ctx_t ctx)
622 {
623     slong i, j;
624     slong deg = -WORD(1);
625 
626     for (i = 0; i < A->length; i++)
627     {
628         fq_nmod_mpolyn_struct * Ai = A->coeffs + i;
629         for (j = 0; j < Ai->length; j++)
630         {
631             deg = FLINT_MAX(deg, fq_nmod_poly_degree(Ai->coeffs + j, ctx->fqctx));
632         }
633     }
634 
635     return deg;
636 }
637 
fq_nmod_mpolyun_set(fq_nmod_mpolyun_t A,const fq_nmod_mpolyun_t B,const fq_nmod_mpoly_ctx_t ctx)638 void fq_nmod_mpolyun_set(
639     fq_nmod_mpolyun_t A,
640     const fq_nmod_mpolyun_t B,
641     const fq_nmod_mpoly_ctx_t ctx)
642 {
643     slong i, Blen;
644     fq_nmod_mpolyn_struct * Acoeff, * Bcoeff;
645     ulong * Aexp, * Bexp;
646 
647     Blen = B->length;
648     fq_nmod_mpolyun_fit_length(A, Blen, ctx);
649     Acoeff = A->coeffs;
650     Bcoeff = B->coeffs;
651     Aexp = A->exps;
652     Bexp = B->exps;
653 
654     for (i = 0; i < Blen; i++)
655     {
656         fq_nmod_mpolyn_set(Acoeff + i, Bcoeff + i, ctx);
657         FLINT_ASSERT((Acoeff + i)->bits == B->bits);
658         Aexp[i] = Bexp[i];
659     }
660     A->length = Blen;
661 }
662 
663 /* take the last variable of B out */
fq_nmod_mpoly_cvtto_mpolyn(fq_nmod_mpolyn_t A,fq_nmod_mpoly_t B,slong var,const fq_nmod_mpoly_ctx_t ctx)664 void fq_nmod_mpoly_cvtto_mpolyn(
665     fq_nmod_mpolyn_t A,
666     fq_nmod_mpoly_t B,
667     slong var,
668     const fq_nmod_mpoly_ctx_t ctx)
669 {
670     slong i;
671     slong k;
672     ulong * oneexp;
673     slong offset;
674     slong shift;
675     ulong mask;
676     slong N;
677     TMP_INIT;
678 
679     FLINT_ASSERT(B->bits <= FLINT_BITS);
680     FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
681 
682     TMP_START;
683 
684     N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
685     oneexp = TMP_ALLOC(N*sizeof(ulong));
686     mask = (-UWORD(1)) >> (FLINT_BITS - B->bits);
687     mpoly_gen_monomial_offset_shift_sp(oneexp, &offset, &shift, var,
688                                                           B->bits, ctx->minfo);
689 
690     fq_nmod_mpolyn_fit_bits(A, B->bits, ctx);
691     A->bits = B->bits;
692 
693     k = 0;
694     fq_nmod_mpolyn_fit_length(A, k + 1, ctx);
695     for (i = 0; i < B->length; i++)
696     {
697         ulong c = (B->exps[N*i + offset] >> shift) & mask;
698         mpoly_monomial_msub(A->exps + N*k, B->exps + N*i, c, oneexp, N);
699 
700         if (k > 0 && mpoly_monomial_equal(A->exps + N*k, A->exps + N*(k - 1), N))
701         {
702             fq_nmod_poly_set_coeff(A->coeffs + k - 1, c, B->coeffs + i,
703                                                                    ctx->fqctx);
704         } else
705         {
706             fq_nmod_poly_zero(A->coeffs + k, ctx->fqctx);
707             fq_nmod_poly_set_coeff(A->coeffs + k, c, B->coeffs + i, ctx->fqctx);
708             k++;
709             fq_nmod_mpolyn_fit_length(A, k + 1, ctx);
710         }
711     }
712 
713     fq_nmod_mpolyn_set_length(A, k, ctx);
714     TMP_END;
715 }
716 
fq_nmod_mpolyu_cvtto_mpolyun(fq_nmod_mpolyun_t A,fq_nmod_mpolyu_t B,slong k,const fq_nmod_mpoly_ctx_t ctx)717 void fq_nmod_mpolyu_cvtto_mpolyun(
718     fq_nmod_mpolyun_t A,
719     fq_nmod_mpolyu_t B,
720     slong k,
721     const fq_nmod_mpoly_ctx_t ctx)
722 {
723     slong i, Blen;
724     fq_nmod_mpolyn_struct * Acoeff;
725     fq_nmod_mpoly_struct * Bcoeff;
726     ulong * Aexp, * Bexp;
727 
728     Blen = B->length;
729     fq_nmod_mpolyun_fit_length(A, Blen, ctx);
730     Acoeff = A->coeffs;
731     Bcoeff = B->coeffs;
732     Aexp = A->exps;
733     Bexp = B->exps;
734 
735     for (i = 0; i < Blen; i++)
736     {
737         fq_nmod_mpoly_cvtto_mpolyn(Acoeff + i, Bcoeff + i, k, ctx);
738         Aexp[i] = Bexp[i];
739     }
740 
741     /* demote remaining coefficients */
742     for (i = Blen; i < A->length; i++)
743     {
744         fq_nmod_mpolyn_clear(Acoeff + i, ctx);
745         fq_nmod_mpolyn_init(Acoeff + i, A->bits, ctx);
746     }
747     A->length = Blen;
748 }
749 
750 
751 /* put the last variable of B back into A */
fq_nmod_mpoly_cvtfrom_mpolyn(fq_nmod_mpoly_t A,fq_nmod_mpolyn_t B,slong var,const fq_nmod_mpoly_ctx_t ctx)752 void fq_nmod_mpoly_cvtfrom_mpolyn(
753     fq_nmod_mpoly_t A,
754     fq_nmod_mpolyn_t B,
755     slong var,
756     const fq_nmod_mpoly_ctx_t ctx)
757 {
758     slong i, j;
759     slong k;
760     slong N;
761     ulong * oneexp;
762     TMP_INIT;
763 
764     FLINT_ASSERT(B->bits == A->bits);
765     FLINT_ASSERT(B->bits <= FLINT_BITS);
766     FLINT_ASSERT(ctx->minfo->ord == ORD_LEX);
767 
768     TMP_START;
769 
770     N = mpoly_words_per_exp_sp(B->bits, ctx->minfo);
771     oneexp = TMP_ALLOC(N*sizeof(ulong));
772     mpoly_gen_monomial_sp(oneexp, var, B->bits, ctx->minfo);
773 
774     fq_nmod_mpoly_fit_length(A, B->length, ctx);
775 
776     k = 0;
777     for (i = 0; i < B->length; i++)
778     {
779         for (j = (B->coeffs + i)->length - 1; j >= 0; j--)
780         {
781             if (!fq_nmod_is_zero((B->coeffs + i)->coeffs + j, ctx->fqctx))
782             {
783                 fq_nmod_mpoly_fit_length(A, k + 1, ctx);
784                 fq_nmod_set(A->coeffs + k, (B->coeffs + i)->coeffs + j,
785                                                                    ctx->fqctx);
786                 mpoly_monomial_madd(A->exps + N*k, B->exps + N*i, j, oneexp, N);
787                 k++;
788             }
789         }
790     }
791 
792     A->length = k;
793     TMP_END;
794 }
795 
fq_nmod_mpolyu_cvtfrom_mpolyun(fq_nmod_mpolyu_t A,fq_nmod_mpolyun_t B,slong var,const fq_nmod_mpoly_ctx_t ctx)796 void fq_nmod_mpolyu_cvtfrom_mpolyun(
797     fq_nmod_mpolyu_t A,
798     fq_nmod_mpolyun_t B,
799     slong var,
800     const fq_nmod_mpoly_ctx_t ctx)
801 {
802     slong i;
803 
804     fq_nmod_mpolyu_fit_length(A, B->length, ctx);
805 
806     for (i = 0; i < B->length; i++)
807     {
808         fq_nmod_mpoly_cvtfrom_mpolyn(A->coeffs + i, B->coeffs + i, var, ctx);
809         A->exps[i] = B->exps[i];
810     }
811     A->length = B->length;
812 }
813 
814