1 | // emacs edit mode for this file is -*- C++ -*- |
---|
2 | /**************************************** |
---|
3 | * Computer Algebra System SINGULAR * |
---|
4 | ****************************************/ |
---|
5 | /* |
---|
6 | * ABSTRACT: flint mpoly |
---|
7 | */ |
---|
8 | |
---|
9 | #include "misc/auxiliary.h" |
---|
10 | #include "flintconv.h" |
---|
11 | #include "flint_mpoly.h" |
---|
12 | |
---|
13 | #ifdef HAVE_FLINT |
---|
14 | #if __FLINT_RELEASE >= 20503 |
---|
15 | #include "coeffs/coeffs.h" |
---|
16 | #include "coeffs/longrat.h" |
---|
17 | #include "polys/monomials/p_polys.h" |
---|
18 | |
---|
19 | #include <vector> |
---|
20 | |
---|
21 | /****** ring conversion ******/ |
---|
22 | |
---|
23 | BOOLEAN convSingRFlintR(fmpq_mpoly_ctx_t ctx, const ring r) |
---|
24 | { |
---|
25 | if (rRing_ord_pure_dp(r)) |
---|
26 | { |
---|
27 | fmpq_mpoly_ctx_init(ctx,r->N,ORD_DEGREVLEX); |
---|
28 | return FALSE; |
---|
29 | } |
---|
30 | else if (rRing_ord_pure_Dp(r)) |
---|
31 | { |
---|
32 | fmpq_mpoly_ctx_init(ctx,r->N,ORD_DEGLEX); |
---|
33 | return FALSE; |
---|
34 | } |
---|
35 | else if (rRing_ord_pure_lp(r)) |
---|
36 | { |
---|
37 | fmpq_mpoly_ctx_init(ctx,r->N,ORD_LEX); |
---|
38 | return FALSE; |
---|
39 | } |
---|
40 | return TRUE; |
---|
41 | } |
---|
42 | |
---|
43 | BOOLEAN convSingRFlintR(nmod_mpoly_ctx_t ctx, const ring r) |
---|
44 | { |
---|
45 | if (rRing_ord_pure_dp(r)) |
---|
46 | { |
---|
47 | nmod_mpoly_ctx_init(ctx,r->N,ORD_DEGREVLEX,r->cf->ch); |
---|
48 | return FALSE; |
---|
49 | } |
---|
50 | else if (rRing_ord_pure_Dp(r)) |
---|
51 | { |
---|
52 | nmod_mpoly_ctx_init(ctx,r->N,ORD_DEGLEX,r->cf->ch); |
---|
53 | return FALSE; |
---|
54 | } |
---|
55 | else if (rRing_ord_pure_lp(r)) |
---|
56 | { |
---|
57 | nmod_mpoly_ctx_init(ctx,r->N,ORD_LEX,r->cf->ch); |
---|
58 | return FALSE; |
---|
59 | } |
---|
60 | return TRUE; |
---|
61 | } |
---|
62 | |
---|
63 | /******** polynomial conversion ***********/ |
---|
64 | |
---|
65 | #if 1 |
---|
66 | // memory allocation is not thread safe; singular polynomials must be constructed in serial |
---|
67 | |
---|
68 | /* |
---|
69 | We agree the that result of a singular -> fmpq_mpoly conversion is |
---|
70 | readonly. This restricts the usage of the result in flint functions to |
---|
71 | const arguments. However, the real readonly conversion is currently only |
---|
72 | implemented in the threaded conversion below since it requires a scan of |
---|
73 | all coefficients anyways. The _fmpq_mpoly_clear_readonly_sing needs to |
---|
74 | be provided for a consistent interface in the polynomial operations. |
---|
75 | */ |
---|
76 | static void _fmpq_mpoly_clear_readonly_sing(fmpq_mpoly_t a, fmpq_mpoly_ctx_t ctx) |
---|
77 | { |
---|
78 | fmpq_mpoly_clear(a, ctx); |
---|
79 | } |
---|
80 | |
---|
81 | void convSingPFlintMP(fmpq_mpoly_t res, fmpq_mpoly_ctx_t ctx, poly p, int lp, const ring r) |
---|
82 | { |
---|
83 | fmpq_mpoly_init2(res, lp, ctx); |
---|
84 | ulong* exp=(ulong*)omAlloc((r->N+1)*sizeof(ulong)); |
---|
85 | while(p!=NULL) |
---|
86 | { |
---|
87 | number n=pGetCoeff(p); |
---|
88 | fmpq_t c; |
---|
89 | convSingNFlintN_QQ(c,n); |
---|
90 | #if SIZEOF_LONG==8 |
---|
91 | p_GetExpVL(p,(int64*)exp,r); |
---|
92 | fmpq_mpoly_push_term_fmpq_ui(res, c, exp, ctx); |
---|
93 | #else |
---|
94 | p_GetExpV(p,(int*)exp,r); |
---|
95 | fmpq_mpoly_push_term_fmpq_ui(res, c, &(exp[1]), ctx); |
---|
96 | #endif |
---|
97 | fmpq_clear(c); |
---|
98 | pIter(p); |
---|
99 | } |
---|
100 | fmpq_mpoly_reduce(res, ctx); // extra step for QQ ensures res has content canonically factored out |
---|
101 | omFreeSize(exp,(r->N+1)*sizeof(ulong)); |
---|
102 | } |
---|
103 | |
---|
104 | poly convFlintMPSingP(fmpq_mpoly_t f, fmpq_mpoly_ctx_t ctx, const ring r) |
---|
105 | { |
---|
106 | int d=fmpq_mpoly_length(f,ctx)-1; |
---|
107 | poly p=NULL; |
---|
108 | ulong* exp=(ulong*)omAlloc((r->N+1)*sizeof(ulong)); |
---|
109 | fmpq_t c; |
---|
110 | fmpq_init(c); |
---|
111 | for(int i=d; i>=0; i--) |
---|
112 | { |
---|
113 | fmpq_mpoly_get_term_coeff_fmpq(c,f,i,ctx); |
---|
114 | poly pp=p_Init(r); |
---|
115 | #if SIZEOF_LONG==8 |
---|
116 | fmpq_mpoly_get_term_exp_ui(exp,f,i,ctx); |
---|
117 | p_SetExpVL(pp,(int64*)exp,r); |
---|
118 | #else |
---|
119 | fmpq_mpoly_get_term_exp_ui(&(exp[1]),f,i,ctx); |
---|
120 | p_SetExpV(pp,(int*)exp,r); |
---|
121 | #endif |
---|
122 | p_Setm(pp,r); |
---|
123 | number n=convFlintNSingN_QQ(c,r->cf); |
---|
124 | pSetCoeff0(pp,n); |
---|
125 | pNext(pp)=p; |
---|
126 | p=pp; |
---|
127 | } |
---|
128 | fmpq_clear(c); |
---|
129 | omFreeSize(exp,(r->N+1)*sizeof(ulong)); |
---|
130 | p_Test(p,r); |
---|
131 | return p; |
---|
132 | } |
---|
133 | |
---|
134 | poly convFlintMPSingP(nmod_mpoly_t f, nmod_mpoly_ctx_t ctx, const ring r) |
---|
135 | { |
---|
136 | int d=nmod_mpoly_length(f,ctx)-1; |
---|
137 | poly p=NULL; |
---|
138 | ulong* exp=(ulong*)omAlloc((r->N+1)*sizeof(ulong)); |
---|
139 | for(int i=d; i>=0; i--) |
---|
140 | { |
---|
141 | ulong c=nmod_mpoly_get_term_coeff_ui(f,i,ctx); |
---|
142 | poly pp=p_Init(r); |
---|
143 | #if SIZEOF_LONG==8 |
---|
144 | nmod_mpoly_get_term_exp_ui(exp,f,i,ctx); |
---|
145 | p_SetExpVL(pp,(int64*)exp,r); |
---|
146 | #else |
---|
147 | nmod_mpoly_get_term_exp_ui(&(exp[1]),f,i,ctx); |
---|
148 | p_SetExpV(pp,(int*)exp,r); |
---|
149 | #endif |
---|
150 | p_Setm(pp,r); |
---|
151 | pSetCoeff0(pp,(number)c); |
---|
152 | pNext(pp)=p; |
---|
153 | p=pp; |
---|
154 | } |
---|
155 | omFreeSize(exp,(r->N+1)*sizeof(ulong)); |
---|
156 | p_Test(p,r); |
---|
157 | return p; |
---|
158 | } |
---|
159 | |
---|
160 | void convSingPFlintMP(nmod_mpoly_t res, nmod_mpoly_ctx_t ctx, poly p, int lp,const ring r) |
---|
161 | { |
---|
162 | nmod_mpoly_init2(res, lp, ctx); |
---|
163 | ulong* exp=(ulong*)omAlloc((r->N+1)*sizeof(ulong)); |
---|
164 | while(p!=NULL) |
---|
165 | { |
---|
166 | number n=pGetCoeff(p); |
---|
167 | #if SIZEOF_LONG==8 |
---|
168 | p_GetExpVL(p,(int64*)exp,r); |
---|
169 | nmod_mpoly_push_term_ui_ui(res, (ulong)n, exp, ctx); |
---|
170 | #else |
---|
171 | p_GetExpV(p,(int*)exp,r); |
---|
172 | nmod_mpoly_push_term_ui_ui(res, (ulong)n, &(exp[1]), ctx); |
---|
173 | #endif |
---|
174 | pIter(p); |
---|
175 | } |
---|
176 | omFreeSize(exp,(r->N+1)*sizeof(ulong)); |
---|
177 | } |
---|
178 | |
---|
179 | #else |
---|
180 | // memory allocator is thread safe; singular polynomials may be constructed in parallel |
---|
181 | |
---|
182 | // like convSingNFlintN_QQ but it takes an initialized fmpq_t f |
---|
183 | static void my_convSingNFlintN_QQ(fmpq_t f, number n) |
---|
184 | { |
---|
185 | if (SR_HDL(n)&SR_INT) |
---|
186 | { |
---|
187 | fmpq_set_si(f,SR_TO_INT(n),1); |
---|
188 | } |
---|
189 | else if (n->s<3) |
---|
190 | { |
---|
191 | fmpz_set_mpz(fmpq_numref(f), n->z); |
---|
192 | fmpz_set_mpz(fmpq_denref(f), n->n); |
---|
193 | } |
---|
194 | else |
---|
195 | { |
---|
196 | fmpz_set_mpz(fmpq_numref(f), n->z); |
---|
197 | fmpz_one(fmpq_denref(f)); |
---|
198 | } |
---|
199 | } |
---|
200 | |
---|
201 | |
---|
202 | /* |
---|
203 | In order that flint may sometimes borrow the large integer coeffs of |
---|
204 | polynomials over QQ (borrow means: simply point to the same GMP structs |
---|
205 | that singular has already allocated), we define the result of a |
---|
206 | singular -> fmpq_mpoly conversion to be readonly. This means we agree |
---|
207 | that |
---|
208 | - it can only be used as an const argument to a flint function |
---|
209 | - singular must not mutate the original coeffs while the readonly object is in use |
---|
210 | */ |
---|
211 | |
---|
212 | static void _fmpq_mpoly_clear_readonly_sing(fmpq_mpoly_t a, fmpq_mpoly_ctx_t ctx) |
---|
213 | { |
---|
214 | if (fmpq_is_one(a->content)) |
---|
215 | { |
---|
216 | if (a->zpoly->alloc > 0) |
---|
217 | { |
---|
218 | flint_free(a->zpoly->coeffs); |
---|
219 | flint_free(a->zpoly->exps); |
---|
220 | } |
---|
221 | |
---|
222 | fmpq_clear(a->content); |
---|
223 | } |
---|
224 | else |
---|
225 | { |
---|
226 | fmpq_mpoly_clear(a, ctx); |
---|
227 | } |
---|
228 | } |
---|
229 | |
---|
230 | /* singular -> fmpq_mpoly conversion */ |
---|
231 | |
---|
232 | class convert_sing_to_fmpq_mpoly_base |
---|
233 | { |
---|
234 | public: |
---|
235 | slong num_threads; |
---|
236 | slong length; |
---|
237 | fmpq_mpoly_struct * res; |
---|
238 | const fmpq_mpoly_ctx_struct * ctx; |
---|
239 | std::vector<poly> markers; |
---|
240 | ring r; |
---|
241 | fmpq_t content; |
---|
242 | |
---|
243 | convert_sing_to_fmpq_mpoly_base(fmpq_mpoly_struct * res_, |
---|
244 | const fmpq_mpoly_ctx_struct * ctx_, const ring r_, poly p) |
---|
245 | : num_threads(0), |
---|
246 | res(res_), |
---|
247 | ctx(ctx_), |
---|
248 | r(r_) |
---|
249 | { |
---|
250 | fmpq_t c; |
---|
251 | fmpq_init(c); |
---|
252 | fmpq_init(content); |
---|
253 | fmpq_zero(content); |
---|
254 | |
---|
255 | length = 0; |
---|
256 | while (1) |
---|
257 | { |
---|
258 | if ((length % 4096) == 0) |
---|
259 | { |
---|
260 | my_convSingNFlintN_QQ(c, number(pGetCoeff(p))); |
---|
261 | fmpq_gcd(content, content, c); |
---|
262 | markers.push_back(p); |
---|
263 | } |
---|
264 | if (p == NULL) |
---|
265 | return; |
---|
266 | length++; |
---|
267 | pIter(p); |
---|
268 | } |
---|
269 | |
---|
270 | fmpq_clear(c); |
---|
271 | } |
---|
272 | |
---|
273 | ~convert_sing_to_fmpq_mpoly_base() |
---|
274 | { |
---|
275 | fmpq_clear(content); |
---|
276 | } |
---|
277 | }; |
---|
278 | |
---|
279 | class convert_sing_to_fmpq_mpoly_arg |
---|
280 | { |
---|
281 | public: |
---|
282 | fmpq_t content; |
---|
283 | slong start_idx, end_idx; |
---|
284 | convert_sing_to_fmpq_mpoly_base* base; |
---|
285 | flint_bitcnt_t required_bits; |
---|
286 | |
---|
287 | convert_sing_to_fmpq_mpoly_arg() {fmpq_init(content);} |
---|
288 | ~convert_sing_to_fmpq_mpoly_arg() {fmpq_clear(content);} |
---|
289 | }; |
---|
290 | |
---|
291 | static void convert_sing_to_fmpq_mpoly_content_bits(void * varg) |
---|
292 | { |
---|
293 | convert_sing_to_fmpq_mpoly_arg* arg = (convert_sing_to_fmpq_mpoly_arg*) varg; |
---|
294 | convert_sing_to_fmpq_mpoly_base * base = arg->base; |
---|
295 | ulong * exp = (ulong*) flint_malloc((base->r->N + 1)*sizeof(ulong)); |
---|
296 | fmpq_t c; |
---|
297 | fmpq_init(c); |
---|
298 | |
---|
299 | slong idx = arg->start_idx/4096; |
---|
300 | poly p = arg->base->markers[idx]; |
---|
301 | idx *= 4096; |
---|
302 | while (idx < arg->start_idx) |
---|
303 | { |
---|
304 | pIter(p); |
---|
305 | idx++; |
---|
306 | } |
---|
307 | |
---|
308 | flint_bitcnt_t required_bits = MPOLY_MIN_BITS; |
---|
309 | fmpq_set(arg->content, base->content); |
---|
310 | |
---|
311 | while (idx < arg->end_idx) |
---|
312 | { |
---|
313 | number n = number(pGetCoeff(p)); |
---|
314 | |
---|
315 | if (fmpq_is_one(arg->content) && (SR_HDL(n)&SR_INT || n->s >= 3)) |
---|
316 | { |
---|
317 | /* content is 1 and n is an integer, nothing to do */ |
---|
318 | } |
---|
319 | else |
---|
320 | { |
---|
321 | my_convSingNFlintN_QQ(c, n); |
---|
322 | fmpq_gcd(arg->content, arg->content, c); |
---|
323 | } |
---|
324 | |
---|
325 | #if SIZEOF_LONG==8 |
---|
326 | p_GetExpVL(p, (int64*)exp, base->r); |
---|
327 | flint_bitcnt_t exp_bits = mpoly_exp_bits_required_ui(exp, base->ctx->zctx->minfo); |
---|
328 | #else |
---|
329 | p_GetExpV(p, (int*)exp, base->r); |
---|
330 | flint_bitcnt_t exp_bits = mpoly_exp_bits_required_ui(&(exp[1]), base->ctx->zctx->minfo); |
---|
331 | #endif |
---|
332 | |
---|
333 | required_bits = FLINT_MAX(required_bits, exp_bits); |
---|
334 | |
---|
335 | pIter(p); |
---|
336 | idx++; |
---|
337 | } |
---|
338 | |
---|
339 | arg->required_bits = required_bits; |
---|
340 | |
---|
341 | fmpq_clear(c); |
---|
342 | flint_free(exp); |
---|
343 | } |
---|
344 | |
---|
345 | static void convert_sing_to_fmpq_mpoly_zpoly_worker(void * varg) |
---|
346 | { |
---|
347 | convert_sing_to_fmpq_mpoly_arg * arg = (convert_sing_to_fmpq_mpoly_arg *) varg; |
---|
348 | convert_sing_to_fmpq_mpoly_base * base = arg->base; |
---|
349 | ulong * exp = (ulong*) flint_malloc((base->r->N + 1)*sizeof(ulong)); |
---|
350 | fmpq_t c, t; |
---|
351 | fmpq_init(c); |
---|
352 | fmpq_init(t); |
---|
353 | |
---|
354 | slong idx = arg->start_idx/4096; |
---|
355 | poly p = base->markers[idx]; |
---|
356 | idx *= 4096; |
---|
357 | while (idx < arg->start_idx) |
---|
358 | { |
---|
359 | pIter(p); |
---|
360 | idx++; |
---|
361 | } |
---|
362 | |
---|
363 | slong N = mpoly_words_per_exp(base->res->zpoly->bits, base->ctx->zctx->minfo); |
---|
364 | fmpz * res_coeffs = base->res->zpoly->coeffs; |
---|
365 | ulong * res_exps = base->res->zpoly->exps; |
---|
366 | flint_bitcnt_t res_bits = base->res->zpoly->bits; |
---|
367 | |
---|
368 | while (idx < arg->end_idx) |
---|
369 | { |
---|
370 | if (fmpq_is_one(base->res->content)) |
---|
371 | { |
---|
372 | // borrowing singular integers |
---|
373 | // the entry res_coeffs[idx] is junk, we should just overwrite it |
---|
374 | |
---|
375 | number n = number(pGetCoeff(p)); |
---|
376 | |
---|
377 | if (SR_HDL(n)&SR_INT) |
---|
378 | { |
---|
379 | // n is a singular-small integer |
---|
380 | res_coeffs[idx] = SR_TO_INT(n); |
---|
381 | } |
---|
382 | else if (n->s<3) |
---|
383 | { |
---|
384 | // n is an element of QQ \ ZZ, should not happen |
---|
385 | assume(false); |
---|
386 | } |
---|
387 | else |
---|
388 | { |
---|
389 | // n is a singular-large integer, n may be flint-small |
---|
390 | res_coeffs[idx] = PTR_TO_COEFF(n->z); |
---|
391 | if (fmpz_fits_si(res_coeffs + idx)) |
---|
392 | { |
---|
393 | slong val = fmpz_get_si(res_coeffs + idx); |
---|
394 | if (val >= COEFF_MIN && val <= COEFF_MAX) |
---|
395 | res_coeffs[idx] = val; |
---|
396 | } |
---|
397 | } |
---|
398 | } |
---|
399 | else |
---|
400 | { |
---|
401 | my_convSingNFlintN_QQ(c, number(pGetCoeff(p))); |
---|
402 | FLINT_ASSERT(!fmpq_is_zero(base->res->content)); |
---|
403 | fmpq_div(t, c, base->res->content); |
---|
404 | FLINT_ASSERT(fmpz_is_one(fmpq_denref(t))); |
---|
405 | fmpz_swap(res_coeffs + idx, fmpq_numref(t)); |
---|
406 | } |
---|
407 | |
---|
408 | #if SIZEOF_LONG==8 |
---|
409 | p_GetExpVL(p, (int64*)exp, base->r); |
---|
410 | mpoly_set_monomial_ui(res_exps + N*idx, exp, res_bits, base->ctx->zctx->minfo); |
---|
411 | #else |
---|
412 | p_GetExpV(p, (int*)exp, base->r); |
---|
413 | mpoly_set_monomial_ui(res_exps + N*idx, &(exp[1]), res_bits, base->ctx->minfo); |
---|
414 | #endif |
---|
415 | |
---|
416 | pIter(p); |
---|
417 | idx++; |
---|
418 | } |
---|
419 | |
---|
420 | flint_free(exp); |
---|
421 | fmpq_clear(c); |
---|
422 | fmpq_clear(t); |
---|
423 | } |
---|
424 | |
---|
425 | /* res comes in unitialized!!!! */ |
---|
426 | void convSingPFlintMP(fmpq_mpoly_t res, fmpq_mpoly_ctx_t ctx, poly p, int lp, const ring r) |
---|
427 | { |
---|
428 | thread_pool_handle * handles; |
---|
429 | slong num_handles; |
---|
430 | slong thread_limit = 1000; // TODO: should be paramter to this function |
---|
431 | |
---|
432 | /* the constructor works out the length of p and sets some markers */ |
---|
433 | convert_sing_to_fmpq_mpoly_base base(res, ctx, r, p); |
---|
434 | |
---|
435 | /* sensibly limit thread count and get workers */ |
---|
436 | thread_limit = FLINT_MIN(thread_limit, base.length/1024); |
---|
437 | handles = NULL; |
---|
438 | num_handles = 0; |
---|
439 | if (thread_limit > 1 && global_thread_pool_initialized) |
---|
440 | { |
---|
441 | slong max_num_handles = thread_pool_get_size(global_thread_pool); |
---|
442 | max_num_handles = FLINT_MIN(thread_limit - 1, max_num_handles); |
---|
443 | if (max_num_handles > 0) |
---|
444 | { |
---|
445 | handles = (thread_pool_handle *) flint_malloc(max_num_handles*sizeof(thread_pool_handle)); |
---|
446 | num_handles = thread_pool_request(global_thread_pool, handles, max_num_handles); |
---|
447 | } |
---|
448 | } |
---|
449 | |
---|
450 | /* fill in thread division points */ |
---|
451 | base.num_threads = 1 + num_handles; |
---|
452 | convert_sing_to_fmpq_mpoly_arg * args = new convert_sing_to_fmpq_mpoly_arg[base.num_threads]; |
---|
453 | slong cur_idx = 0; |
---|
454 | for (slong i = 0; i < base.num_threads; i++) |
---|
455 | { |
---|
456 | slong next_idx = i + 1 < base.num_threads ? (i + 1)*base.length/base.num_threads : base.length; |
---|
457 | FLINT_ASSERT(cur_idx <= base.length); |
---|
458 | next_idx = FLINT_MAX(next_idx, cur_idx); |
---|
459 | next_idx = FLINT_MIN(next_idx, base.length); |
---|
460 | args[i].base = &base; |
---|
461 | args[i].start_idx = cur_idx; |
---|
462 | args[i].end_idx = next_idx; |
---|
463 | cur_idx = next_idx; |
---|
464 | } |
---|
465 | |
---|
466 | /* get content and bits */ |
---|
467 | for (slong i = 0; i < num_handles; i++) |
---|
468 | thread_pool_wake(global_thread_pool, handles[i], convert_sing_to_fmpq_mpoly_content_bits, args + i); |
---|
469 | convert_sing_to_fmpq_mpoly_content_bits(args + num_handles); |
---|
470 | for (slong i = 0; i < num_handles; i++) |
---|
471 | thread_pool_wait(global_thread_pool, handles[i]); |
---|
472 | |
---|
473 | flint_bitcnt_t required_bits = MPOLY_MIN_BITS; |
---|
474 | for (slong i = 0; i <= num_handles; i++) |
---|
475 | required_bits = FLINT_MAX(required_bits, args[i].required_bits); |
---|
476 | |
---|
477 | /* sign of content should match sign of first coeff */ |
---|
478 | fmpq_t content; |
---|
479 | fmpq_init(content); |
---|
480 | fmpq_zero(content); |
---|
481 | for (slong i = 0; i < base.num_threads; i++) |
---|
482 | fmpq_gcd(content, content, args[i].content); |
---|
483 | if (p != NULL) |
---|
484 | { |
---|
485 | fmpq_t c; |
---|
486 | fmpq_init(c); |
---|
487 | my_convSingNFlintN_QQ(c, number(pGetCoeff(p))); |
---|
488 | if (fmpq_sgn(c) < 0) |
---|
489 | fmpq_neg(content, content); |
---|
490 | fmpq_clear(c); |
---|
491 | } |
---|
492 | |
---|
493 | /* initialize res with optimal bits */ |
---|
494 | required_bits = mpoly_fix_bits(required_bits, ctx->zctx->minfo); |
---|
495 | if (fmpq_is_one(content)) |
---|
496 | { |
---|
497 | /* initialize borrowed coeffs */ |
---|
498 | slong N = mpoly_words_per_exp(required_bits, ctx->zctx->minfo); |
---|
499 | slong alloc = base.length; |
---|
500 | if (alloc != 0) |
---|
501 | { |
---|
502 | res->zpoly->coeffs = (fmpz *) flint_malloc(alloc*sizeof(fmpz)); |
---|
503 | res->zpoly->exps = (ulong *) flint_malloc(alloc*N*sizeof(ulong)); |
---|
504 | } |
---|
505 | else |
---|
506 | { |
---|
507 | res->zpoly->coeffs = NULL; |
---|
508 | res->zpoly->exps = NULL; |
---|
509 | } |
---|
510 | res->zpoly->alloc = alloc; |
---|
511 | res->zpoly->length = 0; |
---|
512 | res->zpoly->bits = required_bits; |
---|
513 | |
---|
514 | fmpq_init(res->content); |
---|
515 | fmpq_one(res->content); |
---|
516 | } |
---|
517 | else |
---|
518 | { |
---|
519 | /* initialize coeffs that will be created and destroyed */ |
---|
520 | fmpq_mpoly_init3(res, base.length, required_bits, ctx); |
---|
521 | fmpq_swap(res->content, content); |
---|
522 | } |
---|
523 | |
---|
524 | fmpq_clear(content); |
---|
525 | |
---|
526 | /* fill in res->zpoly */ |
---|
527 | for (slong i = 0; i < num_handles; i++) |
---|
528 | thread_pool_wake(global_thread_pool, handles[i], convert_sing_to_fmpq_mpoly_zpoly_worker, args + i); |
---|
529 | convert_sing_to_fmpq_mpoly_zpoly_worker(args + num_handles); |
---|
530 | for (slong i = 0; i < num_handles; i++) |
---|
531 | thread_pool_wait(global_thread_pool, handles[i]); |
---|
532 | |
---|
533 | base.res->zpoly->length = base.length; |
---|
534 | |
---|
535 | delete[] args; |
---|
536 | |
---|
537 | for (slong i = 0; i < num_handles; i++) |
---|
538 | thread_pool_give_back(global_thread_pool, handles[i]); |
---|
539 | if (handles) |
---|
540 | flint_free(handles); |
---|
541 | } |
---|
542 | |
---|
543 | /* fmpq_mpoly -> singular conversion */ |
---|
544 | |
---|
545 | class convert_fmpq_mpoly_to_sing_base |
---|
546 | { |
---|
547 | public: |
---|
548 | slong num_threads; |
---|
549 | fmpq_mpoly_struct * f; |
---|
550 | const fmpq_mpoly_ctx_struct * ctx; |
---|
551 | ring r; |
---|
552 | |
---|
553 | convert_fmpq_mpoly_to_sing_base(slong num_threads_, fmpq_mpoly_struct * f_, |
---|
554 | const fmpq_mpoly_ctx_struct * ctx_, const ring r_) |
---|
555 | : num_threads(num_threads_), |
---|
556 | f(f_), |
---|
557 | ctx(ctx_), |
---|
558 | r(r_) |
---|
559 | { |
---|
560 | } |
---|
561 | }; |
---|
562 | |
---|
563 | class convert_fmpq_mpoly_to_sing_arg |
---|
564 | { |
---|
565 | public: |
---|
566 | poly poly_start, poly_end; |
---|
567 | slong start_idx, end_idx; |
---|
568 | convert_fmpq_mpoly_to_sing_base* base; |
---|
569 | }; |
---|
570 | |
---|
571 | static void convert_fmpq_mpoly_to_sing_worker(void * varg) |
---|
572 | { |
---|
573 | convert_fmpq_mpoly_to_sing_arg * arg = (convert_fmpq_mpoly_to_sing_arg *) varg; |
---|
574 | convert_fmpq_mpoly_to_sing_base * base = arg->base; |
---|
575 | ulong* exp = (ulong*) flint_malloc((base->r->N + 1)*sizeof(ulong)); |
---|
576 | fmpq_t c; |
---|
577 | fmpq_init(c); |
---|
578 | |
---|
579 | for (slong idx = arg->end_idx - 1; idx >= arg->start_idx; idx--) |
---|
580 | { |
---|
581 | poly pp = p_Init(base->r); |
---|
582 | |
---|
583 | #if SIZEOF_LONG==8 |
---|
584 | fmpq_mpoly_get_term_exp_ui(exp, base->f, idx, base->ctx); |
---|
585 | p_SetExpVL(pp, (int64*)exp, base->r); |
---|
586 | #else |
---|
587 | fmpq_mpoly_get_term_exp_ui(&(exp[1]), base->f, idx, base->ctx); |
---|
588 | p_SetExpV(pp, (int*)exp, base->r); |
---|
589 | #endif |
---|
590 | p_Setm(pp, base->r); |
---|
591 | |
---|
592 | fmpq_mpoly_get_term_coeff_fmpq(c, base->f, idx, base->ctx); |
---|
593 | pSetCoeff0(pp, number(convFlintNSingN_QQ(c, base->r->cf))); |
---|
594 | |
---|
595 | if (idx == arg->end_idx - 1) |
---|
596 | arg->poly_end = pp; |
---|
597 | |
---|
598 | pNext(pp) = arg->poly_start; |
---|
599 | arg->poly_start = pp; |
---|
600 | } |
---|
601 | |
---|
602 | flint_free(exp); |
---|
603 | fmpq_clear(c); |
---|
604 | } |
---|
605 | |
---|
606 | poly convFlintMPSingP(fmpq_mpoly_t f, fmpq_mpoly_ctx_t ctx, const ring r) |
---|
607 | { |
---|
608 | thread_pool_handle * handles; |
---|
609 | slong num_handles; |
---|
610 | slong thread_limit = 1000;// TODO: should be paramter to this function |
---|
611 | |
---|
612 | /* sensibly limit threads and get workers */ |
---|
613 | thread_limit = FLINT_MIN(thread_limit, f->zpoly->length/1024); |
---|
614 | handles = NULL; |
---|
615 | num_handles = 0; |
---|
616 | if (thread_limit > 1 && global_thread_pool_initialized) |
---|
617 | { |
---|
618 | slong max_num_handles = thread_pool_get_size(global_thread_pool); |
---|
619 | max_num_handles = FLINT_MIN(thread_limit - 1, max_num_handles); |
---|
620 | if (max_num_handles > 0) |
---|
621 | { |
---|
622 | handles = (thread_pool_handle *) flint_malloc(max_num_handles*sizeof(thread_pool_handle)); |
---|
623 | num_handles = thread_pool_request(global_thread_pool, handles, max_num_handles); |
---|
624 | } |
---|
625 | } |
---|
626 | |
---|
627 | convert_fmpq_mpoly_to_sing_base base(num_handles + 1, f, ctx, r); |
---|
628 | convert_fmpq_mpoly_to_sing_arg * args = new convert_fmpq_mpoly_to_sing_arg[base.num_threads]; |
---|
629 | slong cur_idx = 0; |
---|
630 | for (slong i = 0; i < base.num_threads; i++) |
---|
631 | { |
---|
632 | slong next_idx = i + 1 < base.num_threads ? (i + 1)*base.f->zpoly->length/base.num_threads |
---|
633 | : base.f->zpoly->length; |
---|
634 | FLINT_ASSERT(cur_idx <= base.f->zpoly->length); |
---|
635 | next_idx = FLINT_MAX(next_idx, cur_idx); |
---|
636 | next_idx = FLINT_MIN(next_idx, base.f->zpoly->length); |
---|
637 | args[i].base = &base; |
---|
638 | args[i].start_idx = cur_idx; |
---|
639 | args[i].end_idx = next_idx; |
---|
640 | cur_idx = next_idx; |
---|
641 | args[i].poly_end = NULL; |
---|
642 | args[i].poly_start = NULL; |
---|
643 | } |
---|
644 | |
---|
645 | /* construct pieces */ |
---|
646 | for (slong i = 0; i < num_handles; i++) |
---|
647 | thread_pool_wake(global_thread_pool, handles[i], convert_fmpq_mpoly_to_sing_worker, args + i); |
---|
648 | convert_fmpq_mpoly_to_sing_worker(args + num_handles); |
---|
649 | for (slong i = 0; i < num_handles; i++) |
---|
650 | thread_pool_wait(global_thread_pool, handles[i]); |
---|
651 | |
---|
652 | /* join pieces */ |
---|
653 | poly p = NULL; |
---|
654 | for (slong i = num_handles; i >= 0; i--) |
---|
655 | { |
---|
656 | if (args[i].poly_end != NULL) |
---|
657 | { |
---|
658 | pNext(args[i].poly_end) = p; |
---|
659 | p = args[i].poly_start; |
---|
660 | } |
---|
661 | } |
---|
662 | |
---|
663 | for (slong i = 0; i < num_handles; i++) |
---|
664 | thread_pool_give_back(global_thread_pool, handles[i]); |
---|
665 | if (handles) |
---|
666 | flint_free(handles); |
---|
667 | |
---|
668 | p_Test(p,r); |
---|
669 | return p; |
---|
670 | } |
---|
671 | |
---|
672 | |
---|
673 | /* singular -> nmod_mpoly conversion */ |
---|
674 | |
---|
675 | class convert_sing_to_nmod_mpoly_base |
---|
676 | { |
---|
677 | public: |
---|
678 | slong num_threads; |
---|
679 | slong length; |
---|
680 | nmod_mpoly_struct * res; |
---|
681 | const nmod_mpoly_ctx_struct * ctx; |
---|
682 | std::vector<poly> markers; |
---|
683 | ring r; |
---|
684 | |
---|
685 | convert_sing_to_nmod_mpoly_base(nmod_mpoly_struct * res_, |
---|
686 | const nmod_mpoly_ctx_struct * ctx_, const ring r_, poly p) |
---|
687 | : num_threads(0), |
---|
688 | res(res_), |
---|
689 | ctx(ctx_), |
---|
690 | r(r_) |
---|
691 | { |
---|
692 | length = 0; |
---|
693 | while (1) |
---|
694 | { |
---|
695 | if ((length % 4096) == 0) |
---|
696 | markers.push_back(p); |
---|
697 | if (p == NULL) |
---|
698 | return; |
---|
699 | length++; |
---|
700 | pIter(p); |
---|
701 | } |
---|
702 | } |
---|
703 | }; |
---|
704 | |
---|
705 | class convert_sing_to_nmod_mpoly_arg |
---|
706 | { |
---|
707 | public: |
---|
708 | slong start_idx, end_idx; |
---|
709 | convert_sing_to_nmod_mpoly_base* base; |
---|
710 | flint_bitcnt_t required_bits; |
---|
711 | }; |
---|
712 | |
---|
713 | static void convert_sing_to_nmod_mpoly_bits(void * varg) |
---|
714 | { |
---|
715 | convert_sing_to_nmod_mpoly_arg * arg = (convert_sing_to_nmod_mpoly_arg *) varg; |
---|
716 | convert_sing_to_nmod_mpoly_base * base = arg->base; |
---|
717 | ulong * exp = (ulong*) flint_malloc((base->r->N + 1)*sizeof(ulong)); |
---|
718 | |
---|
719 | slong idx = arg->start_idx/4096; |
---|
720 | poly p = base->markers[idx]; |
---|
721 | idx *= 4096; |
---|
722 | while (idx < arg->start_idx) |
---|
723 | { |
---|
724 | pIter(p); |
---|
725 | idx++; |
---|
726 | } |
---|
727 | |
---|
728 | flint_bitcnt_t required_bits = MPOLY_MIN_BITS; |
---|
729 | |
---|
730 | while (idx < arg->end_idx) |
---|
731 | { |
---|
732 | #if SIZEOF_LONG==8 |
---|
733 | p_GetExpVL(p, (int64*)exp, base->r); |
---|
734 | flint_bitcnt_t exp_bits = mpoly_exp_bits_required_ui(exp, base->ctx->minfo); |
---|
735 | #else |
---|
736 | p_GetExpV(p, (int*)exp, base->r); |
---|
737 | flint_bitcnt_t exp_bits = mpoly_exp_bits_required_ui(&(exp[1]), base->ctx->minfo); |
---|
738 | #endif |
---|
739 | |
---|
740 | required_bits = FLINT_MAX(required_bits, exp_bits); |
---|
741 | |
---|
742 | pIter(p); |
---|
743 | idx++; |
---|
744 | } |
---|
745 | |
---|
746 | arg->required_bits = required_bits; |
---|
747 | |
---|
748 | flint_free(exp); |
---|
749 | } |
---|
750 | |
---|
751 | |
---|
752 | static void convert_sing_to_nmod_mpoly_worker(void * varg) |
---|
753 | { |
---|
754 | convert_sing_to_nmod_mpoly_arg * arg = (convert_sing_to_nmod_mpoly_arg *) varg; |
---|
755 | convert_sing_to_nmod_mpoly_base * base = arg->base; |
---|
756 | ulong * exp = (ulong*) flint_malloc((base->r->N + 1)*sizeof(ulong)); |
---|
757 | |
---|
758 | slong idx = arg->start_idx/4096; |
---|
759 | poly p = base->markers[idx]; |
---|
760 | idx *= 4096; |
---|
761 | while (idx < arg->start_idx) |
---|
762 | { |
---|
763 | pIter(p); |
---|
764 | idx++; |
---|
765 | } |
---|
766 | |
---|
767 | slong N = mpoly_words_per_exp(base->res->bits, base->ctx->minfo); |
---|
768 | ulong * res_coeffs = base->res->coeffs; |
---|
769 | ulong * res_exps = base->res->exps; |
---|
770 | flint_bitcnt_t res_bits = base->res->bits; |
---|
771 | |
---|
772 | while (idx < arg->end_idx) |
---|
773 | { |
---|
774 | #if SIZEOF_LONG==8 |
---|
775 | p_GetExpVL(p, (int64*)exp, base->r); |
---|
776 | mpoly_set_monomial_ui(res_exps + N*idx, exp, res_bits, base->ctx->minfo); |
---|
777 | #else |
---|
778 | p_GetExpV(p, (int*)exp, base->r); |
---|
779 | mpoly_set_monomial_ui(res_exps + N*idx, &(exp[1]), res_bits, base->ctx->minfo); |
---|
780 | #endif |
---|
781 | |
---|
782 | res_coeffs[idx] = (ulong)(number(pGetCoeff(p))); |
---|
783 | |
---|
784 | pIter(p); |
---|
785 | idx++; |
---|
786 | } |
---|
787 | |
---|
788 | flint_free(exp); |
---|
789 | } |
---|
790 | |
---|
791 | /* res comes in unitialized!!!! */ |
---|
792 | void convSingPFlintMP(nmod_mpoly_t res, nmod_mpoly_ctx_t ctx, poly p, int lp, const ring r) |
---|
793 | { |
---|
794 | thread_pool_handle * handles; |
---|
795 | slong num_handles; |
---|
796 | slong thread_limit = 1000; // TODO: should be paramter to this function |
---|
797 | |
---|
798 | /* the constructor works out the length of p and sets some markers */ |
---|
799 | convert_sing_to_nmod_mpoly_base base(res, ctx, r, p); |
---|
800 | |
---|
801 | /* sensibly limit thread count and get workers */ |
---|
802 | thread_limit = FLINT_MIN(thread_limit, base.length/1024); |
---|
803 | handles = NULL; |
---|
804 | num_handles = 0; |
---|
805 | if (thread_limit > 1 && global_thread_pool_initialized) |
---|
806 | { |
---|
807 | slong max_num_handles = thread_pool_get_size(global_thread_pool); |
---|
808 | max_num_handles = FLINT_MIN(thread_limit - 1, max_num_handles); |
---|
809 | if (max_num_handles > 0) |
---|
810 | { |
---|
811 | handles = (thread_pool_handle *) flint_malloc(max_num_handles*sizeof(thread_pool_handle)); |
---|
812 | num_handles = thread_pool_request(global_thread_pool, handles, max_num_handles); |
---|
813 | } |
---|
814 | } |
---|
815 | |
---|
816 | /* fill in thread division points */ |
---|
817 | base.num_threads = 1 + num_handles; |
---|
818 | convert_sing_to_nmod_mpoly_arg * args = new convert_sing_to_nmod_mpoly_arg[base.num_threads]; |
---|
819 | slong cur_idx = 0; |
---|
820 | for (slong i = 0; i < base.num_threads; i++) |
---|
821 | { |
---|
822 | slong next_idx = i + 1 < base.num_threads ? (i + 1)*base.length/base.num_threads |
---|
823 | : base.length; |
---|
824 | FLINT_ASSERT(cur_idx <= base.length); |
---|
825 | next_idx = FLINT_MAX(next_idx, cur_idx); |
---|
826 | next_idx = FLINT_MIN(next_idx, base.length); |
---|
827 | args[i].base = &base; |
---|
828 | args[i].start_idx = cur_idx; |
---|
829 | args[i].end_idx = next_idx; |
---|
830 | cur_idx = next_idx; |
---|
831 | } |
---|
832 | |
---|
833 | /* find required bits */ |
---|
834 | for (slong i = 0; i < num_handles; i++) |
---|
835 | thread_pool_wake(global_thread_pool, handles[i], convert_sing_to_nmod_mpoly_bits, args + i); |
---|
836 | convert_sing_to_nmod_mpoly_bits(args + num_handles); |
---|
837 | for (slong i = 0; i < num_handles; i++) |
---|
838 | thread_pool_wait(global_thread_pool, handles[i]); |
---|
839 | |
---|
840 | flint_bitcnt_t required_bits = MPOLY_MIN_BITS; |
---|
841 | for (slong i = 0; i <= num_handles; i++) |
---|
842 | required_bits = FLINT_MAX(required_bits, args[i].required_bits); |
---|
843 | |
---|
844 | /* initialize res with optimal bits */ |
---|
845 | nmod_mpoly_init3(res, base.length, mpoly_fix_bits(required_bits, ctx->minfo), ctx); |
---|
846 | |
---|
847 | /* fill in res */ |
---|
848 | for (slong i = 0; i < num_handles; i++) |
---|
849 | thread_pool_wake(global_thread_pool, handles[i], convert_sing_to_nmod_mpoly_worker, args + i); |
---|
850 | convert_sing_to_nmod_mpoly_worker(args + num_handles); |
---|
851 | for (slong i = 0; i < num_handles; i++) |
---|
852 | thread_pool_wait(global_thread_pool, handles[i]); |
---|
853 | |
---|
854 | base.res->length = base.length; |
---|
855 | |
---|
856 | delete[] args; |
---|
857 | |
---|
858 | for (slong i = 0; i < num_handles; i++) |
---|
859 | thread_pool_give_back(global_thread_pool, handles[i]); |
---|
860 | if (handles) |
---|
861 | flint_free(handles); |
---|
862 | } |
---|
863 | |
---|
864 | |
---|
865 | /* nmod_mpoly -> singular conversion */ |
---|
866 | |
---|
867 | class convert_nmod_mpoly_to_sing_base |
---|
868 | { |
---|
869 | public: |
---|
870 | slong num_threads; |
---|
871 | nmod_mpoly_struct * f; |
---|
872 | const nmod_mpoly_ctx_struct * ctx; |
---|
873 | ring r; |
---|
874 | |
---|
875 | convert_nmod_mpoly_to_sing_base(slong num_threads_, nmod_mpoly_struct * f_, |
---|
876 | const nmod_mpoly_ctx_struct * ctx_, const ring r_) |
---|
877 | : num_threads(num_threads_), |
---|
878 | f(f_), |
---|
879 | ctx(ctx_), |
---|
880 | r(r_) |
---|
881 | { |
---|
882 | } |
---|
883 | }; |
---|
884 | |
---|
885 | class convert_nmod_mpoly_to_sing_arg |
---|
886 | { |
---|
887 | public: |
---|
888 | poly poly_start, poly_end; |
---|
889 | slong start_idx, end_idx; |
---|
890 | convert_nmod_mpoly_to_sing_base* base; |
---|
891 | }; |
---|
892 | |
---|
893 | static void convert_nmod_mpoly_to_sing_worker(void * varg) |
---|
894 | { |
---|
895 | convert_nmod_mpoly_to_sing_arg * arg = (convert_nmod_mpoly_to_sing_arg *) varg; |
---|
896 | convert_nmod_mpoly_to_sing_base * base = arg->base; |
---|
897 | ulong* exp = (ulong*) flint_malloc((base->r->N + 1)*sizeof(ulong)); |
---|
898 | |
---|
899 | for (slong idx = arg->end_idx - 1; idx >= arg->start_idx; idx--) |
---|
900 | { |
---|
901 | poly pp = p_Init(base->r); |
---|
902 | |
---|
903 | #if SIZEOF_LONG==8 |
---|
904 | nmod_mpoly_get_term_exp_ui(exp, base->f, idx, base->ctx); |
---|
905 | p_SetExpVL(pp, (int64*)exp, base->r); |
---|
906 | #else |
---|
907 | nmod_mpoly_get_term_exp_ui(&(exp[1]), base->f, idx, base->ctx); |
---|
908 | p_SetExpV(pp, (int*)exp, base->r); |
---|
909 | #endif |
---|
910 | p_Setm(pp, base->r); |
---|
911 | |
---|
912 | pSetCoeff0(pp, number(nmod_mpoly_get_term_coeff_ui(base->f, idx, base->ctx))); |
---|
913 | |
---|
914 | if (idx == arg->end_idx - 1) |
---|
915 | arg->poly_end = pp; |
---|
916 | |
---|
917 | pNext(pp) = arg->poly_start; |
---|
918 | arg->poly_start = pp; |
---|
919 | } |
---|
920 | |
---|
921 | flint_free(exp); |
---|
922 | } |
---|
923 | |
---|
924 | poly convFlintMPSingP(nmod_mpoly_t f, nmod_mpoly_ctx_t ctx, const ring r) |
---|
925 | { |
---|
926 | thread_pool_handle * handles; |
---|
927 | slong num_handles; |
---|
928 | slong thread_limit = 1000; // TODO: should be paramter to this function |
---|
929 | |
---|
930 | /* sensibly limit threads and get workers */ |
---|
931 | thread_limit = FLINT_MIN(thread_limit, f->length/1024); |
---|
932 | handles = NULL; |
---|
933 | num_handles = 0; |
---|
934 | if (thread_limit > 1 && global_thread_pool_initialized) |
---|
935 | { |
---|
936 | slong max_num_handles = thread_pool_get_size(global_thread_pool); |
---|
937 | max_num_handles = FLINT_MIN(thread_limit - 1, max_num_handles); |
---|
938 | if (max_num_handles > 0) |
---|
939 | { |
---|
940 | handles = (thread_pool_handle *) flint_malloc(max_num_handles*sizeof(thread_pool_handle)); |
---|
941 | num_handles = thread_pool_request(global_thread_pool, handles, max_num_handles); |
---|
942 | } |
---|
943 | } |
---|
944 | |
---|
945 | convert_nmod_mpoly_to_sing_base base(num_handles + 1, f, ctx, r); |
---|
946 | convert_nmod_mpoly_to_sing_arg * args = new convert_nmod_mpoly_to_sing_arg[base.num_threads]; |
---|
947 | slong cur_idx = 0; |
---|
948 | for (slong i = 0; i < base.num_threads; i++) |
---|
949 | { |
---|
950 | slong next_idx = i + 1 < base.num_threads ? (i + 1)*base.f->length/base.num_threads |
---|
951 | : base.f->length; |
---|
952 | FLINT_ASSERT(cur_idx <= base.f->length); |
---|
953 | next_idx = FLINT_MAX(next_idx, cur_idx); |
---|
954 | next_idx = FLINT_MIN(next_idx, base.f->length); |
---|
955 | args[i].base = &base; |
---|
956 | args[i].start_idx = cur_idx; |
---|
957 | args[i].end_idx = next_idx; |
---|
958 | cur_idx = next_idx; |
---|
959 | args[i].poly_end = NULL; |
---|
960 | args[i].poly_start = NULL; |
---|
961 | } |
---|
962 | |
---|
963 | /* construct pieces */ |
---|
964 | for (slong i = 0; i < num_handles; i++) |
---|
965 | thread_pool_wake(global_thread_pool, handles[i], convert_nmod_mpoly_to_sing_worker, args + i); |
---|
966 | convert_nmod_mpoly_to_sing_worker(args + num_handles); |
---|
967 | for (slong i = 0; i < num_handles; i++) |
---|
968 | thread_pool_wait(global_thread_pool, handles[i]); |
---|
969 | |
---|
970 | /* join pieces */ |
---|
971 | poly p = NULL; |
---|
972 | for (slong i = num_handles; i >= 0; i--) |
---|
973 | { |
---|
974 | if (args[i].poly_end != NULL) |
---|
975 | { |
---|
976 | pNext(args[i].poly_end) = p; |
---|
977 | p = args[i].poly_start; |
---|
978 | } |
---|
979 | } |
---|
980 | |
---|
981 | for (slong i = 0; i < num_handles; i++) |
---|
982 | thread_pool_give_back(global_thread_pool, handles[i]); |
---|
983 | if (handles) |
---|
984 | flint_free(handles); |
---|
985 | |
---|
986 | p_Test(p,r); |
---|
987 | return p; |
---|
988 | } |
---|
989 | |
---|
990 | #endif |
---|
991 | |
---|
992 | /****** polynomial operations ***********/ |
---|
993 | |
---|
994 | poly Flint_Mult_MP(poly p,int lp, poly q, int lq, fmpq_mpoly_ctx_t ctx, const ring r) |
---|
995 | { |
---|
996 | fmpq_mpoly_t pp,qq,res; |
---|
997 | convSingPFlintMP(pp,ctx,p,lp,r); // pp read only |
---|
998 | convSingPFlintMP(qq,ctx,q,lq,r); // qq read only |
---|
999 | fmpq_mpoly_init(res,ctx); |
---|
1000 | fmpq_mpoly_mul(res,pp,qq,ctx); |
---|
1001 | poly pres=convFlintMPSingP(res,ctx,r); |
---|
1002 | fmpq_mpoly_clear(res,ctx); |
---|
1003 | _fmpq_mpoly_clear_readonly_sing(pp,ctx); |
---|
1004 | _fmpq_mpoly_clear_readonly_sing(qq,ctx); |
---|
1005 | fmpq_mpoly_ctx_clear(ctx); |
---|
1006 | p_Test(pres,r); |
---|
1007 | return pres; |
---|
1008 | } |
---|
1009 | |
---|
1010 | poly Flint_Mult_MP(poly p,int lp, poly q, int lq, nmod_mpoly_ctx_t ctx, const ring r) |
---|
1011 | { |
---|
1012 | nmod_mpoly_t pp,qq,res; |
---|
1013 | convSingPFlintMP(pp,ctx,p,lp,r); |
---|
1014 | convSingPFlintMP(qq,ctx,q,lq,r); |
---|
1015 | nmod_mpoly_init(res,ctx); |
---|
1016 | nmod_mpoly_mul(res,pp,qq,ctx); |
---|
1017 | poly pres=convFlintMPSingP(res,ctx,r); |
---|
1018 | nmod_mpoly_clear(res,ctx); |
---|
1019 | nmod_mpoly_clear(pp,ctx); |
---|
1020 | nmod_mpoly_clear(qq,ctx); |
---|
1021 | nmod_mpoly_ctx_clear(ctx); |
---|
1022 | p_Test(pres,r); |
---|
1023 | return pres; |
---|
1024 | } |
---|
1025 | |
---|
1026 | // Zero will be returned if the division is not exact |
---|
1027 | poly Flint_Divide_MP(poly p,int lp, poly q, int lq, fmpq_mpoly_ctx_t ctx, const ring r) |
---|
1028 | { |
---|
1029 | fmpq_mpoly_t pp,qq,res; |
---|
1030 | convSingPFlintMP(pp,ctx,p,lp,r); // pp read only |
---|
1031 | convSingPFlintMP(qq,ctx,q,lq,r); // qq read only |
---|
1032 | fmpq_mpoly_init(res,ctx); |
---|
1033 | fmpq_mpoly_divides(res,pp,qq,ctx); |
---|
1034 | poly pres = convFlintMPSingP(res,ctx,r); |
---|
1035 | fmpq_mpoly_clear(res,ctx); |
---|
1036 | _fmpq_mpoly_clear_readonly_sing(pp,ctx); |
---|
1037 | _fmpq_mpoly_clear_readonly_sing(qq,ctx); |
---|
1038 | fmpq_mpoly_ctx_clear(ctx); |
---|
1039 | p_Test(pres,r); |
---|
1040 | return pres; |
---|
1041 | } |
---|
1042 | |
---|
1043 | poly Flint_Divide_MP(poly p,int lp, poly q, int lq, nmod_mpoly_ctx_t ctx, const ring r) |
---|
1044 | { |
---|
1045 | nmod_mpoly_t pp,qq,res; |
---|
1046 | convSingPFlintMP(pp,ctx,p,lp,r); |
---|
1047 | convSingPFlintMP(qq,ctx,q,lq,r); |
---|
1048 | nmod_mpoly_init(res,ctx); |
---|
1049 | nmod_mpoly_divides(res,pp,qq,ctx); |
---|
1050 | poly pres=convFlintMPSingP(res,ctx,r); |
---|
1051 | nmod_mpoly_clear(res,ctx); |
---|
1052 | nmod_mpoly_clear(pp,ctx); |
---|
1053 | nmod_mpoly_clear(qq,ctx); |
---|
1054 | nmod_mpoly_ctx_clear(ctx); |
---|
1055 | p_Test(pres,r); |
---|
1056 | return pres; |
---|
1057 | } |
---|
1058 | |
---|
1059 | poly Flint_GCD_MP(poly p,int lp,poly q,int lq,nmod_mpoly_ctx_t ctx,const ring r) |
---|
1060 | { |
---|
1061 | nmod_mpoly_t pp,qq,res; |
---|
1062 | convSingPFlintMP(pp,ctx,p,lp,r); |
---|
1063 | convSingPFlintMP(qq,ctx,q,lq,r); |
---|
1064 | nmod_mpoly_init(res,ctx); |
---|
1065 | int ok=nmod_mpoly_gcd(res,pp,qq,ctx); |
---|
1066 | poly pres; |
---|
1067 | if (ok) |
---|
1068 | { |
---|
1069 | pres=convFlintMPSingP(res,ctx,r); |
---|
1070 | p_Test(pres,r); |
---|
1071 | } |
---|
1072 | else |
---|
1073 | { |
---|
1074 | pres=p_One(r); |
---|
1075 | } |
---|
1076 | nmod_mpoly_clear(res,ctx); |
---|
1077 | nmod_mpoly_clear(pp,ctx); |
---|
1078 | nmod_mpoly_clear(qq,ctx); |
---|
1079 | nmod_mpoly_ctx_clear(ctx); |
---|
1080 | return pres; |
---|
1081 | } |
---|
1082 | |
---|
1083 | poly Flint_GCD_MP(poly p,int lp,poly q,int lq,fmpq_mpoly_ctx_t ctx,const ring r) |
---|
1084 | { |
---|
1085 | fmpq_mpoly_t pp,qq,res; |
---|
1086 | convSingPFlintMP(pp,ctx,p,lp,r); // pp read only |
---|
1087 | convSingPFlintMP(qq,ctx,q,lq,r); // qq read only |
---|
1088 | fmpq_mpoly_init(res,ctx); |
---|
1089 | int ok=fmpq_mpoly_gcd(res,pp,qq,ctx); |
---|
1090 | poly pres; |
---|
1091 | if (ok) |
---|
1092 | { |
---|
1093 | // Flint normalizes the gcd to be monic. |
---|
1094 | // Singular wants a gcd defined over ZZ that is primitive and has a positive leading coeff. |
---|
1095 | if (!fmpq_mpoly_is_zero(res, ctx)) |
---|
1096 | { |
---|
1097 | fmpq_t content; |
---|
1098 | fmpq_init(content); |
---|
1099 | fmpq_mpoly_content(content, res, ctx); |
---|
1100 | fmpq_mpoly_scalar_div_fmpq(res, res, content, ctx); |
---|
1101 | fmpq_clear(content); |
---|
1102 | } |
---|
1103 | pres=convFlintMPSingP(res,ctx,r); |
---|
1104 | p_Test(pres,r); |
---|
1105 | } |
---|
1106 | else |
---|
1107 | { |
---|
1108 | pres=p_One(r); |
---|
1109 | } |
---|
1110 | fmpq_mpoly_clear(res,ctx); |
---|
1111 | _fmpq_mpoly_clear_readonly_sing(pp,ctx); |
---|
1112 | _fmpq_mpoly_clear_readonly_sing(qq,ctx); |
---|
1113 | fmpq_mpoly_ctx_clear(ctx); |
---|
1114 | return pres; |
---|
1115 | } |
---|
1116 | |
---|
1117 | #endif |
---|
1118 | #endif |
---|