1 /*
2     Copyright (C) 2020 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 "fmpz_mod_mpoly.h"
13 
14 /*
15     set A(x_var^Bstride[var]) to B/xbar^Bshifts
16     it is asserted that the conversion is correct
17 */
_fmpz_mod_mpoly_to_fmpz_mod_poly_deflate(fmpz_mod_poly_t A,const fmpz_mod_mpoly_t B,slong var,const ulong * Bshift,const ulong * Bstride,const fmpz_mod_mpoly_ctx_t ctx)18 void _fmpz_mod_mpoly_to_fmpz_mod_poly_deflate(
19     fmpz_mod_poly_t A,
20     const fmpz_mod_mpoly_t B,
21     slong var,
22     const ulong * Bshift,
23     const ulong * Bstride,
24     const fmpz_mod_mpoly_ctx_t ctx)
25 {
26     ulong mask;
27     slong i, shift, off, N;
28     slong len = B->length;
29     const fmpz * coeff = B->coeffs;
30     ulong * exp = B->exps;
31     ulong var_shift, var_stride;
32     flint_bitcnt_t bits = B->bits;
33 
34     FLINT_ASSERT(len > 0);
35     FLINT_ASSERT(bits <= FLINT_BITS);
36 
37     N = mpoly_words_per_exp_sp(bits, ctx->minfo);
38     mpoly_gen_offset_shift_sp(&off, &shift, var, bits, ctx->minfo);
39 
40     fmpz_mod_poly_zero(A, ctx->ffinfo);
41     mask = (-UWORD(1)) >> (FLINT_BITS - bits);
42     var_shift = Bshift[var];
43     var_stride = Bstride[var];
44     for (i = 0; i < len; i++)
45     {
46         ulong k = (exp[N*i + off] >> shift) & mask;
47         FLINT_ASSERT(k >= var_shift);
48         k -= var_shift;
49         if (k != 0)
50             k /= var_stride;
51         fmpz_mod_poly_set_coeff_fmpz(A, k, coeff + i, ctx->ffinfo);
52     }
53 
54 #if FLINT_WANT_ASSERT
55     for (i = 0; i < len; i++)
56     {
57         slong v;
58         for (v = 0; v < ctx->minfo->nvars; v++)
59         {
60             ulong k;
61             mpoly_gen_offset_shift_sp(&off, &shift, v, bits, ctx->minfo);
62             k = (exp[N*i + off] >> shift) & mask;
63             FLINT_ASSERT(   (v == var && k >= Bshift[v])
64                          || (v != var && k == Bshift[v]));
65         }
66     }
67 #endif
68 }
69 
70 /*
71     set A to B(x_var^Astride[var])*xbar^Ashift
72     A must be packed into bits = Abits
73 */
_fmpz_mod_mpoly_from_fmpz_mod_poly_inflate(fmpz_mod_mpoly_t A,flint_bitcnt_t Abits,const fmpz_mod_poly_t B,slong var,const ulong * Ashift,const ulong * Astride,const fmpz_mod_mpoly_ctx_t ctx)74 void _fmpz_mod_mpoly_from_fmpz_mod_poly_inflate(
75     fmpz_mod_mpoly_t A,
76     flint_bitcnt_t Abits,
77     const fmpz_mod_poly_t B,
78     slong var,
79     const ulong * Ashift,
80     const ulong * Astride,
81     const fmpz_mod_mpoly_ctx_t ctx)
82 {
83     slong N;
84     slong k;
85     slong Alen;
86     fmpz * Acoeff;
87     ulong * Aexp;
88     ulong * shiftexp;
89     ulong * strideexp;
90     slong Bdeg = fmpz_mod_poly_degree(B, ctx->ffinfo);
91     TMP_INIT;
92 
93     TMP_START;
94 
95     FLINT_ASSERT(Abits <= FLINT_BITS);
96     FLINT_ASSERT(!fmpz_mod_poly_is_zero(B, ctx->ffinfo));
97 
98     /* must have at least space for the highest exponent of var */
99     FLINT_ASSERT(1 + FLINT_BIT_COUNT(Ashift[var] + Bdeg*Astride[var]) <= Abits);
100 
101     N = mpoly_words_per_exp_sp(Abits, ctx->minfo);
102     strideexp = (ulong*) TMP_ALLOC(N*sizeof(ulong));
103     shiftexp = (ulong*) TMP_ALLOC(N*sizeof(ulong));
104     mpoly_set_monomial_ui(shiftexp, Ashift, Abits, ctx->minfo);
105     mpoly_gen_monomial_sp(strideexp, var, Abits, ctx->minfo);
106     mpoly_monomial_mul_ui(strideexp, strideexp, N, Astride[var]);
107 
108     fmpz_mod_mpoly_fit_length_reset_bits(A, 0, Abits, ctx);
109 
110     Acoeff = A->coeffs;
111     Aexp = A->exps;
112     Alen = 0;
113     for (k = Bdeg; k >= 0; k--)
114     {
115         _fmpz_mod_mpoly_fit_length(&Acoeff, &A->coeffs_alloc,
116                                    &Aexp, &A->exps_alloc, N, Alen + 1);
117         fmpz_mod_poly_get_coeff_fmpz(Acoeff + Alen, B, k, ctx->ffinfo);
118         if (fmpz_is_zero(Acoeff + Alen))
119             continue;
120         mpoly_monomial_madd(Aexp + N*Alen, shiftexp, k, strideexp, N);
121         Alen++;
122     }
123 
124     A->coeffs = Acoeff;
125     A->exps = Aexp;
126     _fmpz_mod_mpoly_set_length(A, Alen, ctx);
127 
128     TMP_END;
129 }
130