source: git/libpolys/polys/flint_mpoly.cc @ 3f94cb

spielwiese
Last change on this file since 3f94cb was 3f94cb, checked in by tthsqe12 <tthsqe12@…>, 4 years ago
limit worker threads based on poly length
  • Property mode set to 100644
File size: 31.9 KB
Line 
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
23BOOLEAN 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
43BOOLEAN 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*/
76static void _fmpq_mpoly_clear_readonly_sing(fmpq_mpoly_t a, fmpq_mpoly_ctx_t ctx)
77{
78    fmpq_mpoly_clear(a, ctx);
79}
80
81void 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
104poly 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
134poly 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
160void 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
183static 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
212static 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
232class convert_sing_to_fmpq_mpoly_base
233{
234public:
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
279class convert_sing_to_fmpq_mpoly_arg
280{
281public:
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
291static 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
345static 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!!!! */
426void 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
545class convert_fmpq_mpoly_to_sing_base
546{
547public:
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
563class convert_fmpq_mpoly_to_sing_arg
564{
565public:
566    poly poly_start, poly_end;
567    slong start_idx, end_idx;
568    convert_fmpq_mpoly_to_sing_base* base;
569};
570
571static 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
606poly 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
675class convert_sing_to_nmod_mpoly_base
676{
677public:
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
705class convert_sing_to_nmod_mpoly_arg
706{
707public:
708    slong start_idx, end_idx;
709    convert_sing_to_nmod_mpoly_base* base;
710    flint_bitcnt_t required_bits;
711};
712
713static 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
752static 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!!!! */
792void 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
867class convert_nmod_mpoly_to_sing_base
868{
869public:
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
885class convert_nmod_mpoly_to_sing_arg
886{
887public:
888    poly poly_start, poly_end;
889    slong start_idx, end_idx;
890    convert_nmod_mpoly_to_sing_base* base;
891};
892
893static 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
924poly 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
994poly 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
1010poly 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
1027poly 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
1043poly 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
1059poly 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
1083poly 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
Note: See TracBrowser for help on using the repository browser.