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 <http://www.gnu.org/licenses/>.
10 */
11
12 #include "fmpq_mpoly.h"
13
14
fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A,const fmpq_mpoly_ctx_t ctx)15 void fmpq_mpoly_univar_init(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx)
16 {
17 A->coeffs = NULL;
18 A->exps = NULL;
19 A->alloc = 0;
20 A->length = 0;
21 }
22
23
fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A,const fmpq_mpoly_ctx_t ctx)24 void fmpq_mpoly_univar_clear(fmpq_mpoly_univar_t A, const fmpq_mpoly_ctx_t ctx)
25 {
26 slong i;
27 for (i = 0; i < A->alloc; i++)
28 {
29 fmpq_mpoly_clear(A->coeffs + i, ctx);
30 fmpz_clear(A->exps + i);
31 }
32
33 if (A->coeffs)
34 flint_free(A->coeffs);
35
36 if (A->exps)
37 flint_free(A->exps);
38 }
39
40
fmpq_mpoly_univar_fit_length(fmpq_mpoly_univar_t A,slong length,const fmpq_mpoly_ctx_t ctx)41 void fmpq_mpoly_univar_fit_length(fmpq_mpoly_univar_t A,
42 slong length, const fmpq_mpoly_ctx_t ctx)
43 {
44 slong i;
45 slong old_alloc = A->alloc;
46 slong new_alloc = FLINT_MAX(length, 2*A->alloc);
47
48 if (length > old_alloc)
49 {
50 if (old_alloc == 0)
51 {
52 A->exps = (fmpz *) flint_malloc(new_alloc*sizeof(fmpz));
53 A->coeffs = (fmpq_mpoly_struct *) flint_malloc(
54 new_alloc*sizeof(fmpq_mpoly_struct));
55 }
56 else
57 {
58 A->exps = (fmpz *) flint_realloc(A->exps, new_alloc*sizeof(fmpz));
59 A->coeffs = (fmpq_mpoly_struct *) flint_realloc(A->coeffs,
60 new_alloc*sizeof(fmpq_mpoly_struct));
61 }
62
63 for (i = old_alloc; i < new_alloc; i++)
64 {
65 fmpz_init(A->exps + i);
66 fmpq_mpoly_init(A->coeffs + i, ctx);
67 }
68 A->alloc = new_alloc;
69 }
70 }
71
72
fmpq_mpoly_univar_assert_canonical(fmpq_mpoly_univar_t A,const fmpq_mpoly_ctx_t ctx)73 void fmpq_mpoly_univar_assert_canonical(fmpq_mpoly_univar_t A,
74 const fmpq_mpoly_ctx_t ctx)
75 {
76 slong i;
77
78 for (i = 0; i + 1 < A->length; i++)
79 {
80 if (fmpz_cmp(A->exps + i, A->exps + i + 1) <= 0
81 || fmpz_sgn(A->exps + i) < 0
82 || fmpz_sgn(A->exps + i + 1) < 0)
83 {
84 flint_throw(FLINT_ERROR, "Univariate polynomial exponents out of order");
85 }
86 }
87
88 for (i = 0; i < A->length; i++)
89 fmpq_mpoly_assert_canonical(A->coeffs + i, ctx);
90 }
91
92
fmpq_mpoly_univar_print_pretty(const fmpq_mpoly_univar_t A,const char ** x,const fmpq_mpoly_ctx_t ctx)93 void fmpq_mpoly_univar_print_pretty(const fmpq_mpoly_univar_t A,
94 const char ** x, const fmpq_mpoly_ctx_t ctx)
95 {
96 slong i;
97 if (A->length == 0)
98 flint_printf("0");
99 for (i = 0; i < A->length; i++)
100 {
101 if (i != 0)
102 flint_printf("+");
103 flint_printf("(");
104 fmpq_mpoly_print_pretty(A->coeffs + i,x,ctx);
105 flint_printf(")*X^");
106 fmpz_print(A->exps + i);
107 }
108 }
109
110
fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A,const fmpq_mpoly_t B,slong var,const fmpq_mpoly_ctx_t ctx)111 void fmpq_mpoly_to_univar(fmpq_mpoly_univar_t A, const fmpq_mpoly_t B,
112 slong var, const fmpq_mpoly_ctx_t ctx)
113 {
114 slong i;
115 fmpz_mpoly_univar_t Z;
116 fmpz_mpoly_univar_init(Z, ctx->zctx);
117 fmpz_mpoly_to_univar(Z, B->zpoly, var, ctx->zctx);
118 fmpq_mpoly_univar_fit_length(A, Z->length, ctx);
119 A->length = Z->length;
120 for (i = Z->length - 1; i >= 0; i--)
121 {
122 fmpz_swap(A->exps + i, Z->exps + i);
123 fmpz_mpoly_swap(A->coeffs[i].zpoly, Z->coeffs + i, ctx->zctx);
124 fmpq_set(A->coeffs[i].content, B->content);
125 fmpq_mpoly_reduce(A->coeffs + i, ctx);
126 }
127 fmpz_mpoly_univar_clear(Z, ctx->zctx);
128 }
129
130 /*
131 Currently this function does not work if the coefficients depend on "var".
132 The assertion x->next == NULL would need to be replaced by a loop.
133 Other asserts would need to be removed as well.
134 */
fmpq_mpoly_from_univar_bits(fmpq_mpoly_t A,flint_bitcnt_t Abits,const fmpq_mpoly_univar_t B,slong var,const fmpq_mpoly_ctx_t ctx)135 void fmpq_mpoly_from_univar_bits(fmpq_mpoly_t A, flint_bitcnt_t Abits,
136 const fmpq_mpoly_univar_t B, slong var, const fmpq_mpoly_ctx_t ctx)
137 {
138 slong N = mpoly_words_per_exp(Abits, ctx->zctx->minfo);
139 slong i;
140 slong next_loc, heap_len = 1;
141 ulong * cmpmask;
142 slong total_len;
143 mpoly_heap_s * heap;
144 slong Alen;
145 ulong ** Btexp;
146 fmpz * Bscales;
147 fmpz_t t;
148 ulong * exp;
149 ulong * one;
150 mpoly_heap_t * chain, * x;
151 TMP_INIT;
152
153 if (B->length == 0)
154 {
155 fmpz_mpoly_fit_bits(A->zpoly, Abits, ctx->zctx);
156 A->zpoly->bits = Abits;
157 _fmpz_mpoly_set_length(A->zpoly, 0, ctx->zctx);
158 fmpq_zero(A->content);
159 return;
160 }
161
162 TMP_START;
163
164 /* pack everything into Abits */
165
166 one = (ulong*) TMP_ALLOC(N*sizeof(ulong));
167 cmpmask = (ulong*) TMP_ALLOC(N*sizeof(ulong));
168 Btexp = (ulong **) TMP_ALLOC(B->length*sizeof(ulong*));
169 Bscales = (fmpz *) TMP_ALLOC(B->length*sizeof(ulong*));
170
171 total_len = 0;
172 fmpq_zero(A->content);
173 for (i = 0; i < B->length; i++)
174 {
175 fmpz_mpoly_struct * Bi;
176
177 fmpz_init(Bscales + i);
178
179 fmpq_gcd(A->content, A->content, B->coeffs[i].content);
180
181 Bi = B->coeffs[i].zpoly;
182 total_len += Bi->length;
183 Btexp[i] = Bi->exps;
184 if (Abits != Bi->bits)
185 {
186 Btexp[i] = (ulong *) flint_malloc(N*Bi->length*sizeof(ulong));
187 if (!mpoly_repack_monomials(Btexp[i], Abits,
188 Bi->exps, Bi->bits, Bi->length, ctx->zctx->minfo))
189 {
190 FLINT_ASSERT(0 && "repack does not fit");
191 }
192 }
193 }
194
195 fmpz_init(t);
196 if (!fmpq_is_zero(A->content))
197 {
198 for (i = 0; i < B->length; i++)
199 {
200 _fmpq_div(Bscales + i, t, fmpq_numref(B->coeffs[i].content),
201 fmpq_denref(B->coeffs[i].content),
202 fmpq_numref(A->content),
203 fmpq_denref(A->content));
204 FLINT_ASSERT(fmpz_is_one(t));
205 }
206 }
207 fmpz_clear(t);
208
209 fmpz_mpoly_fit_length(A->zpoly, total_len, ctx->zctx);
210 fmpz_mpoly_fit_bits(A->zpoly, Abits, ctx->zctx);
211 A->zpoly->bits = Abits;
212
213 next_loc = B->length + 2;
214 heap = (mpoly_heap_s *) TMP_ALLOC((B->length + 1)*sizeof(mpoly_heap_s));
215 exp = (ulong *) TMP_ALLOC(B->length*N*sizeof(ulong));
216 chain = (mpoly_heap_t *) TMP_ALLOC(B->length*sizeof(mpoly_heap_t));
217
218 mpoly_get_cmpmask(cmpmask, N, Abits, ctx->zctx->minfo);
219
220 Alen = 0;
221 if (Abits <= FLINT_BITS)
222 {
223 mpoly_gen_monomial_sp(one, var, Abits, ctx->zctx->minfo);
224
225 for (i = 0; i < B->length; i++)
226 {
227 FLINT_ASSERT(fmpz_fits_si(B->exps + i));
228 x = chain + i;
229 x->i = i;
230 x->j = 0;
231 x->next = NULL;
232 mpoly_monomial_madd(exp + N*x->i, Btexp[x->i] + N*x->j,
233 fmpz_get_si(B->exps + i), one, N);
234 _mpoly_heap_insert(heap, exp + N*i, x, &next_loc, &heap_len,
235 N, cmpmask);
236 }
237
238 while (heap_len > 1)
239 {
240 FLINT_ASSERT(Alen < A->zpoly->alloc);
241 mpoly_monomial_set(A->zpoly->exps + N*Alen, heap[1].exp, N);
242 x = _mpoly_heap_pop(heap, &heap_len, N, cmpmask);
243 fmpz_mul(A->zpoly->coeffs + Alen, Bscales + x->i,
244 (B->coeffs + x->i)->zpoly->coeffs + x->j);
245 Alen++;
246
247 FLINT_ASSERT(x->next == NULL);
248
249 if (x->j + 1 < (B->coeffs + x->i)->zpoly->length)
250 {
251 FLINT_ASSERT(fmpz_fits_si(B->exps + x->i));
252 x->j = x->j + 1;
253 x->next = NULL;
254 mpoly_monomial_madd(exp + N*x->i, Btexp[x->i] + N*x->j,
255 fmpz_get_si(B->exps + x->i), one, N);
256 _mpoly_heap_insert(heap, exp + N*x->i, x, &next_loc, &heap_len,
257 N, cmpmask);
258 }
259 }
260 }
261 else
262 {
263 mpoly_gen_monomial_offset_mp(one, var, Abits, ctx->zctx->minfo);
264
265 for (i = 0; i < B->length; i++)
266 {
267 x = chain + i;
268 x->i = i;
269 x->j = 0;
270 x->next = NULL;
271 mpoly_monomial_madd_fmpz(exp + N*x->i, Btexp[x->i] + N*x->j,
272 B->exps + i, one, N);
273 _mpoly_heap_insert(heap, exp + N*i, x, &next_loc, &heap_len,
274 N, cmpmask);
275 }
276
277 while (heap_len > 1)
278 {
279 FLINT_ASSERT(Alen < A->zpoly->alloc);
280 mpoly_monomial_set(A->zpoly->exps + N*Alen, heap[1].exp, N);
281 x = _mpoly_heap_pop(heap, &heap_len, N, cmpmask);
282 fmpz_mul(A->zpoly->coeffs + Alen, Bscales + x->i,
283 (B->coeffs + x->i)->zpoly->coeffs + x->j);
284 Alen++;
285
286 FLINT_ASSERT(x->next == NULL);
287
288 if (x->j + 1 < (B->coeffs + x->i)->zpoly->length)
289 {
290 x->j = x->j + 1;
291 x->next = NULL;
292 mpoly_monomial_madd_fmpz(exp + N*x->i, Btexp[x->i] + N*x->j,
293 B->exps + x->i, one, N);
294 _mpoly_heap_insert(heap, exp + N*x->i, x, &next_loc, &heap_len,
295 N, cmpmask);
296 }
297 }
298 }
299
300 for (i = 0; i < B->length; i++)
301 {
302 fmpz_clear(Bscales + i);
303 if (Btexp[i] != (B->coeffs + i)->zpoly->exps)
304 flint_free(Btexp[i]);
305 }
306 TMP_END;
307
308 _fmpz_mpoly_set_length(A->zpoly, Alen, ctx->zctx);
309 fmpq_mpoly_reduce(A, ctx);
310 }
311
312
fmpq_mpoly_from_univar(fmpq_mpoly_t A,const fmpq_mpoly_univar_t B,slong var,const fmpq_mpoly_ctx_t ctx)313 void fmpq_mpoly_from_univar(fmpq_mpoly_t A, const fmpq_mpoly_univar_t B,
314 slong var, const fmpq_mpoly_ctx_t ctx)
315 {
316 slong n = ctx->zctx->minfo->nfields;
317 flint_bitcnt_t bits;
318 slong i;
319 fmpz * gen_fields, * tmp_fields, * max_fields;
320 TMP_INIT;
321
322 if (B->length == 0)
323 {
324 fmpq_mpoly_zero(A, ctx);
325 return;
326 }
327
328 TMP_START;
329
330 /* find bits required to represent result */
331 gen_fields = (fmpz *) TMP_ALLOC(ctx->zctx->minfo->nfields*sizeof(fmpz));
332 tmp_fields = (fmpz *) TMP_ALLOC(ctx->zctx->minfo->nfields*sizeof(fmpz));
333 max_fields = (fmpz *) TMP_ALLOC(ctx->zctx->minfo->nfields*sizeof(fmpz));
334 for (i = 0; i < ctx->zctx->minfo->nfields; i++)
335 {
336 fmpz_init(gen_fields + i);
337 fmpz_init(tmp_fields + i);
338 fmpz_init(max_fields + i);
339 }
340
341 mpoly_gen_fields_fmpz(gen_fields, var, ctx->zctx->minfo);
342
343 for (i = 0; i < B->length; i++)
344 {
345 fmpz_mpoly_struct * Bi = B->coeffs[i].zpoly;
346 mpoly_max_fields_fmpz(tmp_fields, Bi->exps, Bi->length, Bi->bits, ctx->zctx->minfo);
347 _fmpz_vec_scalar_addmul_fmpz(tmp_fields, gen_fields, n, B->exps + i);
348 _fmpz_vec_max_inplace(max_fields, tmp_fields, n);
349 }
350 bits = _fmpz_vec_max_bits(max_fields, n);
351 bits = FLINT_MAX(MPOLY_MIN_BITS, bits + 1);
352 bits = mpoly_fix_bits(bits, ctx->zctx->minfo);
353
354 for (i = 0; i < ctx->zctx->minfo->nfields; i++)
355 {
356 fmpz_clear(gen_fields + i);
357 fmpz_clear(tmp_fields + i);
358 fmpz_clear(max_fields + i);
359 }
360 TMP_END;
361
362 fmpq_mpoly_from_univar_bits(A, bits, B, var, ctx);
363 }
364
365